#include <qtimer.h>
#include <qdragobject.h>
#include <qregexp.h>

#include <kiconloader.h>
#include <kstandarddirs.h>
#include <kapplication.h>
#include <kaction.h>
#include <kdebug.h>
#include <klocale.h>
#include <kfiledialog.h>
#include <kmessagebox.h>
#include <klibloader.h>
#include <kstdaction.h>
#include <khelpmenu.h>
#include <kedittoolbar.h>


#include <kprogress.h>
#include <qlabel.h>

#include <stdlib.h>
#include <unistd.h>

#include "kviewpart_iface.h"
#include <kstatusbar.h>
#include "kviewshell.moc"


#define StatusBar_ID_PageNr 1
#define StatusBar_ID_PageSize 2
#define StatusBar_ID_Zoom 3


KViewShell::KViewShell(QString partname, KAboutData *about)
  : KParts::MainWindow(), _partname(partname)
{
  // create the viewer part

  // Try to load
  KLibFactory *factory = KLibLoader::self()->factory("kviewerpart");
  if (factory) {
    QStringList args;
    args << _partname;
    view = (KViewPart_Iface*) factory->create(this, "kviewerpart", "KViewPart", args);
  } else {
    KMessageBox::error(this, i18n("No viewing component found"));
    ::exit(-1);
  }

  setCentralWidget(view->widget());

  // file menu
  KStdAction::open(this, SLOT(slotFileOpen()), actionCollection());
  recent = KStdAction::openRecent (this, SLOT(openURL(const KURL &)), actionCollection());
  reloadAction = new KAction(i18n("Reload"), "reload", CTRL + Key_R, view, SLOT(reload(void)), actionCollection(), "reload");
  closeAction = KStdAction::close(this, SLOT(slotFileClose()), actionCollection());
  KStdAction::quit (this, SLOT(slotQuit()), actionCollection());

  // settings menu
  showtoolbar = KStdAction::showToolbar(this, SLOT(slotShowToolBar()), actionCollection());
  showstatusbar = KStdAction::showStatusbar(this, SLOT(slotShowStatusBar()), actionCollection());

  // statusbar connects
  connect( view, SIGNAL( zoomChanged(const QString &) ), this,SLOT( slotChangeZoomText(const QString &) ) );
  connect( view, SIGNAL( pageChanged(const QString &) ), this,SLOT( slotChangePageText(const QString &) ) );
  connect( view, SIGNAL( sizeChanged(const QString &) ), this,SLOT( slotChangeSizeText(const QString &) ) );

  //Creates new object of class statusbar
  statusbar= new KStatusBar(this,"StatusBar");

  m_helpMenu = new KHelpMenu( this, about, true, actionCollection() );

  setXMLFile( "kviewshell.rc" );

  createGUI(view);

  readSettings();

  checkActions();

  setAcceptDrops(true);

  // Add statusbar-widgets for zoom, pagenr and format
  statusbar->insertItem("", StatusBar_ID_PageNr, 0, true);
  statusbar->insertFixedItem("XXXX%", StatusBar_ID_Zoom, true);
  statusbar->insertItem("", StatusBar_ID_PageSize, 0, true);
}


void KViewShell::checkActions()
{
  bool doc = !view->url().isEmpty();

  closeAction->setEnabled(doc);
  reloadAction->setEnabled(doc);
}


KViewShell::~KViewShell()
{
  writeSettings();
  delete view;
}


void KViewShell::slotQuit()
{
  kapp->closeAllWindows();
  kapp->quit();
}


void KViewShell::readSettings()
{
  KConfig *config = kapp->config();

  config->setGroup("General");

  showtoolbar->setChecked(config->readBoolEntry("ShowToolBar", true));
  slotShowToolBar();

  showstatusbar->setChecked (config->readBoolEntry ("ShowStatusBar", true));
  slotShowStatusBar();

  int w = config->readNumEntry ("WindowWidth", 600);
  int h = config->readNumEntry ("WindowHeight", 300);
  resize(w, h);

  recent->loadEntries(config, QString("%1-RecentFiles").arg(_partname));

  // Constant source of anoyment in KDVI < 1.0: the 'recent-files'
  // menu contains lots of files which don't exist (any long). Thus,
  // we'll sort out the non-existent files here.
  QStringList items = recent->items();
  for ( QStringList::Iterator it = items.begin(); it != items.end(); ++it ) {
    KURL url(*it);
    if (url.isLocalFile()) {
      QFileInfo info(url.path());
      if (!info.exists())
	recent->removeURL(url);
    }
  }

}


void KViewShell::writeSettings()
{
  KConfig *config = kapp->config();

  config->setGroup( "General" );

  config->writeEntry ("ShowToolBar", showtoolbar->isChecked());
  config->writeEntry ("ShowStatusBar", showstatusbar->isChecked());
  config->writeEntry ("WindowWidth", width());
  config->writeEntry ("WindowHeight", height());

  recent->saveEntries(config, QString("%1-RecentFiles").arg(_partname));

  config->sync();
}


void KViewShell::openURL(const KURL &url)
{
  if (view->openURL(url)) {
    // The URL which we passed as an argument may have been incomplete
    // (e.g. "test" instead of "test.dvi"). Thus, we use the completed
    // version from the kviewpart here.
    KURL actualURL = view->url();
    // To store the URL in the list of recent files, we remove the
    // reference part.
    actualURL.setRef(QString::null);
    recent->addURL(actualURL);
    checkActions();
  }
}


void KViewShell::slotFileOpen()
{
  KURL url = KFileDialog::getOpenURL(QString::null, view->fileFormats().join("\n"));

  if (!url.isEmpty())
    openURL(url);
}


void KViewShell::slotFileClose()
{
  view->closeURL();

  checkActions();
}


void KViewShell::slotShowStatusBar()
{
  if (showstatusbar->isChecked())
    statusBar()->show();
  else
    statusBar()->hide();
}


void KViewShell::slotShowToolBar()
{
  if (showtoolbar->isChecked())
    toolBar()->show();
  else
    toolBar()->hide();
}


void KViewShell::slotEditToolbar()
{
  KEditToolbar dlg(actionCollection());
  if (dlg.exec())
    createGUI(view);
}


void KViewShell::dragEnterEvent(QDragEnterEvent *event)
{
  if (QUriDrag::canDecode(event)) {
    QStringList urls;
    QUriDrag::decodeToUnicodeUris(event, urls);
    if (urls.count() > 0) {
      // look if the extension is right
      QStringList list = view->fileFormats();
      QStringList::Iterator it;
      for (it = list.begin(); it != list.end(); ++it) {
	QString ext = *it;
	int pos = ext.find('|');
	if (pos >= 0)
	  ext = ext.left(pos);

	QRegExp re(ext, false, true);
	if (re.search(urls[0]) >= 0) {
	  event->accept(true);
	  return;
	}
      }
    }
  }
  event->accept(false);
}


void KViewShell::dropEvent(QDropEvent *event)
{
  if (QUriDrag::canDecode(event)) {
    QStringList urls;
    QUriDrag::decodeToUnicodeUris(event, urls);
    if (urls.count() > 0)
      openURL(KURL(urls[0]));
  }
}


void KViewShell::slotChangePageText(const QString &message)
{
  statusbar->changeItem(" "+message+" ",StatusBar_ID_PageNr);
}


void KViewShell::slotChangeSizeText(const QString &message)
{
  statusbar->changeItem(" "+message+" ",StatusBar_ID_PageSize);
}


void KViewShell::slotChangeZoomText(const QString &message)
{
  statusbar->changeItem(" "+message+" ",StatusBar_ID_Zoom);
}
