/***************************************************************************
                          dvbconfig.cpp  -  description
                             -------------------
    begin                : Wed Apr 21 2004
    copyright            : (C) 2004-2005 by Christophe Thommeret
    email                : hftom@free.fr
    last modified        : $Date: 2005/08/27 00:35:28 $ by $Author: hftom $
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>

#include <linux/dvb/frontend.h>

#include <qdir.h>
#include <qlayout.h>
#include <qgroupbox.h>
#include <qregexp.h>
#include <qradiobutton.h>

#include <klocale.h>
#include <kiconloader.h>
#include <kmessagebox.h>
#include <kfiledialog.h>
#include <ktar.h>
#include <kstandarddirs.h>

#include "dvbconfig.h"
#include "gdvb.h"



MSpinBox::MSpinBox( QWidget *parent, int devNum ) : QSpinBox( 1, 4, 1, parent )
{
	deviceNumber = devNum;
	connect( this, SIGNAL(valueChanged(int)), this, SLOT(slotValueChanged(int)) );
}



void MSpinBox::slotValueChanged( int value )
{
	emit signalValueChanged( value, deviceNumber );
}



MPushButton::MPushButton( QWidget *parent, int devNum, int lnbNum ) : KPushButton( parent )
{
	deviceNumber = devNum;
	lnbNumber = lnbNum;
	connect( this, SIGNAL(clicked()), this, SLOT(isClicked()) );
}



void MPushButton::isClicked()
{
	emit clicked( deviceNumber, lnbNumber );
}



LNB::LNB()
{
	switchFreq = 11700;
	loFreq = 9750;
	hiFreq = 10600;
}



Device::Device( int anum, int tnum, fe_type_t t, const QString &n )
{
	adapter = anum;
	tuner = tnum;
	type = t;
	name = n;
	source = "";
}



Category::Category( const QString &tname, const QString &ticon )
{
	name = tname;
	icon = ticon;
}



DVBconfig::DVBconfig( const QString &dvbConf )
{
	dvbConfigDir = dvbConf;
	config = new KConfig( dvbConfigDir+"dvbrc" );
	downProgress = 0;
	categories.setAutoDelete( true );
	devList.setAutoDelete( true );
	startup();
	readConfig();
}



DVBconfig::~DVBconfig()
{
	saveConfig();
	delete config;
	categories.clear();
	devList.clear();
}



bool DVBconfig::haveDvbDevice()
{
	int i=0, j=0, res, fdFrontend=0;
	struct dvb_frontend_info info;
	bool ret = false;

	while ( i>=0 ) {
		j = 0;
		while ( j>=0 ) {
			fdFrontend = open( QString("/dev/dvb/adapter%1/frontend%2").arg( i ).arg( j ).ascii(), O_RDWR);
			if ( fdFrontend<0 ) {
				perror( QString("/dev/dvb/adapter%1/frontend%2 : ").arg( i ).arg( j ).ascii() );
				if ( j==0 )
					i = -1;
				j=-1;
			}
			else {
				if ( (res = ioctl( fdFrontend, FE_GET_INFO, &info ) < 0) ) {
					perror( QString("/dev/dvb/adapter%1/frontend%2 FE_GET_INFO: ").arg( i ).arg( j ).ascii() );
				}
				else {
					fprintf(stderr,"/dev/dvb/adapter%d/frontend%d : opened ( %s )\n", i, j, info.name );
					ret = true;
				}
				close( fdFrontend );
				++j;
			}
		}
		if ( i!=-1 )
			++i;
	}

	return ret;
}



void DVBconfig::startup()
{
	int i=0, j=0, res, fdFrontend=0;
	struct dvb_frontend_info info;

	while ( i>=0 ) {
		j = 0;
		while ( j>=0 ) {
			fdFrontend = open( QString("/dev/dvb/adapter%1/frontend%2").arg( i ).arg( j ).ascii(), O_RDWR);
			if ( fdFrontend<0 ) {
				if ( j==0 )
					i = -1;
				j=-1;
			}
			else {
				if ( !(res = ioctl( fdFrontend, FE_GET_INFO, &info ) < 0) ) {
					devList.append( new Device( i, j, info.type, info.name ) );
				}
				close( fdFrontend );
				++j;
			}
		}
		if ( i!=-1 )
			++i;
	}

	//devList.append( new Device( 0, 1, FE_QPSK, "Dummy S" ) );
	//devList.append( new Device( 1, 0, FE_OFDM, "Dummy T" ) );
	//devList.append( new Device( 2, 0, FE_QAM, "Dummy C" ) );
}



void DVBconfig::setDownloadResult( Job *job )
{
	if ( downProgress && job ) {
		delete downProgress;
		downProgress = 0;
	}
}



void DVBconfig::setDownloadPercent( Job *job, unsigned long percent )
{
	if ( downProgress && job )
		downProgress->progressBar()->setProgress( percent );
}



bool DVBconfig::loadDvbData( QWidget *parent )
{
	QString s="";
	FileCopyJob *job;
	QFile f( dvbConfigDir+"dvbdata.tar.gz" );

	//if ( f.exists() ) f.remove();
	downProgress = new KProgressDialog( parent, "progress", i18n("Downloading... "), i18n("Copying data files..."), true );
	downProgress->progressBar()->setTotalSteps( 100 );
	//job = file_copy( KURL( "http://hftom.free.fr/kaxtv/dvbdata.tar.gz" ), KURL( dvbConfigDir+"dvbdata.tar.gz" ), -1, true, false, false );
	job = file_copy( KURL( "http://hftom.free.fr/kaxtv/dvbdata.tar.gz" ), KURL( dvbConfigDir+"dvbdata.tar.gz" ), -1, true, false, false );
	connect( job, SIGNAL(result(KIO::Job*)), this, SLOT(setDownloadResult(KIO::Job*)) );
	connect( job, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(setDownloadPercent(KIO::Job*,unsigned long)) );
	downProgress->exec();
	disconnect( job, SIGNAL(result(KIO::Job*)), this, SLOT(setDownloadResult(KIO::Job*)) );
	disconnect( job, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(setDownloadPercent(KIO::Job*,unsigned long)) );
	if ( downProgress ) {
		delete downProgress;
		downProgress = 0;
	}
	KTar tar( dvbConfigDir+"dvbdata.tar.gz");
	if ( tar.open( IO_ReadOnly ) ) {
		tar.directory()->copyTo( dvbConfigDir );
		return true;
	}
	else
		return false;
}



bool DVBconfig::localData()
{
	QString s = locate("data","kaffeine/dvbdata.tar.gz");
	KTar tar( s );
	if ( tar.open( IO_ReadOnly ) ) {
		tar.directory()->copyTo( dvbConfigDir );
		return true;
	}
	else
		return false;
}



bool DVBconfig::haveData()
{
	if ( !QDir( dvbConfigDir+"dvb-s" ).exists() || !QDir( dvbConfigDir+"dvb-c" ).exists() || !QDir( dvbConfigDir+"dvb-t" ).exists() ) {
		loadDvbData(0);
		if ( !QDir( dvbConfigDir+"dvb-s" ).exists() || !QDir( dvbConfigDir+"dvb-c" ).exists() || !QDir( dvbConfigDir+"dvb-t" ).exists() ) {
			if ( !localData() )
				return false;
		}
	}
	return true;
}



QStringList DVBconfig::getSourcesList( int devNum )
{
	QString s;
	QStringList list;

	switch ( devList.at(devNum)->type ) {
		case FE_QPSK : s = "dvb-s"; break;
		case FE_QAM : s = "dvb-c"; break;
		case FE_OFDM : s = "dvb-t"; break;
		default : return list;
	}
	list = QDir( dvbConfigDir+s ).entryList( QDir::Files, QDir::Name );
	return list;
}



void DVBconfig::addCategory( const QString &name, const QString &icon )
{
	categories.append( new Category( name, icon ) );
}



void DVBconfig::removeCategory( const QString &name )
{
	int i;

	for ( i=0; i<(int)categories.count(); i++ ) {
		if ( categories.at(i)->name==name ) {
			categories.remove( i );
			break;
		}
	}
}



void DVBconfig::changeIconCategory( const QString &name, const QString &icon )
{
	int i;

	if ( name==i18n("All") )
		allIcon = icon;
	else if ( name==i18n("TV") )
		tvIcon = icon;
	else if ( name==i18n("Radio") )
		radioIcon = icon;
	else {
		for ( i=0; i<(int)categories.count(); i++ ) {
			if ( categories.at(i)->name==name ) {
				categories.at(i)->icon = icon;
				break;
			}
		}
	}
}



void DVBconfig::readConfig()
{
	QSize size;
	QString s;
	int i, j;

	config->setGroup( "DVB Options" );
	broadcastAddress = config->readEntry( "BroadcastAddress", "192.168.0.255" );
	broadcastPort = config->readNumEntry( "BroadcastPort", 1234 );
	senderPort = config->readNumEntry( "SenderPort", 1235 );
	size = QSize(600, 350);
	epgSize = config->readSizeEntry( "EPG Geometry", &size );
	size = QSize(600, 300);
	timerSize = config->readSizeEntry( "Timers Geometry", &size );
	size = QSize(300, 300);
	scanSize = config->readSizeEntry( "Scan Geometry", &size );
	beginMargin = config->readNumEntry( "BeginMargin", 5 );
	endMargin = config->readNumEntry( "EndMargin", 10 );
	instantDuration = config->readNumEntry( "InstantDuration", 120 );
	format = config->readNumEntry( "PrefFormat", OutTS );
	recordDir = config->readEntry( "RecordDir", QDir::homeDirPath() );
	if ( !recordDir.endsWith("/") )
		recordDir+= "/";
	shiftDir = config->readEntry( "ShiftDir", QDir::homeDirPath() );
	if ( !shiftDir.endsWith("/") )
		shiftDir+= "/";
	for ( i=0; i<(int)devList.count(); i++ ) {
		devList.at(i)->source = config->readEntry( QString("DVB%1").arg(i), "" );
		if ( devList.at(i)->type==FE_QPSK ) {
			devList.at(i)->lnb0.switchFreq = config->readNumEntry( QString("DVB%1_LNB0_switch").arg(i), 11700 );
			devList.at(i)->lnb0.loFreq = config->readNumEntry( QString("DVB%1_LNB0_lo").arg(i), 9750 );
			devList.at(i)->lnb0.hiFreq = config->readNumEntry( QString("DVB%1_LNB0_hi").arg(i), 10600 );
			devList.at(i)->lnb1.switchFreq = config->readNumEntry( QString("DVB%1_LNB1_switch").arg(i), 11700 );
			devList.at(i)->lnb1.loFreq = config->readNumEntry( QString("DVB%1_LNB1_lo").arg(i), 9750 );
			devList.at(i)->lnb1.hiFreq = config->readNumEntry( QString("DVB%1_LNB1_hi").arg(i), 10600 );
			devList.at(i)->lnb2.switchFreq = config->readNumEntry( QString("DVB%1_LNB2_switch").arg(i), 11700 );
			devList.at(i)->lnb2.loFreq = config->readNumEntry( QString("DVB%1_LNB2_lo").arg(i), 9750 );
			devList.at(i)->lnb2.hiFreq = config->readNumEntry( QString("DVB%1_LNB2_hi").arg(i), 10600 );
			devList.at(i)->lnb3.switchFreq = config->readNumEntry( QString("DVB%1_LNB3_switch").arg(i), 11700 );
			devList.at(i)->lnb3.loFreq = config->readNumEntry( QString("DVB%1_LNB3_lo").arg(i), 9750 );
			devList.at(i)->lnb3.hiFreq = config->readNumEntry( QString("DVB%1_LNB3_hi").arg(i), 10600 );
		}
	}
	j = config->readNumEntry( "NumCategories", 0 );
	for ( i=0; i<j; i++ )
		categories.append( new Category( config->readEntry( QString("CategoryName%1").arg(i), "" ), config->readEntry( QString("CategoryIcon%1").arg(i), "kaffeine" ) ) );
	allIcon = config->readEntry( "AllIcon", "kaffeine" );
	tvIcon = config->readEntry( "TvIcon", "kdvbtv" );
	radioIcon = config->readEntry( "RadioIcon", "kdvbra" );
	lastChannel = config->readNumEntry( "LastChannel", 1 );
	alternateLayout = config->readBoolEntry( "AlternateLayout", false );
	splitSizes = config->readIntListEntry("SplitSizes");
	defaultCharset = config->readEntry( "DefaultCharset", "ISO8859-1" );
}



void DVBconfig::saveConfig()
{
	int i;

	config->setGroup( "DVB Options" );
	config->writeEntry( "EPG Geometry", epgSize );
	config->writeEntry( "Timers Geometry", timerSize );
	config->writeEntry( "Scan Geometry", scanSize );
	config->writeEntry( "BeginMargin", beginMargin );
	config->writeEntry( "EndMargin", endMargin );
	config->writeEntry( "InstantDuration", instantDuration );
	config->writeEntry( "PrefFormat", format );
	config->writeEntry( "RecordDir", recordDir );
	config->writeEntry( "ShiftDir", shiftDir );
	config->writeEntry( "BroadcastAddress", broadcastAddress );
	config->writeEntry( "BroadcastPort", broadcastPort );
	config->writeEntry( "SenderPort", senderPort );
	for ( i=0; i<(int)devList.count(); i++ ) {
		config->writeEntry( QString("DVB%1").arg(i), devList.at(i)->source );
		if ( devList.at(i)->type==FE_QPSK ) {
			config->writeEntry( QString("DVB%1_LNB0_switch").arg(i), devList.at(i)->lnb0.switchFreq );
			config->writeEntry( QString("DVB%1_LNB0_lo").arg(i), devList.at(i)->lnb0.loFreq );
			config->writeEntry( QString("DVB%1_LNB0_hi").arg(i), devList.at(i)->lnb0.hiFreq );
			config->writeEntry( QString("DVB%1_LNB1_switch").arg(i), devList.at(i)->lnb1.switchFreq );
			config->writeEntry( QString("DVB%1_LNB1_lo").arg(i), devList.at(i)->lnb1.loFreq );
			config->writeEntry( QString("DVB%1_LNB1_hi").arg(i), devList.at(i)->lnb1.hiFreq );
			config->writeEntry( QString("DVB%1_LNB2_switch").arg(i), devList.at(i)->lnb2.switchFreq );
			config->writeEntry( QString("DVB%1_LNB2_lo").arg(i), devList.at(i)->lnb2.loFreq );
			config->writeEntry( QString("DVB%1_LNB2_hi").arg(i), devList.at(i)->lnb2.hiFreq );
			config->writeEntry( QString("DVB%1_LNB3_switch").arg(i), devList.at(i)->lnb3.switchFreq );
			config->writeEntry( QString("DVB%1_LNB3_lo").arg(i), devList.at(i)->lnb3.loFreq );
			config->writeEntry( QString("DVB%1_LNB3_hi").arg(i), devList.at(i)->lnb3.hiFreq );
		}
	}
	config->writeEntry( "NumCategories", categories.count() );
	for ( i=0; i<(int)categories.count(); i++ ) {
		config->writeEntry( QString("CategoryName%1").arg(i), categories.at(i)->name );
		config->writeEntry( QString("CategoryIcon%1").arg(i), categories.at(i)->icon );
	}
	config->writeEntry( "AllIcon", allIcon );
	config->writeEntry( "TvIcon", tvIcon );
	config->writeEntry( "RadioIcon", radioIcon );
	config->writeEntry( "LastChannel", lastChannel );
	config->writeEntry( "AlternateLayout", alternateLayout );
	config->writeEntry( "SplitSizes", splitSizes );
	config->writeEntry( "DefaultCharset", defaultCharset );
	config->sync();
}



bool DVBconfig::firstRun()
{
	config->setGroup( "DVB Options" );
	if ( config->readNumEntry( "FirstRun", 0 )<2 ) {
		config->writeEntry( "FirstRun", 2 );
		return true;
	}
	return false;
}



DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent ) :
	KDialogBase ( IconList, i18n("DVB Settings"), Ok|Cancel, Ok, parent, "dvbConfigDialog", true, true )
{
	QLabel *lab;
	KIconLoader *icon = new KIconLoader();
	QHBoxLayout *h1;
	QString s;
	int i;
	QVBoxLayout *vb;
	QGroupBox *gb;
	QGridLayout *grid;
	QLabel *ident;
	QLabel *dvbType;

	dvbConfig = dc;

	dvbPage[0]=dvbPage[1]=dvbPage[2]=dvbPage[3]=0;

	for ( i=0; i<(int)dvbConfig->devList.count(); i++ ) {
		dvbPage[i] = addPage( i18n("DVB Device")+" "+s.setNum( dvbConfig->devList.at(i)->adapter )+":"+s.setNum( dvbConfig->devList.at(i)->tuner ), i18n("Device Settings"),
			KGlobal::instance()->iconLoader()->loadIcon( "hwinfo", KIcon::NoGroup, KIcon::SizeMedium ) );
		vb = new QVBoxLayout( dvbPage[i], 6, 6 );
		gb = new QGroupBox( "", dvbPage[i] );
		grid = new QGridLayout( gb, 1, 1, 20, 6 );

		lab = new QLabel( i18n("<qt><b>Name:</b></qt>"), gb );
		grid->addWidget( lab, 0, 0 );
		ident = new QLabel( dvbConfig->devList.at(i)->name, gb );
		grid->addMultiCellWidget( ident, 0, 0, 1, 3 );

		lab = new QLabel( i18n("<qt><b>Type:</b></qt>"), gb );
		grid->addWidget( lab, 1, 0 );
		dvbType = new QLabel( gb );
		switch ( dvbConfig->devList.at(i)->type ) {
			case FE_QAM : dvbType->setText( i18n("DVB-C") ); break;
			case FE_OFDM : dvbType->setText( i18n("DVB-T") ); break;
			case FE_QPSK : dvbType->setText( i18n("DVB-S") ); break;
			default : dvbType->setText( i18n("Unknown") );
		}
		grid->addMultiCellWidget( dvbType, 1, 1, 1, 3 );

		if ( dvbConfig->devList.at(i)->type==FE_QPSK ) {
			lab = new QLabel( i18n("Number of LNBs:"), gb );
			grid->addWidget( lab, 2, 0 );
			satNumber[i] = new MSpinBox( gb, i );
			connect( satNumber[i], SIGNAL(signalValueChanged(int,int)), this, SLOT(satNumberChanged(int,int)));
			grid->addWidget( satNumber[i], 2, 1 );

			lab = new QLabel( i18n("1st sat:"), gb );
			grid->addWidget( lab, 3, 0 );
			sat0[i] = new QComboBox( gb );
			sat0[i]->setEnabled(true);
			sat0[i]->insertStringList( dvbConfig->getSourcesList(i) );
			setSource( sat0[i], dvbConfig->devList.at(i)->source, 0 );
			grid->addWidget( sat0[i], 3, 1 );
			lnb0[i] = new MPushButton( gb, i, 0 );
			lnb0[i]->setGuiItem( KGuiItem(i18n("LNB Settings..."), icon->loadIconSet("hwinfo", KIcon::Small) ) );
			lnb0[i]->setEnabled(true);
			grid->addWidget( lnb0[i], 3, 2 );
			connect( lnb0[i], SIGNAL(clicked(int,int)), this, SLOT(setLnb(int,int)));

			lab = new QLabel( i18n("2nd sat:"), gb );
			grid->addWidget( lab, 4, 0 );
			sat1[i] = new QComboBox( gb );
			sat1[i]->setEnabled(false);
			sat1[i]->insertStringList( dvbConfig->getSourcesList(i) );
			setSource( sat1[i], dvbConfig->devList.at(i)->source, 1 );
			grid->addWidget( sat1[i], 4, 1 );
			lnb1[i] = new MPushButton( gb, i, 1 );
			lnb1[i]->setGuiItem( KGuiItem(i18n("LNB Settings..."), icon->loadIconSet("hwinfo", KIcon::Small) ) );
			lnb1[i]->setEnabled(false);
			grid->addWidget( lnb1[i], 4, 2 );
			connect( lnb1[i], SIGNAL(clicked(int,int)), this, SLOT(setLnb(int,int)));

			lab = new QLabel( i18n("3rd sat:"), gb );
			grid->addWidget( lab, 5, 0 );
			sat2[i] = new QComboBox( gb );
			sat2[i]->setEnabled(false);
			sat2[i]->insertStringList( dvbConfig->getSourcesList(i) );
			setSource( sat2[i], dvbConfig->devList.at(i)->source, 2 );
			grid->addWidget( sat2[i], 5, 1 );
			lnb2[i] = new MPushButton( gb, i, 2 );
			lnb2[i]->setGuiItem( KGuiItem(i18n("LNB Settings..."), icon->loadIconSet("hwinfo", KIcon::Small) ) );
			lnb2[i]->setEnabled(false);
			grid->addWidget( lnb2[i], 5, 2 );
			connect( lnb2[i], SIGNAL(clicked(int,int)), this, SLOT(setLnb(int,int)));

			lab = new QLabel( i18n("4th sat:"), gb );
			grid->addWidget( lab, 6, 0 );
			sat3[i] = new QComboBox( gb );
			sat3[i]->setEnabled(false);
			sat3[i]->insertStringList( dvbConfig->getSourcesList(i) );
			setSource( sat3[i], dvbConfig->devList.at(i)->source, 3 );
			grid->addWidget( sat3[i], 6, 1 );
			lnb3[i] = new MPushButton( gb, i, 3 );
			lnb3[i]->setGuiItem( KGuiItem(i18n("LNB settings..."), icon->loadIconSet("hwinfo", KIcon::Small) ) );
			lnb3[i]->setEnabled(false);
			grid->addWidget( lnb3[i], 6, 2 );
			connect( lnb3[i], SIGNAL(clicked(int,int)), this, SLOT(setLnb(int,int)));

			satNumber[i]->setValue( dvbConfig->devList.at(i)->source.contains("|") );
		}
		else {
			lab = new QLabel( i18n("Source:"), gb );
			grid->addWidget( lab, 2, 0 );
			sat0[i] = new QComboBox( gb );
			sat0[i]->insertStringList( dvbConfig->getSourcesList(i) );
			setSource( sat0[i], dvbConfig->devList.at(i)->source, 0 );
			grid->addWidget( sat0[i], 2, 1 );
		}

		vb->addWidget( gb );
		vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) );
	}

	recordPage = addPage(i18n("Recording"),i18n("DVB Recording Options"),
		KGlobal::instance()->iconLoader()->loadIcon( "hdd_unmount", KIcon::NoGroup, KIcon::SizeMedium ) );
	vb = new QVBoxLayout( recordPage, 6, 6 );
	gb = new QGroupBox( "", recordPage );
	grid = new QGridLayout( gb, 1, 1, 20, 6 );

	lab = new QLabel( i18n("Records directory:"), gb );
	grid->addWidget( lab, 0, 0 );
	recordDirLe = new QLineEdit( gb );
	recordDirLe->setReadOnly( true );
	grid->addWidget( recordDirLe, 0, 1 );
	recordDirBtn = new QToolButton( gb );
	recordDirBtn->setIconSet( icon->loadIconSet("fileopen", KIcon::Small) );
	grid->addWidget( recordDirBtn, 0, 2 );

	lab = new QLabel( i18n("Time shifting directory:"), gb );
	grid->addWidget( lab, 1, 0 );
	shiftDirLe = new QLineEdit( gb );
	shiftDirLe->setReadOnly( true );
	grid->addWidget( shiftDirLe, 1, 1 );
	shiftDirBtn = new QToolButton( gb );
	shiftDirBtn->setIconSet( icon->loadIconSet("fileopen", KIcon::Small) );
	grid->addWidget( shiftDirBtn, 1, 2 );

	lab = new QLabel( i18n("Begin margin:"), gb );
	grid->addWidget( lab, 2, 0 );
	beginSpin = new QSpinBox( gb );
	h1 = new QHBoxLayout();
	h1->addWidget( beginSpin );
	lab = new QLabel( i18n("(minutes)"), gb );
	h1->addWidget( lab );
	grid->addLayout( h1, 2, 1 );

	lab = new QLabel( i18n("End margin:"), gb );
	grid->addWidget( lab, 3, 0 );
	endSpin = new QSpinBox( gb );
	h1 = new QHBoxLayout();
	h1->addWidget( endSpin );
	lab = new QLabel( i18n("(minutes)"), gb );
	h1->addWidget( lab );
	grid->addLayout( h1, 3, 1 );

	lab = new QLabel( i18n("Instant record duration:"), gb );
	grid->addWidget( lab, 4, 0 );
	instantDurationSpin = new QSpinBox( 1, 1440, 1, gb );
	h1 = new QHBoxLayout();
	h1->addWidget( instantDurationSpin );
	lab = new QLabel( i18n("(minutes)"), gb );
	h1->addWidget( lab );
	grid->addLayout( h1, 4, 1 );

	lab = new QLabel( i18n("Preferred format:"), gb );
	grid->addWidget( lab, 5, 0 );
	formatComb = new QComboBox( gb );
	grid->addWidget( formatComb, 5, 1 );

	vb->addWidget( gb );
	vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) );

	recordDirLe->setText( dvbConfig->recordDir );
	shiftDirLe->setText( dvbConfig->shiftDir );
	beginSpin->setValue( dvbConfig->beginMargin );
	endSpin->setValue( dvbConfig->endMargin );
	instantDurationSpin->setValue( dvbConfig->instantDuration );
	formatComb->insertItem( "TS" );
	formatComb->insertItem( "MPEG_PES" );
	formatComb->insertItem( "MPEG_PS" );
	switch ( dvbConfig->format ) {
		case OutTS : formatComb->setCurrentItem( 0 ); break;
		case OutPES : formatComb->setCurrentItem( 1 ); break;
		case OutPS : formatComb->setCurrentItem( 2 ); break;
	}

	broadcastPage = addPage(i18n("Broadcasting"),i18n("DVB Broadcasting"),
		KGlobal::instance()->iconLoader()->loadIcon( "network_local", KIcon::NoGroup, KIcon::SizeMedium ) );
	vb = new QVBoxLayout( broadcastPage, 6, 6 );
	gb = new QGroupBox( "", broadcastPage );
	grid = new QGridLayout( gb, 1, 1, 20, 6 );

	lab = new QLabel( i18n("Broadcast address:"), gb );
	grid->addWidget( lab, 0, 0 );
	broadcastLe = new QLineEdit( gb );
	grid->addWidget( broadcastLe, 0, 1 );
	lab = new QLabel( i18n("Broadcast port:"), gb );
	grid->addWidget( lab, 1, 0 );
	bportSpin = new QSpinBox( 1, 65535, 1, gb );
	grid->addWidget( bportSpin, 1, 1 );
	lab = new QLabel( i18n("Info port:"), gb );
	grid->addWidget( lab, 2, 0 );
	sportSpin = new QSpinBox( 1, 65535, 1, gb );
	grid->addWidget( sportSpin, 2, 1 );

	vb->addWidget( gb );
	vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) );

	broadcastLe->setText( dvbConfig->broadcastAddress );
	bportSpin->setValue( dvbConfig->broadcastPort );
	sportSpin->setValue( dvbConfig->senderPort );

	miscPage = addPage(i18n("Misc"),i18n("Misc"),
		KGlobal::instance()->iconLoader()->loadIcon( "misc", KIcon::NoGroup, KIcon::SizeMedium ) );
	vb = new QVBoxLayout( miscPage, 6, 6 );
	gb = new QGroupBox( "", miscPage );
	grid = new QGridLayout( gb, 1, 1, 20, 6 );

	lab = new QLabel( i18n("Default charset (restart needed):"), gb );
	grid->addWidget( lab, 0, 0 );
	charsetComb = new QComboBox( gb );
	charsetComb->insertItem( "ISO8859-1" );
	charsetComb->insertItem( "ISO6937" );
	if ( dvbConfig->defaultCharset=="ISO8859-1" )
		charsetComb->setCurrentItem( 0 );
	else if ( dvbConfig->defaultCharset=="ISO6937" )
		charsetComb->setCurrentItem( 1 );
	grid->addWidget( charsetComb, 0, 1 );

	lab = new QLabel( i18n("Update scan data:"), gb );
	grid->addWidget( lab, 1, 0 );
	updateBtn = new KPushButton( gb );
	updateBtn->setGuiItem( KGuiItem(i18n("Download"), icon->loadIconSet("khtml_kget", KIcon::Small) ) );
	grid->addWidget( updateBtn, 1, 1 );

	lab = new QLabel( i18n("Dump epg's events to \n~/kaffeine_dvb_events.tx:"), gb );
	grid->addWidget( lab, 2, 0 );
	dumpBtn = new KPushButton( gb );
	dumpBtn->setGuiItem( KGuiItem(i18n("Dump"), icon->loadIconSet("filesave", KIcon::Small) ) );
	grid->addWidget( dumpBtn, 2, 1 );

	vb->addWidget( gb );
	vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) );

	connect( recordDirBtn, SIGNAL(clicked()), this, SLOT(setRecordDir()) );
	connect( shiftDirBtn, SIGNAL(clicked()), this, SLOT(setShiftDir()) );
	connect( updateBtn, SIGNAL(clicked()), this, SLOT(downloadData()) );
	delete icon;
}



void DvbConfigDialog::setLnb( int devNum, int lnbNum )
{
	LNB *b;

	switch ( lnbNum ) {
		case 0 :
			b = &dvbConfig->devList.at(devNum)->lnb0;
			break;
		case 1 :
			b = &dvbConfig->devList.at(devNum)->lnb1;
			break;
		case 2 :
			b = &dvbConfig->devList.at(devNum)->lnb2;
			break;
		case 3 :
			b = &dvbConfig->devList.at(devNum)->lnb3;
			break;
		default :
			return;
	}

	LnbConfig lnb( b, this );
	lnb.exec();
}



void DvbConfigDialog::downloadData()
{
	int ret;

loop:
	if ( !dvbConfig->loadDvbData(0) ) {
		ret = KMessageBox::questionYesNo( this, i18n("<qt>Can't get DVB data from http://hftom.free.fr/kaxtv/dvbdata.tar.gz!<br>\
			Check your internet connection, and say Yes to try again.<br>\
			Or say No to cancel.<br> Should I try again?</qt>") );
		if ( ret==KMessageBox::Yes )
			goto loop;
		return;
	}
}



void DvbConfigDialog::setSource( QComboBox *box, QString s, int sat )
{
	QString c;
	int pos, i;

	for ( i=0; i<sat+1; i++ ) {
		pos = s.find("|");
		s = s.right( s.length()-pos-1 );
	}
	pos = s.find("|");
	c = s.left(pos);
	for ( i=0; i<(int)box->count(); i++ ) {
		if ( box->text(i)==c ) {
			box->setCurrentItem(i);
			break;
		}
	}
}



void DvbConfigDialog::satNumberChanged( int value, int devNum )
{
	sat0[devNum]->setEnabled( value > 0 );
	sat1[devNum]->setEnabled( value > 1 );
	sat2[devNum]->setEnabled( value > 2 );
	sat3[devNum]->setEnabled( value > 3 );

	lnb0[devNum]->setEnabled( value > 0 );
	lnb1[devNum]->setEnabled( value > 1 );
	lnb2[devNum]->setEnabled( value > 2 );
	lnb3[devNum]->setEnabled( value > 3 );
}



void DvbConfigDialog::setRecordDir()
{
	QString s = KFileDialog::getExistingDirectory( recordDirLe->text().stripWhiteSpace() );
	if ( !s.isEmpty() )
		recordDirLe->setText( s );
}



void DvbConfigDialog::setShiftDir()
{
	QString s = KFileDialog::getExistingDirectory( shiftDirLe->text().stripWhiteSpace() );
	if ( !s.isEmpty() )
		shiftDirLe->setText( s );
}



void DvbConfigDialog::accept()
{
	QString s;
	int i;

	if ( recordDirLe->text().stripWhiteSpace().isEmpty() ) {
		KMessageBox::sorry( this, i18n("Invalid records directory.") );
		recordDirLe->setFocus();
		return;
	}
	if ( shiftDirLe->text().stripWhiteSpace().isEmpty() ) {
		KMessageBox::sorry( this, i18n("Invalid time shifting directory.") );
		shiftDirLe->setFocus();
		return;
	}
	if ( bportSpin->value()==sportSpin->value() ) {
		KMessageBox::sorry( this, i18n("Broadcast and Info ports must be different.") );
		sportSpin->setFocus();
		return;
	}
	if ( !QRegExp("(\\d{1,3}\\.){3}\\d{1,3}").exactMatch( broadcastLe->text().stripWhiteSpace() ) ) {
		KMessageBox::sorry( this, i18n("Invalid broadcast address.") );
		broadcastLe->setFocus();
		return;
	}

	for ( i=0; i<(int)dvbConfig->devList.count(); i++ ) {
		if ( dvbConfig->devList.at(i)->type==FE_QPSK ) {
			s = "S";
			if ( sat0[i]->isEnabled() ) s+="|"+sat0[i]->currentText();
			if ( sat1[i]->isEnabled() ) s+="|"+sat1[i]->currentText();
			if ( sat2[i]->isEnabled() ) s+="|"+sat2[i]->currentText();
			if ( sat3[i]->isEnabled() ) s+="|"+sat3[i]->currentText();
		}
		else {
			if ( dvbConfig->devList.at(i)->type==FE_QAM )
				s = "C";
			else
				s = "T";
			s+="|"+sat0[i]->currentText();
		}
		dvbConfig->devList.at(i)->source = s;
	}

	dvbConfig->recordDir = recordDirLe->text();
	if ( !dvbConfig->recordDir.endsWith("/") )
		dvbConfig->recordDir+= "/";
	dvbConfig->shiftDir = shiftDirLe->text();
	if ( !dvbConfig->shiftDir.endsWith("/") )
		dvbConfig->shiftDir+= "/";
	dvbConfig->beginMargin = beginSpin->value();
	dvbConfig->endMargin = endSpin->value();
	dvbConfig->instantDuration = instantDurationSpin->value();
	switch ( formatComb->currentItem() ) {
		case 0 : dvbConfig->format = OutTS; break;
		case 1 : dvbConfig->format = OutPES; break;
		case 2 : dvbConfig->format = OutPS; break;
	}
	dvbConfig->defaultCharset = charsetComb->currentText();
	dvbConfig->broadcastAddress = broadcastLe->text().stripWhiteSpace();
	dvbConfig->broadcastPort = bportSpin->value();
	dvbConfig->senderPort = sportSpin->value();
	dvbConfig->saveConfig();
	done( Accepted );
}



DvbConfigDialog::~DvbConfigDialog()
{
}



LnbConfig::LnbConfig( LNB *b, QWidget *parent ) :
	KDialogBase ( parent, "lnbConfigDialog", true, i18n("LNB Settings"), Ok|Cancel, Ok, true )
{
	QGridLayout *grid;

	QWidget *page = new QWidget( this );
	setMainWidget( page );

	lnb = b;

	QVBoxLayout *vb = new QVBoxLayout( page, 6, 6 );
	univ = new QPushButton( i18n("Universal LNB"), page );
	connect( univ, SIGNAL(clicked()), this, SLOT(setUniversal()) );
	vb->addWidget( univ );

	grid = new QGridLayout( 0, 1, 1 );
	nLO = new QButtonGroup( 2, Qt::Horizontal, page );
	connect( nLO, SIGNAL(clicked(int)), this, SLOT(setDual(int)) );
	new QRadioButton( i18n("Dual LO"), nLO );
	new QRadioButton( i18n("Single LO"), nLO );
	grid->addMultiCellWidget( nLO, 0, 0, 0, 1 );
	slofLab = new QLabel( i18n("Dual LO switch frequency:")+i18n(" (MHz)"), page );
	grid->addWidget( slofLab, 1, 0 );
	slof = new QSpinBox( 0, 13000, 1, page );
	grid->addWidget( slof, 1, 1 );
	loLab = new QLabel( i18n("Lo-band frequency:")+i18n(" (MHz)"), page );
	grid->addWidget( loLab, 2, 0 );
	lo = new QSpinBox( 0, 13000, 1, page );
	grid->addWidget( lo, 2, 1 );
	hiLab = new QLabel( i18n("Hi-band frequency:")+i18n(" (MHz)"), page );
	grid->addWidget( hiLab, 3, 0 );
	hi = new QSpinBox( 0, 13000, 1, page );
	grid->addWidget( hi, 3, 1 );
	singleLab = new QLabel( i18n("Single LO frequency:")+i18n(" (MHz)"), page );
	grid->addWidget( singleLab, 4, 0 );
	single = new QSpinBox( 0, 13000, 1, page );
	grid->addWidget( single, 4, 1 );

	vb->addLayout( grid );
	vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) );


	slof->setValue( lnb->switchFreq );
	lo->setValue( lnb->loFreq );
	hi->setValue( lnb->hiFreq );
	single->setValue( lnb->loFreq );

	if ( lnb->switchFreq ) {
		nLO->setButton( 0 );
		setDual( 0 );
	}
	else {
		nLO->setButton( 1 );
		setDual( 1 );
	}
}



void LnbConfig::setDual( int id )
{
	if ( id==0 ) {
		singleLab->hide();
		single->hide();
		slofLab->show();
		slof->show();
		loLab->show();
		lo->show();
		hiLab->show();
		hi->show();
	}
	else {
		slofLab->hide();
		slof->hide();
		loLab->hide();
		lo->hide();
		hiLab->hide();
		hi->hide();
		singleLab->show();
		single->show();
	}
}



void LnbConfig::setUniversal()
{
	nLO->setButton( 0 );
	setDual( 0 );
	slof->setValue( 11700 );
	lo->setValue( 9750 );
	hi->setValue( 10600 );
	single->setValue( 9750 );
}



void LnbConfig::accept()
{
	if ( nLO->selectedId() ) {
		lnb->switchFreq = 0;
		lnb->hiFreq = 0;
		lnb->loFreq = single->value();
	}
	else {
		lnb->switchFreq = slof->value();
		lnb->loFreq = lo->value();
		lnb->hiFreq = hi->value();
	}
	done( Accepted );
}

#include "dvbconfig.moc"
