#include <qframe.h>
#include <qlayout.h>

#include <kaction.h>
#include <kconfig.h>
#include <kdirwatch.h>
#include <kglobalsettings.h>
#include <kiconloader.h>
#include <kinstance.h>
#include <klocale.h>
#include <kstdaction.h>

#include "kgv_view.h"
#include "kgv_miniwidget.h"
#include "kpswidget.h"
#include "marklist.h"
#include "scrollbox.h"

#define PAGELIST_WIDTH 75

extern "C"{
  void *init_libkghostview()
  {
    return new KGVFactory;
  }
};

KInstance *KGVFactory::s_instance = 0L;

KGVFactory::KGVFactory()
{
}

KGVFactory::~KGVFactory()
{
    if ( s_instance )
        delete s_instance;

    s_instance = 0;
}

KParts::Part *KGVFactory::createPart( QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name, const char *className, const QStringList & )
{
    bool bBrowserView = ( strcmp( className, "Browser/View" ) == 0 );
    KParts::Part *obj = new KGVPart( bBrowserView, parentWidget, widgetName, parent, name );
    emit objectCreated( obj );
    return obj;
}

KInstance *KGVFactory::instance()
{
    if ( !s_instance )
        s_instance = new KInstance( "kghostview" );
    return s_instance;
}

KGVPart::KGVPart( bool bBrowserView, QWidget *parentWidget, 
		  const char *, QObject *parent, const char *name )
 :  KParts::ReadOnlyPart( parent, name )
{
    setInstance( KGVFactory::instance() );
   
    
    // Setup main widget
    _mainWidget = new QWidget( parentWidget );
    _mainWidget->setFocusPolicy( QWidget::StrongFocus );

    QHBoxLayout* hlay = new QHBoxLayout( _mainWidget, 0, 0 );
    QVBoxLayout* vlay = new QVBoxLayout( hlay );
 
    _scrollBox = new ScrollBox( _mainWidget , "scrollbox" );
    _scrollBox->setMinimumWidth( PAGELIST_WIDTH );
    _scrollBox->setMinimumHeight( PAGELIST_WIDTH );
    vlay->addWidget( _scrollBox );

    _markList = new MarkList( _mainWidget, "marklist" );
    _markList->setMinimumWidth( PAGELIST_WIDTH );
    _markList->setSelectColors( _mainWidget->colorGroup().highlight(), 
				_mainWidget->colorGroup().highlightedText());
    vlay->addWidget( _markList, 1 );

    _divider = new QFrame( _mainWidget, "divider" );
    _divider->setFrameStyle( QFrame::Panel | QFrame::Raised );
    _divider->setLineWidth( 1 );
    _divider->setMinimumWidth( 3 );
    hlay->addWidget( _divider );
 
    _psView = new KPSView( _mainWidget, "psview" );
    hlay->addWidget( _psView, 1);
    _mainWidget->setFocusProxy( _psView );

    setWidget( _mainWidget );

    
    // Setup document manager
    _docManager = new KGVMiniWidget( _psView->psWidget(), this );

    
    // Connect up the necessary signals and slots.
    connect( _markList, SIGNAL( selected( int ) ), 
	     _docManager, SLOT( goToPage( int ) ) );
    connect( _docManager, SIGNAL( newPageShown( int ) ), 
	     _markList, SLOT( select( int ) ) );

    connect( _scrollBox, SIGNAL( valueChangedRelative( int, int ) ),
	     _psView, SLOT( scrollBy( int, int ) ) );
    connect( _psView->psWidget(), SIGNAL( pageSizeChanged( QSize ) ),
	     _scrollBox, SLOT( setPageSize( QSize ) ) );
    connect( _psView, SIGNAL( viewSizeChanged( QSize ) ),
	     _scrollBox, SLOT( setViewSize( QSize ) ) );
    connect( _psView, SIGNAL( contentsMoving( int, int ) ),
	     _scrollBox, SLOT( setViewPos( int, int ) ) );

    connect( _docManager, SIGNAL( fileChangeFailed() ),
	     this, SLOT( slotCancelWatch() ) );
    connect( _docManager, SIGNAL( setStatusBarText( const QString& ) ),
	     this, SIGNAL( setStatusBarText( const QString& ) ) );

    // Put state-dependent actions in this collection.
    statedep = new KActionCollection;
  
  
    // File Menu
    if ( !bBrowserView )
	statedep->insert( KStdAction::saveAs( miniWidget(), SLOT( saveAs() ), 
			    actionCollection() ) );
  
    statedep->insert( new KAction( i18n( "Document &Info..." ), 0, 
			    miniWidget(), SLOT( info() ),
			    actionCollection(), "info") );


    // View Menu  
    QStringList orientations;
    orientations.append( i18n( "Auto" ) );
    orientations.append( i18n( "Portrait" ) );
    orientations.append( i18n( "Landscape" ) );
    orientations.append( i18n( "Upside Down" ) );
    orientations.append( i18n( "Seascape" ) );
  
    orientation = new KSelectAction( i18n( "&Orientation" ), 0, 0, 0, 
			actionCollection(), "orientation_menu" );
    orientation->setItems( orientations );
    connect( orientation, SIGNAL( activated( int ) ),
	     this, SLOT( slotOrientation( int ) ) );
  
    media = new KSelectAction( i18n( "Paper &Size" ), 0, 0, 0,
		       actionCollection(), "media_menu" );
    connect( media, SIGNAL( activated( int ) ),
	     this, SLOT( slotMedia(int ) ) );
  
    zoomInAct	= KStdAction::zoomIn (_docManager,  SLOT(zoomIn() ),
			actionCollection(), "zoomIn" );
			
    zoomOutAct	= KStdAction::zoomOut( _docManager,  SLOT( zoomOut() ),
			actionCollection(), "zoomOut" );
			
    backAct	= KStdAction::prior( this, SLOT( slotPrevPage() ),
			actionCollection(), "prevPage" );
			
    forwardAct	= KStdAction::next( this, SLOT( slotNextPage() ),
			actionCollection(), "nextPage" );
  
    startAct	= new KAction( i18n( "Go to start" ), "start",
			CTRL+Key_Home, this, SLOT( slotGotoStart() ), 
			actionCollection(), "goToStart" );
		    
    endAct	= new KAction( i18n( "Go to end" ), "finish",
			CTRL+Key_End, this, SLOT( slotGotoEnd() ), 
			actionCollection(), "goToEnd" );
		    
    endDocAct	= new KAction( i18n( "Read down document" ), "next",
			Key_Space, this, SLOT( slotReadDown() ),
			actionCollection(), "readDown" );

    gotoAct	= KStdAction::gotoPage( _docManager, SLOT( goToPage() ),
			actionCollection(), "goToPage" );
    
    statedep->insert( orientation );
    statedep->insert( media );
    statedep->insert( zoomInAct );
    statedep->insert( zoomOutAct );
    statedep->insert( backAct );
    statedep->insert( forwardAct );
    statedep->insert( startAct );
    statedep->insert( endAct );
    statedep->insert( endDocAct );
    statedep->insert( gotoAct);


    // Pagemarks Menu
    markAct = new KAction(i18n( "Mark Current Page" ), "flag",
		    Key_Enter, _docManager, SLOT( markPage() ), 
		    actionCollection(), "mark_current");
    statedep->insert( markAct );
    
    statedep->insert(  
	    new KAction( i18n( "Mark &All Pages" ), 0, 
		    _markList, SLOT( markAll() ),
		    actionCollection(), "mark_all" ) );
    statedep->insert( 
	    new KAction( i18n( "Mark &Even Pages" ), 0, 
		    _markList, SLOT( markEven() ),
		    actionCollection(), "mark_even" ) );
    statedep->insert( 
	    new KAction( i18n( "Mark &Odd Pages" ), 0, 
		    _markList, SLOT( markOdd() ),
		    actionCollection(), "mark_odd" ) );
    statedep->insert( 
	    new KAction( i18n( "&Toggle Page Marks" ), 0,
		    _markList, SLOT( toggleMarks() ),
		    actionCollection(), "toggle" ) );
    statedep->insert( 
	    new KAction( i18n("&Remove Page Marks"), 0, 
		    _markList, SLOT( removeMarks() ),
		    actionCollection(), "remove" ) );
      
  
    // TODO -- disable entry if there aren't any page names
    
    
    // Settings menu
    showscrollbars = new KToggleAction( i18n( "Show &Scrollbars" ), 0,
			this, SLOT( slotShowScrollBars() ),
			actionCollection(), "show_scrollbars" );
    
    watchaction	= new KToggleAction( i18n( "&Watch File" ), 0, 
			this, SLOT( slotWatchFile() ),
			actionCollection(), "watch_file" );

    showmarklist = new KToggleAction( i18n( "Show &Page List" ), 0, 
			this, SLOT( slotShowMarkList() ),
			actionCollection(), "show_page_list" );
  
    fancyAct = new KToggleAction (i18n("Show Page Names"), 0, 
			this, SLOT( slotFancy() ), 
			actionCollection(), "fancy_page_labels" );
    fancyAct->setChecked( _docManager->areFancyPageLabelsEnabled() );
    
    new KAction( i18n( "Configure &Interpreter..." ), 0, 
		miniWidget(), SLOT( configureGhostscript() ),
		actionCollection(), "config_interpreter" );

    //TODO
    // progress bars for conversions (see loadingProgress())
  
    _watch = 0;
  
    _extension = new KGVBrowserExtension( this );
  
    setXMLFile( "kgv_part.rc" );
  
    connect( miniWidget(), SIGNAL( newPageShown( int ) ),
	     this, SLOT( slotNewPage( int ) ) );

    readSettings();

    enableStateDepActions( false ); // no document to apply the actions to, yet
}

KGVPart::~KGVPart()
{
    stopWatching();
    writeSettings();
}

void
KGVPart::writeSettings()
{
  KConfig *config = KGVFactory::instance()->config();

  config->setGroup( "General" );
  config->writeEntry ("ShowScrollBars", showscrollbars->isChecked());
  config->writeEntry ("WatchFile", watchaction->isChecked());
  config->writeEntry ("ShowPageList", showmarklist->isChecked());
  config->writeEntry ("ShowPageNames", fancyAct->isChecked());

  miniWidget()->writeSettings();

  config->sync();
}

void
KGVPart::readSettings()
{
    KConfig *config = KGVFactory::instance()->config();

    config->setGroup( "General" );

    showscrollbars->setChecked( 
			config->readBoolEntry( "ShowScrollBars", true ) );
    slotShowScrollBars();

    watchaction->setChecked( config->readBoolEntry( "WatchFile", false ) );
    slotWatchFile();
  
    showmarklist->setChecked( config->readBoolEntry( "ShowPageList", true ) );
    slotShowMarkList();
  
    fancyAct->setChecked( config->readBoolEntry( "ShowPageNames", false ) );
    slotFancy();
}

void KGVPart::slotScrollLeft()
{
    _psView->scrollLeft();
}

void KGVPart::slotScrollRight()
{
    _psView->scrollRight();
}

void KGVPart::slotScrollUp()
{
    _psView->scrollUp();
}

void KGVPart::slotScrollDown()
{
    _psView->scrollDown();
}

void KGVPart::slotReadDown()
{
    if( !_psView->readDown() )
	slotNextPage();
}

void KGVPart::slotPrevPage()
{
    _docManager->prevPage();
    _psView->scrollTop();
}

void KGVPart::slotNextPage()
{
    _docManager->nextPage();
    _psView->scrollTop();
}

void KGVPart::slotGotoStart()
{
    _docManager->firstPage();
    _psView->scrollTop();
}

void
KGVPart::slotGotoEnd()
{
    _docManager->lastPage();
    _psView->scrollTop();
}

void KGVPart::startWatching()
{
    //NOTE: isFileOpen() will (appropriately) return false if the viewer is
     // viewing data from stdin
    if( miniWidget()->isFileOpen() ) {
	// Setup the dirwatcher to watch this file.
	_watch = new KDirWatch();
	_watch->addDir( m_file );
	connect( _watch, SIGNAL( dirty( const QString& ) ),
		 _docManager, SLOT( fileChanged( const QString& ) ) );
	_watch->startScan();
    }
}

void KGVPart::stopWatching()
{
    if( _watch != 0 ) {
	delete _watch;
	_watch = 0;
    }
}

void KGVPart::slotWatchFile()
{
    if( watchaction->isChecked() )
	startWatching();
    else
	stopWatching();
}

void KGVPart::slotCancelWatch()
{
    stopWatching();
    watchaction->setChecked( false );
}

void
KGVPart::enableStateDepActions( bool enable )
{
    int count = statedep->count();
    for ( int i = 0; i < count; i++ )
	statedep->action( i )->setEnabled( enable );

    if( true ) {
	QStringList items = miniWidget()->sizeList();
	items.prepend( i18n( "Auto ") );
	media->setItems( items );
    }
}

bool
KGVPart::openStdin()
{
  QString s ("-");
  bool b = _docManager->openFile(s);
  if (b)
    enableStateDepActions( true );  //do we want eAA (b) ?
  return b;
}

bool
KGVPart::openFile()
{
    bool success = _docManager->openFile( m_file );
    
    if( success ) {
	enableStateDepActions( true );
	slotWatchFile();
    }

    return success;
}

void
KGVPart::slotFancy()
{
    _docManager->enableFancyPageLabels( fancyAct->isChecked() );
}

void
KGVPart::slotNewPage( int )
{
  ;//media->setCurrentItem (miniWidget()->getSize()-1);
  ;//orientation->setCurrentItem (miniWidget()->getOrientation()-1);
  //TODO -- zoom
}

void KGVPart::slotOrientation( int id )
{
    if( id == 0 )
	miniWidget()->setAutoOrientation();
    else
	miniWidget()->setManualOrientation( id );
}

void
KGVPart::slotMedia(int id)
{
    if( id == 0 )
	miniWidget()->setAutoPageMedia();
    else
	miniWidget()->setManualPageMedia( id );
}

void KGVPart::slotShowScrollBars()
{
    _psView->enableScrollBars( showscrollbars->isChecked() );
}

void
KGVPart::slotShowMarkList()
{
    if( showmarklist->isChecked() ) {
	_markList->show();
	_scrollBox->show();
	_divider->show();
    }
    else {
	_markList->hide();
	_scrollBox->hide();
	_divider->hide();
    }
}


KGVBrowserExtension::KGVBrowserExtension( KGVPart *parent ) :
  KParts::BrowserExtension( parent, "KGVBrowserExtension" )
{
}

void
KGVBrowserExtension::print()
{
  ((KGVPart *)parent())->miniWidget()->print();
}



#include "kgv_view.moc"

