/*
 * Copyright (C) 2004 Robert Hogan <robert at roberthogan dot net>
 */

#include "klamav.h"
#include "freshklam.h"
#include "sigtool.h"
#include "klamscan.h"
#include "schedule.h"
#include "kuarantine.h"
#include "welcome.h"
#include "dbviewer.h"
#include "activityviewer.h"
#include "version.h"
#include "firstrunwizard.h"
#include "collectiondb.h"
#include "configdialog.h"
#include "tabwidget.h"
#include "klamavconfig.h"
#include "klamonacc.h"

#include <tdelocale.h>


#include <tdeaction.h>
#include <tqpushbutton.h>
#include <tqtooltip.h>
#include <tqlayout.h>
#include <ksystemtray.h>
#include <tdemenubar.h>
#include <tdepopupmenu.h>
#include <kdebug.h>
#include <tdemessagebox.h>
#include <kurl.h>
#include <kiconloader.h>

#include <tqdir.h>
#include <tqfile.h>

Klamav *tdemain = 0L;

using namespace KlamAV;

Klamav::Klamav()
    : TDEMainWindow( 0, "KlamAV " )
{

	downloadDBForWizard = false;

	tdemain = this;
	TQVBoxLayout *top = new TQVBoxLayout(this,3,0);

	// We don't want these tabs closed
	TQStringList fixedTabs;
	fixedTabs << i18n("Scan") << i18n("Update");

	tab = new TabWidget(this, "KlamAV", fixedTabs);
	connect( tab, TQ_SIGNAL(tabClosed(TQString)), this, TQ_SLOT(tabClosed(TQString)) );

  	_tray = new KSystemTray(tdemain, "klamav tray");
 _tray->setPixmap( KSystemTray::loadIcon("klamav") );
	connect(_tray,TQ_SIGNAL(quitSelected()),TQ_SLOT(shuttingDown()));

	TDEPopupMenu *conf_menu = _tray->contextMenu();

  EnableFreshklam = new TDEAction(i18n("&Enable Auto-Updates"), "system-software-update", 0,this, TQ_SLOT(contextEnableFK()),actionCollection(),"fk_enable");
  DisableFreshklam = new TDEAction(i18n("&Disable Auto-Updates"), 0, 0, this, TQ_SLOT(contextDisableFK()),actionCollection(),"fk_disable");

	EnableFreshklam->plug(conf_menu);
	DisableFreshklam->plug(conf_menu);

  EnableKlamOnAcc = new TDEAction(i18n("&Start On-Access Scanner"), "filefind", 0,this, TQ_SLOT(contextEnableKOA()),actionCollection(),"koa_enable");
  DisableKlamOnAcc = new TDEAction(i18n("&Stop On-Access Scanner"), 0, 0, this, TQ_SLOT(contextDisableKOA()),actionCollection(),"koa_disable");

  EnableKlamOnAcc->plug(conf_menu);
  DisableKlamOnAcc->plug(conf_menu);

	TQToolTip::add( _tray, i18n( "KlamAV - Virus Protection for TDE" ) );
	_tray->show();

	DisableFreshklam->setEnabled(false);
	EnableFreshklam->setEnabled(true);

        config = TDEGlobal::config();
        config->setGroup("Freshklam");
        TQStringList DatabasePaths = config->readListEntry("lastDownloadPaths");

        config->setGroup("Kuarantine");
        TQStringList QuarantinePaths = config->readListEntry("KuarantineLocations");

	if ((DatabasePaths.isEmpty()) && (QuarantinePaths.isEmpty())){

            firstRunWizard();
        }

	// Menus
	TDEPopupMenu *scanner_menu = new TDEPopupMenu(this);
	scanner_menu->insertItem( SmallIcon("document-open"), i18n("Scan &File..."), this, TQ_SLOT(slotScanFile()), CTRL+Key_O );
	scanner_menu->insertItem( SmallIcon("folder_open"), i18n("Scan &Directory..."), this, TQ_SLOT(slotScanDir()) );
	scanner_menu->insertSeparator();
	scanner_menu->insertItem( SmallIcon("xclock"), i18n("&Schedule scan..."), this, TQ_SLOT(slotScheduleScan()) );
	scanner_menu->insertItem( SmallIcon("configure"), i18n("&Options..."), this, TQ_SLOT(slotOptions()) );
	scanner_menu->insertSeparator();
	scanner_menu->insertItem( SmallIcon("application-exit"), i18n("&Quit"), tdeApp, TQ_SLOT(quit()) );

	tabs_menu = new TDEPopupMenu(this);
	tabs_menu->setCheckable(true);
	showWelcomeTab = tabs_menu->insertItem( SmallIcon("klamav"), i18n("Show &Welcome tab"), this, TQ_SLOT(slotToggleWelcome()) );
	showQuarantineTab = tabs_menu->insertItem( SmallIcon("encrypted"), i18n("Show &Quarantine tab"), this, TQ_SLOT(slotToggleQuarantine()) );
	showDBViewerTab = tabs_menu->insertItem( SmallIcon("system-search"), i18n("Show &Virus Browser tab"), this, TQ_SLOT(slotToggleDBViewer()) );
	showEventsTab = tabs_menu->insertItem( SmallIcon("toggle_log"), i18n("Show &Events tab"), this, TQ_SLOT(slotToggleEvents()) );


	// Menu bar
	KMenuBar *menubar = this->menuBar();
	menubar->insertItem( i18n("&Scanner"), scanner_menu );
	menubar->insertItem( i18n("&Tabs"), tabs_menu );
	menubar->insertItem( i18n("&Help"), helpMenu(NULL,false) );

	top->setMenuBar(menubar);

	activityviewer = new Activityviewer(this, "Events");

	aboutklamav = new Aboutklamav(this, "Welcome");
	updateTabState(0, true); // Welcome tab

	klamscan = new Klamscan(this);
	tab->addTab(klamscan, i18n("Scan"));

	freshklam = new Freshklam(this);
	tab->addTab(freshklam, i18n("Update"));

	connect(freshklam->search_button,TQ_SIGNAL(clicked()),TQ_SLOT(contextUpdateFK()));
	connect(freshklam->cancel_button,TQ_SIGNAL(clicked()),TQ_SLOT(contextDisableFK()));



	kuarantine = new Kuarantine(this, "Quarantine");
	updateTabState(1, true); // Quarantine tab

	klamdb = new KlamDB(this, "DBViewer");
	updateTabState(2, true); // Virus Browser tab

	updateTabState(3, true); // Events tab


	top->addWidget(tab);

  // On-Access scanner
  klamonacc = new KlamOnAcc(this);
  connect( klamonacc, TQ_SIGNAL(stateUpdated()), this, TQ_SLOT(slotKOAStateUpdate()) );

  slotKOAStateUpdate(); // initial state

	connect(tab,TQ_SIGNAL(currentChanged ( TQWidget * ) ),klamdb,TQ_SLOT(shouldIShow(TQWidget *)));

	KStdAction::quit(this, TQ_SLOT(shuttingDown()), actionCollection());

  	if (tdeApp->isRestored()){
		hide();
	}else{
		show();
   	}


	if ((firstDownload) || (downloadDBForWizard)){
		kdDebug() << "firstdownload" << firstDownload << endl;
		kdDebug() << "downloadDBForWizard" << downloadDBForWizard << endl;
		tab->setCurrentPage(2);
		freshklam->slotSearch();
	}
	//klamdb->shouldIShow();

	CollectionDB::instance()->insertEvent("Launch","KlamAV Launched");

    setCaption(TQString("KlamAV %1 (Using ClamAV %2)").arg(KLAMAV_VERSION).arg(KlamavConfig::clamAVVersion()));
}

Klamav::~Klamav()
{
  klamonacc->stop();
  KlamavConfig::writeConfig();
	tdeApp->quit();
}

void  Klamav::shuttingDown(){

	this->topLevelWidget()->hide();

}

bool Klamav::queryClose() {
	if ( freshklam->isFreshklamAlive() || klamscan->scanGoingOn() || klamonacc->isActive() ){
        KMessageBox::information (this,i18n("<p>KlamAV will stay open in the system tray. <br><br>"
        " <b>Remember</b> - you can't quit KlamAV while <br> "
        " a scan, Fresklam or KlamOnAcc is active!</p>"),"KlamAV","dontshow");
		hide();
		return false;

	}
	return true;
}

void Klamav::updateTabState( int tabId, bool init ) {
	if( config->group() != "Tabs" )
		config->setGroup("Tabs");

	TQString optionName, tabName;
	TQWidget* tabWidget;
	int itemId;

	switch(tabId) {
		case 0: // Welcome tab
			optionName="ShowWelcomeTab";
			tabName=i18n("Welcome");
			tabWidget=aboutklamav;
			itemId=showWelcomeTab;
			break;

		case 1: // Quarantine tab
			optionName="ShowQuarantineTab";
			tabName=i18n("Quarantine");
			tabWidget=kuarantine;
			itemId=showQuarantineTab;
			break;

		case 2: // DBViewer tab
			optionName="ShowDBViewerTab";
			tabName=i18n("Virus Browser");
			tabWidget=klamdb;
			itemId=showDBViewerTab;
			break;

		case 3: // Events tab
			optionName="ShowEventsTab";
			tabName=i18n("Events");
			tabWidget=activityviewer;
			itemId=showEventsTab;
			break;
	}

	if( config->readBoolEntry(optionName, true) ) {
		tab->insertTab(tabWidget, tabName);
		tabWidget->show();

		if(!init) tab->setCurrentPage( tab->indexOf(tabWidget) );
	} else {
		if( tab->currentPageIndex() == tabId )
			tab->setCurrentPage(0);

		if( tab->indexOf( tabWidget ) != -1 ) {
			tab->removePage( tabWidget );
		}
		tabWidget->hide();
	}

	tabs_menu->setItemChecked(itemId, config->readBoolEntry(optionName, true) );
}

void Klamav::tabClosed(TQString name) {
	int uncheck;
	TQString optionName;

	if ( name == "Welcome" ) {
		uncheck=showWelcomeTab;
		optionName="ShowWelcomeTab";
	} else if ( name == "Quarantine" ) {
		uncheck=showQuarantineTab;
		optionName="ShowQuarantineTab";
	} else if ( name == "DBViewer" ) {
		uncheck=showDBViewerTab;
		optionName="ShowDBViewerTab";
	} else if ( name == "Events" ) {
		uncheck=showEventsTab;
		optionName="ShowEventsTab";
	}

  tabs_menu->setItemChecked(uncheck, false);
  config->setGroup("Tabs");
	config->writeEntry(optionName, false);
}

// Menu slots
void Klamav::slotScanFile() {
	klamscan->slotScanFile();
}

void Klamav::slotScanDir() {
	klamscan->slotScanDir();
}

void Klamav::slotScheduleScan() {
	Schedule *schedule_dlg = new Schedule(this, "scheduler");
	schedule_dlg->show();
	schedule_dlg->raise();
	schedule_dlg->setActiveWindow();
}

void Klamav::slotOptions() {
	slotConfigKlamav("Scanning Backend");
}

void Klamav::slotToggleWelcome() {
  if( config->group() != "Tabs" )
    config->setGroup("Tabs");

	bool newState = ! config->readBoolEntry("ShowWelcomeTab", true);
	config->writeEntry("ShowWelcomeTab", newState);
	config->sync();

	updateTabState(0, false);
}
void Klamav::slotToggleQuarantine() {
  if( config->group() != "Tabs" )
    config->setGroup("Tabs");

	bool newState = ! config->readBoolEntry("ShowQuarantineTab", true);
	config->writeEntry("ShowQuarantineTab", newState);
	config->sync();

	updateTabState(1, false);
}
void Klamav::slotToggleDBViewer() {
  if( config->group() != "Tabs" )
    config->setGroup("Tabs");

	bool newState = ! config->readBoolEntry("ShowDBViewerTab", true);
	config->writeEntry("ShowDBViewerTab", newState);
	config->sync();

	updateTabState(2, false);
}
void Klamav::slotToggleEvents() {
  if( config->group() != "Tabs" )
    config->setGroup("Tabs");

	bool newState = ! config->readBoolEntry("ShowEventsTab", true);
	config->writeEntry("ShowEventsTab", newState);
	config->sync();

	updateTabState(3, false);
}

void Klamav::slotKOAStateUpdate()
{
    kdDebug() << "slotKOAStateUpdate" << endl;
    bool on = klamonacc->isActive();
    bool enabled = klamonacc->isEnabled();

    _tray->setPixmap(
        KSystemTray::loadIcon(
            (on ? "klamav_on_acc_enabled"
                : "klamav_on_acc_disabled")
        )
    );

    if(enabled) {
        EnableKlamOnAcc->setEnabled(!on);
        DisableKlamOnAcc->setEnabled(on);
    } else {
        EnableKlamOnAcc->setEnabled(false);
        DisableKlamOnAcc->setEnabled(false);
    }
}

void Klamav::contextUpdateFK() {

    freshklam->slotSearch();
}

void Klamav::contextEnableFK() {

    freshklam->enableAutoUpdates();
}

void Klamav::contextDisableFK() {

	freshklam->slotCancel();
// 	DisableFreshklam->setEnabled(false);
// 	EnableFreshklam->setEnabled(true);

}

void Klamav::contextEnableKOA() {
    klamonacc->start();
}

void Klamav::contextDisableKOA() {
    klamonacc->stop();
}

void Klamav::showVirusBrowser() {
	tab->setCurrentPage(5);
}

void Klamav::firstRunWizard() {

        FirstRunWizard wizard;
        wizard.setCaption( i18n( "First-Run Wizard" ));

        TQString homepath = getenv("HOME");
        TQString defaultdb = homepath + "/.klamav/database";
        TQString defaultquar = homepath + "/.klamav/quarantine";

	// Execute wizard
	wizard.exec();

        // These are run after the wizard is finished
        TDEConfig* config = TDEGlobal::config();

        config->setGroup("Freshklam");

        TQString wizardDBPath = wizard.databasePath().path(-1);
        TQString wizardTQRPath = wizard.quarantinePath().path(-1);

        //Configure Database Path
        TQStringList lastDownloadPaths;
        if ((wizardDBPath != "") && (TQDir::cleanDirPath(wizardDBPath) != defaultdb)){
            lastDownloadPaths.prepend( TQString("%1").arg(wizardDBPath));
            checkDir(wizardDBPath);
        }else{
            lastDownloadPaths.prepend( TQString("%1").arg(wizard.defaultDatabasePath()));
            createDefaultKlamAVDir("database");
        }
        config->writeEntry("lastDownloadPaths", lastDownloadPaths);
        config->sync();

        //Configure Quarantine Path
        TQStringList lastQuarLocations;

        config->setGroup("Kuarantine");

        if ((wizardTQRPath != "") && (TQDir::cleanDirPath(wizardTQRPath) != defaultquar)){
            lastQuarLocations.prepend( TQString("%1").arg(wizardTQRPath));
            checkDir(wizardTQRPath);
        }else{
            lastQuarLocations.prepend( TQString("%1").arg(wizard.defaultQuarantinePath()));
            createDefaultKlamAVDir("quarantine");
        }
        config->writeEntry("KuarantineLocations", lastQuarLocations);
        config->sync();

        if (wizard.downloadDatabase()){
            kdDebug() << "downloading database" << endl;
            downloadDBForWizard = true;
        }


}

void  Klamav::createDefaultKlamAVDir(TQString type){

    TQString path = getenv("HOME");
    bool ok = true;
    // directory exist?
    path += "/.klamav";
    TQDir klamavdir(path);
    if (!klamavdir.exists() && !klamavdir.mkdir(path))
        ok = false;

    path += "/" + type;
    if (ok)
    {
        TQDir klamavqdir(path);
        if (!klamavqdir.exists() && !klamavqdir.mkdir(path))
            ok = false;
        else
            chmod(path.ascii(),0700);
    }

}

void  Klamav::checkDir(TQString path){

    TQDir klamavdir(path);
    TQFile f1( path );
    if ((!klamavdir.exists()) || (f1.open( IO_ReadWrite )))
        KMessageBox::information(this, i18n("Either the directory %1 does not exist or you are not able to write to it. Either way, you will have to change it as it cannot be used. Sorry!").arg(path));
    f1.close();

}

void Klamav::slotConfigKlamav( const TQCString& page )
{
    KlamavConfigDialog* dialog = (KlamavConfigDialog*) TDEConfigDialog::exists( "settings" );

    if( !dialog )
    {
        //TDEConfigDialog didn't find an instance of this dialog, so lets create it :
        dialog = new KlamavConfigDialog( this, "settings", KlamavConfig::self() );
        //connect( dialog, TQ_SIGNAL(settingsChanged()), TQ_SLOT(applySettings()) );
    }

    //FIXME it seems that if the dialog is on a different desktop it gets lost
    //      what do to? detect and move it?

    dialog->show();
    dialog->raise();
    dialog->setActiveWindow();

    //so that if the engine page is needed to be shown it works

    if ( !page.isNull() ) dialog->showPage( page );
}


#include "klamav.moc"
