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

#include "directorylist.h"
#include "schedule.h"
#include "klamav.h"
#include "datepicker.h"


#include "ktview.h"


#include <tqlabel.h>
#include <kurlrequester.h>
#include <tqlayout.h>
#include <tqlistview.h>
//#include <qlistviewitem.h>
#include <tdeglobalsettings.h>
#include <kdialog.h>
#include <dcopclient.h>
#include <kstdguiitem.h>
#include <sys/stat.h>
#include <kdebug.h> // REMOVEME

/* Finding out ICEauthority path */
#include <kprocio.h>

Schedule::Schedule( TQWidget* parent, const char* name, bool modal, WFlags fl )
    : TQDialog( parent, name, modal, fl )
{

	setCaption( i18n( "Schedule Scan" ) );

 	cthost = new CTHost();
// 	const CTHost& cth(*cthost);

	// for each user
//  	CTCronIterator i = const_cast<CTHost&>(cth).cron.begin();
// 	CTCron* ctcron((CTCron*)*i);

  /* Figure out where the ICEauthority file is located */
  getICEauth();

	//bool isRTL = TQApplication::reverseLayout();
	TQHBoxLayout *hbox = new TQHBoxLayout(this, KDialog::marginHint(),
			KDialog::spacingHint(), "hbox");

	/* CollectionSetup not in full mode due to issue #19 */
	setup = new CollectionSetup(this, true, false);
	hbox->addWidget(setup);

	TQVBoxLayout *vbox = new TQVBoxLayout(0, 0, 0, "vbox");
	hbox->addLayout(vbox);

	TQGroupBox *group = new TQGroupBox("Schedule Scan of Selected Folders", this);
	vbox->addWidget(group);



	TQGridLayout *layout = new TQGridLayout( group, 6, 6, KDialog::spacingHint(),
			KDialog::spacingHint(), "layout");
	layout->addRowSpacing(0, group->fontMetrics().height());
	layout->setColStretch(0, 1);
	layout->setColStretch(1, 1);

	

	check_combo = new TQComboBox(false, group);
   check_combo->insertItem( i18n("When I log in to TDE"));
   check_combo->insertItem( i18n("Every day at "));
   check_combo->insertItem( i18n("Every day at the current time"));
   check_combo->insertItem( i18n("Every week from now on at the current time"));
   check_combo->insertItem( i18n("Every week from now on at"));
   check_combo->insertItem( i18n("Every week from a specific date at"));
   check_combo->insertItem( i18n("Every month from now on at the current time"));
   check_combo->insertItem( i18n("Every month from now on at"));
   check_combo->insertItem( i18n("Every month from a specific date at"));
   check_combo->insertItem( i18n("Once only on a specific date at the current time"));
   check_combo->insertItem( i18n("Once only on a specific date at"));

 	layout->addWidget(check_combo,1,0);
 	connect( check_combo, TQ_SIGNAL(activated(int)),this,
 		TQ_SLOT(slotQueryDatePicker(int)) );


	hour = new HMSTimeWidget( group );
	hour->setWrapping(true);
	hour->setMaxValue(23);
	hour->setValidator(new KStrictIntValidator(0, 23, hour));
	layout->addWidget(hour, 1, 1);
	
	TQLabel *dots1 = new TQLabel(":", group);
	dots1->setMinimumWidth( 7 );
	dots1->setAlignment( TQLabel::AlignCenter );
	layout->addWidget(dots1, 1, 2);
	
	minute = new HMSTimeWidget( group );
	minute->setWrapping(true);
	minute->setMinValue(0);
	minute->setMaxValue(59);
	minute->setValidator(new KStrictIntValidator(0, 59, minute));
	layout->addWidget(minute, 1, 3);




	TQPushButton* add = new TQPushButton ("Add", group);
	layout->addWidget(add,1,5);
	//add->setFixedSize(add->sizeHint());

 	connect( add, TQ_SIGNAL(clicked()),
 		TQ_SLOT(slotScheduleScan()) );

	TQPushButton* del = new TQPushButton ("Delete", group);
	layout->addWidget(del,1,6);
	//del->setFixedSize(del->sizeHint());

 	connect( del, TQ_SIGNAL(clicked()),
 		TQ_SLOT(slotDelete()) );


	//schedulebox = new TQListView(group);
	schedulebox = new KTView(group);
	TQFontMetrics rb_fm(schedulebox->fontMetrics());
	schedulebox->setMinimumSize(rb_fm.width("0")*55,
				rb_fm.lineSpacing()*15);
/*	//kdDebug() << ((schedulebox->width())/2) << endl;
	schedulebox->addColumn( "Paths to Scan",(group->width()));
        schedulebox->addColumn( "When to Scan",(group->width()));
	schedulebox->setResizeMode(TQListView::AllColumns);
	schedulebox->setSelectionMode( TQListView::Extended );
	schedulebox->setAllColumnsShowFocus(true);*/
	
	layout->addMultiCellWidget(schedulebox, 2, 4,0,6);

	TQHBoxLayout *h5 = new TQHBoxLayout( vbox, KDialog::spacingHint() );
	h5->addStretch( 1 );

	// OK
	KPushButton *pbOk = new KPushButton(KStdGuiItem::ok(), this, "pbOk");
	pbOk->setDefault(true);
	h5->addWidget( pbOk);
	
	// Cancel
// 	KPushButton *pbCancel = new KPushButton(KStdGuiItem::cancel(), this, "pbCancel");
// 	h5->addWidget( pbCancel);

	connect(pbOk, TQ_SIGNAL(clicked()), TQ_SLOT(slotOK()));
/*	connect(pbCancel, TQ_SIGNAL(clicked()), TQ_SLOT(slotCancel()));*/
	
	schedulebox->hideCommand();
}

Schedule::~Schedule()
{
	delete cthost;
}


void Schedule::slotQueryDatePicker(int)
{

	if (check_combo->currentText().contains(i18n("specific date")) ){
		DatePicker *_calendar;	
		_calendar = new DatePicker(this, TQDateTime::currentDateTime().date());
		int x = this->width() - (this->width()/2);
		int y = this->height() - (this->height()/2);
		_calendar->move(TQPoint(x,y));
		_calendar->show();
		_calendar->setFocus();
		connect( _calendar, TQ_SIGNAL(signalSelectedDate(TQDate)),this,
			TQ_SLOT(slotAddDateToCombo(TQDate)) );

	}
}

void Schedule::slotAddDateToCombo(TQDate newdate)
{

	//check_combo->insertItem
	_date = newdate;
	//kdDebug() << newdate.toString() << endl;
	TQString newstring = check_combo->currentText().replace("a specific date",newdate.toString());
	check_combo->insertItem(newstring);
	check_combo->setCurrentItem(check_combo->count()-1);

	DCOPClient* client = TDEApplication::dcopClient();
	client->attach();
	client->registerAs(kapp->name());


	
}


void Schedule::slotScheduleScan()
{
	// Update directory list
	filepattern = setup->dirs();
	setup->reset();

/* 	cthost = new CTHost();*/
/* 	const CTHost& cth(*cthost);
// 
// 	// for each user
 	CTCronIterator i = const_cast<CTHost&>(cth).cron.begin();
 	CTCron* ctcron((CTCron*)*i);	*/
 
	//delete cttask;
	TQString command = check_combo->currentText();

	
	
 	cttask = new CTTask ("", "", TRUE);

	cttask->user = "";

	if (command.contains(i18n("When I log in to TDE")) ){
		TQString startupcommand = createStartupScript();
		cttask->comment = (const char *)i18n("KlamAV Scheduled Scan at TDE Login of %1").arg(filepattern.join(" ")).local8Bit();
		cttask->command = (const char *)TQString("%1").arg(startupcommand).local8Bit();
		cttask->enabled = FALSE;

	}else{
	
		cttask->comment = (const char *)i18n("KlamAV Scheduled Scan of %1").arg(filepattern.join(" ")).local8Bit();
		cttask->command = (const char *)TQString("%1 '%2'").arg(createScanScript()).arg(filepattern.join("' '")).local8Bit();
		cttask->enabled = TRUE;
	}
	cttask->silent = FALSE;
	

	int curhour = (TQTime::currentTime()).hour();
	unsigned int curmin = (TQTime::currentTime()).minute();
	
	int shour = TQString(hour->text()).toInt();
	unsigned int smin = TQString(minute->text()).toInt();

	int sdatedayofweek = _date.dayOfWeek();
	int todaydayofweek = TQDate::currentDate().dayOfWeek();


	if (command.contains(i18n("at the current time")) ){
		cttask->hour.set(curhour, TRUE);
		cttask->minute.set(curmin, TRUE);
	}else{
		cttask->hour.set(shour, TRUE);
		cttask->minute.set(smin, TRUE);
	}

	if (command.contains(i18n("Every week")) ){
		if (command.contains(i18n("from now on") ))
			cttask->dayOfWeek.set(todaydayofweek, TRUE);
		else
			cttask->dayOfWeek.set(sdatedayofweek, TRUE);
		for (int dm = 1; dm <= 31; dm++)
		{
			cttask->dayOfMonth.set(dm, true);
		}
		for (int mo = 1; mo <= 12; mo++)
		{
			cttask->month.set(mo, true);
		}

	}else if (command.contains(i18n("Every month")) ){
		if (command.contains(i18n("from now on") ))
			cttask->dayOfMonth.set(TQDate::currentDate().day(), TRUE);
		else
			cttask->dayOfMonth.set(_date.day(), TRUE);
		for (int dw = 1; dw <= 7; dw++)
		{
		cttask->dayOfWeek.set(dw, true);
		}
		for (int mo = 1; mo <= 12; mo++)
		{
			cttask->month.set(mo, true);
		}
	}else if (command.contains(i18n("Every day")) ){
		for (int dw = 1; dw <= 7; dw++)
		{
		cttask->dayOfWeek.set(dw, true);
		}

		for (int dm = 1; dm <= 31; dm++)
		{
			cttask->dayOfMonth.set(dm, true);
		}
		for (int mo = 1; mo <= 12; mo++)
		{
			cttask->month.set(mo, true);
		}
	}else if (command.contains(i18n("Once only")) ){
		cttask->month.set(_date.month(), TRUE);
		cttask->dayOfMonth.set(_date.day(), TRUE);
	}else{
		cttask->month.set(1, TRUE);
		cttask->dayOfMonth.set(1, TRUE);
		cttask->dayOfWeek.set(1, true);
		cttask->hour.set(0, TRUE);
		cttask->minute.set(0, TRUE);

	}




	TQString description = TQString::fromLocal8Bit(cttask->describe().c_str()); 
	CTCron* ctcron(schedulebox->getCTCron());
	if (cttask->dirty())
		ctcron->task.push_back(cttask);
		//new KTListTask(this, ctcron, cttask); // TQt will clean up
	else
		delete cttask;


	schedulebox->refresh();
	cthost->apply();
	
	//TQListViewItem* tm = new TQListViewItem( schedulebox, _filepattern, description);

/*	if (cthost->isError())
	{
		KMessageBox::error(this, cthost->errorMessage());
	}
	//kdDebug() << "finished crontab" << endl;


	delete cthost;*/
}


void Schedule::slotDelete()
{

	//kdDebug() << schedulebox->currentItem()->text(1) << endl;
	TQFile file(schedulebox->currentItem()->text(1).section(" ",0,0).stripWhiteSpace());
	file.remove();
	schedulebox->remove();
	cthost->apply();
}

void Schedule::slotOK()
{
	cthost->apply();
	close();
}

void Schedule::slotCancel()
{
	close();
}

TQString Schedule::createScanScript()
{

	TQString path = getenv("HOME");
	path += "/.klamav";
	TQDir klamavdir(path);
	if (!klamavdir.exists() && !klamavdir.mkdir(path))
		return TQString("Error");

	TQTime now = TQTime::currentTime();
	TQDate today = TQDate::currentDate();
	TQString timestring = TQString("%1%2")
		.arg(today.toString("ddMMyy"))
		.arg(now.toString("hhmmss"));

	TQFile file( TQString("%1/ScanWithKlamav.sh").arg(path) );

	if ( file.open( IO_WriteOnly ) ) {
		TQTextStream ts( &file );
	
		TQString tdedir = getenv("TDEDIR");
	
	
		ts << "#!/bin/bash" << "\n";
		ts << "export HOSTNAME=`hostname`" << "\n";
		ts << TQString("export PATH=%1").arg(TQString(getenv("PATH"))) << "\n";
		/* The following inspired by https://unix.stackexchange.com/a/17278 */
		ts << "if [ -z \"$DISPLAY\" ]; then" << "\n";
		ts << "        for d in /tmp/.X11-unix/X*" << "\n";
		ts << "        do" << "\n";
		ts << "                export DISPLAY=$(echo $d|sed \"s!/tmp/.X11-unix/X!:!\")" << "\n";
		ts << "        done" << "\n";
		ts << "fi" << "\n";
		ts << "export DCOPSERVER=`cat ${HOME}/.DCOPserver_${HOSTNAME}_${DISPLAY} | grep local`" << "\n";
    /* This path is always the same for the current user */
    ts << TQString("export ICEAUTHORITY=%1 # issue 21").arg(iceauth) << "\n";
		ts << "# Execution starts here" << "\n";
		ts << "if [ \"$1\" = \"\" ]; then" << "\n";
		ts << "        exit 1" << "\n";
		ts << "fi" << "\n";
		ts << "until [ -z \"$1\" ]  # Until all parameters used up..." << "\n";
		ts << "do" << "\n";
		ts << "  if [ \"${URL}\" = \"\" ]; then" << "\n";
		ts << "        URL=$1" << "\n";
		ts << "        SCANTHIS=$1" << "\n";
		ts << "  else" << "\n";
		ts << "        URL=${URL}'*'$1" << "\n";
		ts << "        SCANTHIS=${SCANTHIS}' '$1" << "\n";
		ts << "  fi" << "\n";
		ts << "  shift" << "\n";
		ts << "done" << "\n";
        ts << "DCOPEXEC=`which dcop`" << "\n";
        ts << "KLAMAVEXEC=`which klamav`" << "\n";
        ts << "if ${DCOPEXEC} `${DCOPEXEC}|grep klamav|head -1` DCOPKlamscan scanURLs \"${URL}\"; then" << "\n";
		ts << "        exit 0" << "\n";
		ts << "else" << "\n";
		ts << "         ${KLAMAVEXEC} --scanthis ${SCANTHIS}" << "\n";
		ts << "fi" << "\n";
	
		file.close();
		chmod(file.name().ascii(), S_IWUSR | S_IRUSR | S_IEXEC );
		return file.name();
	}else
		return TQString("Error");

}

TQString Schedule::createStartupScript()
{

	TQString path = TDEGlobalSettings::autostartPath();
	TQDir startupdir(path);
	if (!startupdir.exists())
		return TQString("Error");

	TQTime now = TQTime::currentTime();
	TQDate today = TQDate::currentDate();
	TQString timestring = TQString("%1%2")
		.arg(today.toString("ddMMyy"))
		.arg(now.toString("hhmmss"));

	TQFile file( TQString("%1klamav_%2.desktop").arg(path).arg(timestring ));

	if ( file.open( IO_WriteOnly ) ) {
		TQTextStream ts( &file );
	
		ts << "[Desktop Entry]" << "\n";
		ts << "Encoding=UTF-8" << "\n";
		ts << "Name=Klamav" << "\n";
		ts << TQString("Exec=klamav %i %m -caption \"%c\" --scanthis '%1'").arg(filepattern.join("' '")) << "\n";
		ts << "Icon=klamav" << "\n";
		ts << "Type=Application" << "\n";
		ts << "DocPath=klamav/klamav.html" << "\n";
		ts << "Comment=An Anti-Virus Manager" << "\n";
		ts << "Comment[cs]=Aplikace typu KPart" << "\n";
		ts << "Comment[da]=Et TDE KPart program" << "\n";
		ts << "Comment[de]=Ein TDE-Programm" << "\n";
		ts << "Comment[el]=Μια εφαρμογή TDE KPart" << "\n";
		ts << "Comment[eo]=TDEa Parto-aplikaĵo" << "\n";
		ts << "Comment[es]=Una aplicación KPart para TDE" << "\n";
		ts << "Comment[et]=TDE KPart rakendus" << "\n";
		ts << "Comment[fi]=TDE KPart sovellus" << "\n";
		ts << "Comment[fr]=Une Application KPart pour TDE" << "\n";
		ts << "Comment[he]=TDE לש KPart םושיי" << "\n";
		ts << "Comment[hu]=Egy TDE KPart tesztalkalmazás" << "\n";
		ts << "Comment[is]=TDE KPart forrit" << "\n";
		ts << "Comment[it]=Un'applicazione \"part\" di TDE" << "\n";
		ts << "Comment[ja]=TDE KPart アプリケーション" << "\n";
		ts << "Comment[ko]=TDE용 KPart 응용 프로그램" << "\n";
		ts << "Comment[lv]=TDE KPart Aplikācija" << "\n";
		ts << "Comment[nl]=een TDE KPart-applicatie" << "\n";
		ts << "Comment[no_NY]=Eit TDE KPart-program" << "\n";
		ts << "Comment[pt]=Uma aplicação KPart" << "\n";
		ts << "Comment[pt_BR]=Uma aplicação KPart do TDE" << "\n";
		ts << "Comment[ro]=O aplicaţie KPart pentru TDE" << "\n";
		ts << "Comment[ru]=Приложение KPart TDE" << "\n";
		ts << "Comment[sk]=TDE KPart aplikácia" << "\n";
		ts << "Comment[sl]=Program za TDE KPart" << "\n";
		ts << "Comment[sr]=TDE KPart aplikacija" << "\n";
		ts << "Comment[sv]=Ett TDE KPart-program" << "\n";
		ts << "Comment[tr]=TDE Kpart Uygulaması" << "\n";
		ts << "Comment[uk]=Програма KPart для TDE" << "\n";
		ts << "Comment[zh_CN.GB2312]=TDE KPart程序" << "\n";
		ts << "Terminal=0" << "\n";
	
		file.close();
		chmod(file.name().ascii(), S_IWUSR | S_IRUSR | S_IEXEC );
		return file.name();
	}else
		return TQString("Error");

}

void Schedule::getICEauth()
{
    /* Code taken from freshklam.cpp */
    TQString command=TQString("iceauth -v exit");

    iceproc = new KProcIO();
    iceproc->setUseShell(TRUE);
    iceproc->setUsePty(KProcIO::Stdout,TRUE);

    *iceproc<<command;

    connect( iceproc, TQ_SIGNAL(readReady(KProcIO *)),
             TQ_SLOT(slotICEoutput(KProcIO *)) );
    connect( iceproc, TQ_SIGNAL(processExited(TDEProcess *)),
             TQ_SLOT(slotICEexited()) );

    iceproc->start(KProcIO::NotifyOnExit);
    iceproc->closeWhenDone();
}


void Schedule::slotICEexited()
{
    delete iceproc;
}

void Schedule::slotICEoutput(KProcIO *)
{
    TQString lineout = "";
    int pos;

    if ((pos = (iceproc->readln(lineout))) != -1) {
        if ((pos = (lineout.find("Using authority file"))) != -1){
            lineout = lineout.stripWhiteSpace();
            int StartPoint = (lineout.find("Using authority file") + 20);
            iceauth = lineout.mid(StartPoint).stripWhiteSpace();
            //    kdDebug() << "iceauth file: " << iceauth << endl;
        }
    }

    iceproc->ackRead();
    lineout = "";
}



HMSTimeWidget::HMSTimeWidget(TQWidget *parent, const char *name) :
	KIntSpinBox(parent, name)
{
}


TQString HMSTimeWidget::mapValueToText(int value)
{
  TQString s = TQString::number(value);
  if( value < 10 ) {
    s = "0" + s;
  }
  return s;
}

TQValidator::State KStrictIntValidator::validate( TQString & input, int & d ) const
{
  if( input.isEmpty() )
    return Valid;

  State st = TQIntValidator::validate( input, d );

  if( st == Intermediate )
    return Invalid;

  return st;
}

const CTHost& Schedule::getCTHost() const
{
  return *cthost;
}


#include "schedule.moc"
