//
// C++ Implementation: kalvacmd
//
// Description: 
//
//
// Author: Andreas Silberstorff <andreas@andreas-silberstorff.de>, (C) 2005-2006
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "kalvacmd.h"

#include "settings.h"
#include <cmath>
#include <qdir.h>
#include <qstring.h>
#include <qregexp.h>
#include <kdebug.h>
#include <klocale.h>
#include <kstandarddirs.h>
#include <kmessagebox.h>
#include <kalvaprofile.h>

#include <kdeversion.h>
#undef KDE_3_3_FEATURES
#if defined(KDE_MAKE_VERSION)
#if KDE_VERSION >= KDE_MAKE_VERSION(3,3,0)
	#define KDE_3_3_FEATURES
#endif
#endif

KalvaCmd::KalvaCmd( QWidget * p )  {
	m_parent = p;
	m_hwprofile = new KalvaProfile( KALVA_HARDWARE_PROFILE );
	m_qprofile = new KalvaProfile( KALVA_QUALITY_PROFILE );
}

bool KalvaCmd::read()  {
	if ( ! ( m_hwprofile->read( Settings::hwprofile() ) ) )  {
		return false;
	}
	if ( ! ( m_qprofile->read( Settings::qprofile() ) ) )  {
		return false;
	}
	computeCropAndAspect();
	return true;
}

void KalvaCmd::playMovieCmd(const QString & movieFiles)
{
	if ( ! read() )  {
		return;
	}
	append(Settings::mplayer());
	QString targetedAspect =
		m_qprofile->getValueString("targetedAspect");

	if (! targetedAspect.isEmpty() )
	{
	       append(" -aspect ");
	       append(targetedAspect);
	}

	/* Fullscreen? */
	if ( Settings::fullscreen() )
	{
		append(" -fs");
	}

	/* verbosity level */
	int verbositylevel = Settings::verbosity_level();
	for (int i = 1; i <= verbositylevel; i++ )
	{
		append(" -v ");
	}
	append( movieFiles );
}

void KalvaCmd::playCmd( const QString & station,
			const QString & channel,
                        const QString & freq
	               )
{
	if ( ! read() )  {
		return;
	}
	QString driver = m_hwprofile->getValueString( "driver" );
	kdDebug() << "driver = " << driver << endl;

    ///@TODO this is a HACK, make it better!
	if ( driver.contains( "DVB" ) )  {
		playCmdDVB(station);
	} else if ( driver.contains( "IVTV" ) )  {
		playCmdIVTV(channel);

	}  else  {
		playCmdAnalog(channel, freq);
	}
}

void KalvaCmd::playCmdAnalog( const QString & channel,
                              const QString & freq
	                     )
{
	m_channel  = channel;
	m_freq     = freq;
	prepareAumix();
	setAumixPrePlay();
	append(Settings::mplayer());
	append(" -bpp 32");
	if ( Settings::fullscreen() )
	{
		append(" -fs");
	}
	setURLtv();
	QString inputOptions = QString::null;
	setInputOptsTV( inputOptions );
	setInputOptsPost( inputOptions );
	if (! inputOptions.isEmpty()) {
		append( " -tv " + inputOptions );

	}

	/************************************************
	*  F i l t e r s
	************************************************/
	QString filter = QString::null;
	setFilterRect( filter );
	setFilterPre( filter );
	setFilterPP( filter );
	setFilterScale( filter );
	setFilterAspect( filter );
	setFilterDenoiser( filter );
	setFilterPost( filter );
	if (! filter.isEmpty()) {
		append(" -vf " + filter );
	}
	append(" -vo xv ");
	setVerbosity();
	setAumixPostPlay();
	return;
}

void KalvaCmd::playCmdIVTV( const QString & channel )
{
	m_channel  = channel;
	prepareAumix();
	setAumixPrePlay();

	append(Settings::ivtvtune());
	append(" --device=" + Settings::videodev());
	append(" --freqtable=" + Settings::freq_table());
	append(" --channel=" + m_channel);
	append(" &&");

	append(Settings::mplayer());
	append(" ");
	append(Settings::videodev());

	append(" -bpp 32");
	if ( Settings::fullscreen() )
	{
		append(" -fs");
	}
//???	setURLivtv(); with ivtv-based cards we simply read from /dev/video, so there is no URL to set
// Are there any usefull input options for ivtv-based cards?
//	QString inputOptions = QString::null;
//	setInputOptsPost( inputOptions );
//	if (! inputOptions.isEmpty()) {
//		append( " -dvbin " + inputOptions );
//	}

	/************************************************
	*  F i l t e r s
	************************************************/
	QString filter = QString::null;
	setFilterRect( filter );
	setFilterPre( filter );
	setFilterPP( filter );
	setFilterScale( filter );
	setFilterAspect( filter );
	setFilterDenoiser( filter );
	setFilterPost( filter );
	if (! filter.isEmpty()) {
		append(" -vf " + filter );
	}
	//append(" -vo xv ");
	setVerbosity();
	setAumixPostPlay();
	return;
}

void KalvaCmd::playCmdDVB( const QString & station )
{
	m_station  = station;
	prepareAumix();
	setAumixPrePlay();
	append(Settings::mplayer());
	append(" -bpp 32");
	if ( Settings::fullscreen() )
	{
		append(" -fs");
	}
	setURLdvb();
	QString inputOptions = QString::null;
	setInputOptsPost( inputOptions );
	if (! inputOptions.isEmpty()) {
		append( " -dvbin " + inputOptions );
	}

	/************************************************
	*  F i l t e r s
	************************************************/
	QString filter = QString::null;
	setFilterRect( filter );
	setFilterPre( filter );
	setFilterPP( filter );
	setFilterScale( filter );
	setFilterAspect( filter );
	setFilterDenoiser( filter );
	setFilterPost( filter );
	if (! filter.isEmpty()) {
		append(" -vf " + filter );
	}
	//append(" -vo xv ");
	setVerbosity();
	setAumixPostPlay();
	return;
}

void KalvaCmd::recordCmd(           const QString & filmtitle,
                                    const QString & station,
                                    const QString & duration,
                                    const QString & channel,
                                    const QString & freq
                         )
{
	if ( ! read() )  {
		return;
	}
	QString driver = m_hwprofile->getValueString( "driver" );
	kdDebug() << "driver = " << driver << endl;

	if ( driver.contains( "DVB" ) )  {
		if ( Settings::convert_mpg2_to_divx() ) {
			recordCmdDVBAsDivX4(filmtitle, station, duration);
		} else {
			recordCmdDVB(filmtitle, station, duration);
		}
	} else if ( driver.contains( "IVTV" ) )  {
		recordCmdIVTV(filmtitle, station, channel, duration);

	}  else  {
		recordCmdAnalogue(filmtitle, station, duration, channel, freq);
	}
}

void KalvaCmd::recordCmdAnalogue(const QString & filmtitle,
                                    const QString & station,
                                    const QString & duration,
                                    const QString & channel,
                                    const QString & freq
                         )
{
	if ( ! read() )  {
		return;
	}
	m_channel  = channel;
	m_freq     = freq;
	m_duration = QTime::fromString( duration );

	prepareAumix();
	setAumixPreRec();
	setNice();
	append(Settings::mencoder());
	// URL
	setURLtv();
	QString inputOptions = QString::null;
	setInputOptsTV( inputOptions );
	if ( isEmpty() )
		return;
	setInputOptsPost( inputOptions );
	if (! inputOptions.isEmpty()) {
		append( " -tv " + inputOptions );
	}

	/************************************************
	* lavc options
	************************************************/
	append(" -ovc lavc");
	QString lavcOpts = QString::null;
	setLavcOpts( lavcOpts );
	if ( isEmpty() )
		return;
	setEncoderOptsPost( lavcOpts );
	if (! lavcOpts.isEmpty()) {
		append(" -lavcopts " + lavcOpts );
	}

	/************************************************
	* mp3 audio options
	************************************************/
	append(" -oac mp3lame -lameopts ");
	append("abr:br=128:mode=0");

	/************************************************
	****  F i l t e r s
	************************************************/
	QString filter = QString::null;
	setFilterCrop( filter );
	setFilterPre( filter );
	setFilterPP( filter );
	setFilterScale( filter );
	setFilterDenoiser( filter );
	setFilterPost( filter );
	if (! filter.isEmpty()) {
		append(" -vf " + filter );
	}

	/************************************************
	* other options
	************************************************/

	/* Mencoder >= 1.0pre7 uses it's own fourcc (FMP4) which makes
	it incompatible with many dvd/divx players. Restore the old
	behaviour by setting it to "DIVX". */
	append(" -ffourcc DIVX");
	append(" -endpos " + duration );

	setTitle( filmtitle, station );
	setVerbosity();

	/************************************************
	* optional use of aumix
	************************************************/
	setAumixPostRec();

	return;
}

void KalvaCmd::recordCmdDVBAsDivX4( const QString & filmtitle,
                                    const QString & station,
                                    const QString & duration
                                   )
{
	if ( ! read() )  {
		return;
	}

	m_station  = station;
	m_duration = QTime::fromString( duration );

	prepareAumix();
	setAumixPreRec();

	setNice();

	append(Settings::mencoder());
	setURLdvb();
	QString inputOptions = QString::null;
	setInputOptsPost( inputOptions );
	if (! inputOptions.isEmpty()) {
		append( " -dvbin " + inputOptions );
	}
	append(" -ovc lavc");
	QString lavcOpts = QString::null;
	setLavcOpts( lavcOpts );
	if ( isEmpty() )
		return;
	if (! lavcOpts.isEmpty()) {
		append(" -lavcopts " + lavcOpts );
	}

	/************************************************
	* free editable en/decoder options
	************************************************/
	QString postlavcopts = m_qprofile->getValueString( "postlavcopts" );
//   QString postlavcopts = Settings::postlavcopts();
	if ( ! postlavcopts.isEmpty() ) {
		append(":");
		append(postlavcopts);
	}

	/************************************************
	* mp3 audio options
	************************************************/
	append(" -oac mp3lame -lameopts ");
	append("abr:br=128:mode=0");

	/************************************************
	*  F i l t e r s
	************************************************/

	QString filter = QString::null;
	setFilterCrop( filter );
	setFilterPre( filter );
	setFilterPP( filter );
	setFilterScale( filter );
	setFilterDenoiser( filter );
	setFilterPost( filter );
	if (! filter.isEmpty()) {
		append(" -vf " + filter );
	}

	/************************************************
	*
	************************************************/

	/* Mencoder >= 1.0pre7 uses it's own fourcc (FMP4) which makes
	it incompatible with many dvd/divx players. Restore the old
	behaviour by setting it to "DIVX". */
	append(" -ffourcc DIVX");

	append( " -endpos " + duration );
	setTitle( filmtitle, station );
	setVerbosity();
	setAumixPostRec();
	return;
}

void KalvaCmd::recordCmdIVTV(       const QString & filmtitle,
                                    const QString & station,
                                    const QString & channel,
                                    const QString & duration
                            )
{
	if ( ! read() )  {
		return;
	}
	m_channel  = channel;
	m_duration = QTime::fromString( duration );

	prepareAumix();
	setAumixPreRec();

	setNice();

	append(Settings::ivtvtune());
	append(" --device=" + Settings::videodev());
	append(" --freqtable=" + Settings::freq_table());
	append(" --channel=" + m_channel);
	append(" &&");

	append(Settings::mencoder());

	append(" ");
	append(Settings::videodev());
	append(" ");

	append(" -ovc copy");
	append(" -oac copy ");
	QString filter = QString::null;
	setFilterCrop( filter );
	setFilterPre( filter );
	setFilterScale( filter );
	setFilterPost( filter );
	if (! filter.isEmpty()) {
		append(" -vf " + filter );
	}
	append( " -endpos " + duration );
	append( " -of mpeg" );
	setTitle( filmtitle, station );
	setVerbosity();
	setAumixPostRec();
	return;
}

void KalvaCmd::recordCmdDVB(        const QString & filmtitle,
                                    const QString & station,
                                    const QString & duration
                            )
{
	if ( ! read() )  {
		return;
	}
	m_station  = station;
	m_duration = QTime::fromString( duration );

	prepareAumix();
	setAumixPreRec();

	setNice();

	append(Settings::mencoder());
	//URL
	setURLdvb();
	QString inputOptions = QString::null;
	setInputOptsPost( inputOptions );
	if (! inputOptions.isEmpty()) {
		append( " -dvbin " + inputOptions );
	}
	append(" -ovc copy");
	append(" -oac copy ");
	QString filter = QString::null;
	setFilterCrop( filter );
	setFilterPre( filter );
	setFilterScale( filter );
	setFilterPost( filter );
	if (! filter.isEmpty()) {
		append(" -vf " + filter );
	}
	append( " -endpos " + duration );
	append( " -of mpeg" );
	setTitle( filmtitle, station );
	setVerbosity();
	setAumixPostRec();
	return;
}

/************************************************
 ****  Input options for analogue TV cards
 ************************************************/

void KalvaCmd::setInputOptsTV( QString & Opts )
{
	QString driver   = m_hwprofile->getValueString( "driver" );
	QString norm     = m_hwprofile->getValueString( "norm" );
	QString videodev = m_hwprofile->getValueString( "videodev" );
	QString input    = m_hwprofile->getValueString( "input" );
	Opts.append( QString("driver=%1:norm=%2:device=%3:input=%4")
                  .arg( driver )
                  .arg( norm )
                  .arg( videodev )
                  .arg( input )
		);
    // these are rather hardwareoptions as they are used
    // for cards with ugly defaults
	int brightness    = m_hwprofile->getValueInt( "brightness" );
	if ( brightness != 0 ) {
		Opts.append(QString(":brightness=%1").arg(brightness));
	}
	int hue    = m_hwprofile->getValueInt( "hue" );
	if ( hue  != 0 ) {
		Opts.append(QString(":hue=%1").arg(hue));
	}
	int saturation = m_hwprofile->getValueInt( "saturation" );
	if ( saturation != 0 )  {
		Opts.append(QString(":saturation=%1").arg(saturation));
	}
	int contrast = m_hwprofile->getValueInt( "contrast" );
	if ( contrast != 0 ) {
		Opts.append(QString(":contrast=%1").arg(contrast));
	}
	Opts.append(":quality=0");

	QString tv_scale = getTvScale();
	Opts.append( tv_scale );

	QString tuner = getTuner();
	if ( isEmpty() )
		return;
	Opts.append( tuner );
	return;
}

QString KalvaCmd::getTvScale()  {
	QString tv_scale = m_qprofile->getValueString( "tvscale" );
	x_scale          = tv_scale.section( ":", 0, 0 );
	y_scale          = tv_scale.section( ":", 1, 1 );
	y_scale          = y_scale.section( " ", 0, 0 );
	return QString(":width=%1:height=%2" )
		.arg( x_scale )
		.arg( + y_scale);
}

void KalvaCmd::setInputOptsPost( QString & Opts)
{
	/************************************************
	* free editable en/decoder options
	************************************************/
	QString postcodingpars = m_qprofile->getValueString( "postcodingpars" );
//    QString postcodingpars = Settings::postcodingpars();
	if ( ! postcodingpars.isEmpty() ) {
		if ( ! Opts.isEmpty() )
			Opts.append(":");
		Opts.append(postcodingpars);
	}
	return;
}


/************************************************
 ****  A u m i x
 ************************************************/

void KalvaCmd::prepareAumix()
{
	/************************************************
	**** optional use of aumix
	************************************************/
	aumix     = Settings::aumix();
	kdDebug() << "in prepareAumix" << endl;
	QString audiodev = m_hwprofile->getValueString( "audiodev" );
	kdDebug() << "audiodev = " << audiodev << endl;
	aumixdev  = getAumixdev( audiodev );
	kdDebug() << "aumixdev = " << aumixdev << endl;
	return;
}

QString KalvaCmd::getAumixdev ( const QString& audiodev )
{
   QString myAudiodev = audiodev.stripWhiteSpace();
   kdDebug() << "in getAumixdev, audiodev = " << audiodev << endl;
   kdDebug() << "stripped audiodev = " << myAudiodev << endl;

   if    ( audiodev.contains( QRegExp("^\\[.*\\]$") ) ) 
      return QString::null;
   else if ( myAudiodev.compare("vol") == 0 )
       return QString("v");
   else if ( myAudiodev.compare("bass") == 0 )
       return QString("b");
   else if ( myAudiodev.compare("cd") == 0 )
       return QString("c");
   else if ( myAudiodev.compare("igain") == 0 )
       return QString("i");
   else if ( myAudiodev.compare("mic") == 0 )
       return QString("m");
   else if ( myAudiodev.compare("lineout") == 0 )
       return QString("o");
   else if ( myAudiodev.compare("speaker") == 0 )
       return QString("p");
   else if ( myAudiodev.compare("synthesizer") == 0 )
       return QString("s");
   else if ( myAudiodev.compare("treble") == 0 )
       return QString("t");
   else if ( myAudiodev.compare("pcm") == 0 )
       return QString("w");
   else if ( myAudiodev.compare("imix") == 0 )
       return QString("x");
   else if ( myAudiodev.compare("line") == 0 )
       return QString("l");
   else if ( myAudiodev.contains( QRegExp("line\\d") ) )  {
       return QString( myAudiodev.remove("line") );
   }
   else  {
      kdWarning() << i18n("device not known to aumix") << endl;
       return QString( QString::null );
   }
}

void KalvaCmd::setAumixPrePlay()
{
	/************************************************
	**** optional use of aumix
	************************************************/
	kdDebug() << "in setAumixPrePlay()" << endl;
	if ( !( aumixdev.isEmpty() ) ) {
		kdDebug() << "aumixdev is not empty" << endl;

		QString audiodev_volume = m_hwprofile->getValueString( "audiodev_volume" );
		append(QString("%1 -%2 %3 && ")
			.arg(aumix)
			.arg( aumixdev )
			.arg( audiodev_volume ) );
	}
	return;
}

void KalvaCmd::setAumixPostPlay()
{
	/************************************************
	**** optional use of aumix
	************************************************/
	if ( !( aumixdev.isEmpty() ) ) {
	append(QString(" && %1 -%2 0 ")
			.arg(aumix)
			.arg( aumixdev ) );
	}
	return;
}

void KalvaCmd::setAumixPreRec()
{
	/************************************************
	**** optional use of aumix
	************************************************/
	if ( !( aumixdev.isEmpty() ) ) {
		int igain_volume = m_hwprofile->getValueInt( "igain_volume" );
		append(QString("%1 -%2 0 -%3 R -i %4 && ")
			.arg( aumix )
			.arg( aumixdev )
			.arg( aumixdev )
			.arg( igain_volume ) );
	}
	return;
}

void KalvaCmd::setAumixPostRec()
{
	/************************************************
	**** optional use of aumix
	************************************************/
	if ( !( aumixdev.isEmpty() ) ) {
		int audiodev_volume = m_hwprofile->getValueInt( "audiodev_volume" );
		append(QString(" && %1 -%2 %3 -%4 P -i 0 ")
			.arg( aumix )
			.arg( aumixdev )
			.arg( audiodev_volume )
			.arg( aumixdev ) );
	}
	return;
}

/************************************************
 ****  
 ************************************************/

void KalvaCmd::setURLtv()
{
	append( QString(" tv:// ") );
}

void KalvaCmd::setURLdvb()
{
	append( QString( " \"dvb://%1\" " ).arg( m_station ) );
}

/************************************************
 ****  Lavc Options
 ************************************************/

void KalvaCmd::setLavcOpts( QString & Opts )
{
	/************************************************
	* 
	************************************************/
	Opts.append("vcodec=mpeg4");

	setBitrate( Opts );
	if ( isEmpty() )
		return;

	int vratetol = m_qprofile->getValueInt( "vratetol" );
//    int vratetol = Settings::vratetol();
	if ( vratetol > 0 ) {
		Opts.append(QString(":vratetol=%1").arg(vratetol));
	}

	int mbd = m_qprofile->getValueInt( "mbd" );
//    int mbd = Settings::mbd();
	if ( mbd > 0 ) {
		Opts.append(QString(":mbd=%1").arg(mbd));
	}

	int precmp = m_qprofile->getValueInt( "precmp" );
//    int precmp = Settings::precmp();
	if ( precmp > 0 ) {
	Opts.append(QString(":precmp=%1").arg(precmp));
	}

	int cmp = m_qprofile->getValueInt( "cmp" );
//    int cmp = Settings::cmp();
	if ( cmp > 0 ) {
		Opts.append(QString(":cmp=%1").arg(cmp));
	}

	int subcmp = m_qprofile->getValueInt( "subcmp" );
//    int subcmp = Settings::subcmp();
	if ( subcmp > 0 ) {
		Opts.append(QString(":subcmp=%1").arg(subcmp));
	}

	QString aspect = m_qprofile->getValueString( "aspect" );
//    QString aspect = Settings::aspect();
	if (! aspect.isEmpty()) {
		Opts.append(QString(":aspect=%1").arg(aspect));
	}

	bool useKeyint = m_qprofile->getValueBoolean( "use_keyint" );
//    if ( Settings::use_keyint() == true )  {
	if ( useKeyint )  {
		Opts.append(":keyints=true" );
	}

	bool grey = m_qprofile->getValueBoolean( "grey" );
//   if (Settings::grey() == true)  {
	if ( grey )  {
		Opts.append(":gray");
	}
	return;
}

void KalvaCmd::setBitrate( QString & lavcOpts )
{
	double bitrate  = Bitrate();
	if ( bitrate < 0 )  {
		truncate (0);
		return;
	}
	else if ( bitrate == 0 )  {
		return;
	}
	else {
		lavcOpts.append(QString(":vbitrate=%1").arg(bitrate));
		return;
	}
}

double KalvaCmd::Bitrate()
{
	double bitrate = m_qprofile->getValueDouble( "bitrate" );
	double maxBitrate = m_qprofile->getValueDouble( "maxBitrate" );
//   double bitrate        = Settings::bitrate();
//   double maxBitrate     = Settings::maxBitrate();

	// compute duration in seconds
	int hours   = m_duration.hour();
	int minutes = m_duration.minute();
	int seconds = m_duration.second();
	minutes += (hours * 60);
	if ((minutes > 0) and (seconds > 0))
	minutes -= 1;
	seconds += ( minutes * 60 );

	// test duration
	if ( seconds <= 0 )  {
		KMessageBox::error (
			m_parent,
			i18n ("Duration is not set") ,
			i18n ("Command not build") );
		return -1;
	}

	// if the hardware profile defines a maximum bitrate
	// the bitrate from the quality profile must not be
	// greater
	if ( maxBitrate && ( maxBitrate < bitrate ) )
		bitrate = maxBitrate;

	// Only test resulting filesize when the user wants this
	bool testBitrate = m_qprofile->getValueBoolean( "testBitrate" );
//   if ( ! Settings::testBitrate() )
	if ( ! testBitrate )
		return bitrate;

	// compute the maximum bitrate that is allowed if the
	// filesize should stay under 2GB
	double reducedBitrate = std::floor((( 1995 - 0.9375 * minutes) *
					8192/( seconds )));

	// test if bitrate is exceeding the computed bitrate
	if ( reducedBitrate < bitrate )  {
		int ret = KMessageBox::Continue;
	bool bitrateWarnOnly = m_qprofile->getValueBoolean( "bitrateWarnOnly" );
//   if ( Settings::bitrateWarnOnly() )  {
	if ( bitrateWarnOnly )  {
		ret = KMessageBox::warningContinueCancel (
			m_parent,
			i18n("<qt>Using the bitrate <b>%1</b> would result in a <i>filesize &gt;= 2GB</i>. Shall I <i>reduce</i> the bitrate to <b>%2</b> to keep the filesize &lt; 2GB ?</qt>")
				.arg(bitrate)
				.arg(reducedBitrate), 
			i18n("Reduce bitrate?") );
	}
	if ( ret == KMessageBox::Continue )
		bitrate = reducedBitrate;
	}
	return bitrate;
}

void KalvaCmd::setEncoderOptsPost( QString & Opts)
{
	/************************************************
	* free editable en/decoder options
	************************************************/
	QString postlavcopts = m_qprofile->getValueString( "postlavcopts" );
//    QString postlavcopts = Settings::postlavcopts();
	if ( ! postlavcopts.isEmpty() ) {
		if ( ! Opts.isEmpty() )
			Opts.append( ":" );
			Opts.append( postlavcopts );
	}
	return;
}

/************************************************
 ****  F i l t e r s
 ************************************************/

void KalvaCmd::setFilterRect( QString & filter)
{
	/************************************************
	* crop
	************************************************/
	if (Settings::croppreview()) {
		QString crop = getCrop();
		if (! crop.isEmpty()) {
			if (! filter.isEmpty()) {
				filter.append(",");
			}
			filter.append("rectangle=" + crop );
		}
	}
	return;
}

void KalvaCmd::setFilterCrop( QString & filter)
{
	/************************************************
	* crop
	************************************************/
	QString crop = getCrop();
	if (! crop.isEmpty()) {
		if (! filter.isEmpty()) {
			filter.append(",");
		}
		filter.append("crop=" + crop );
	}
	return;
}

void KalvaCmd::setFilterPre( QString & filter)
{
	/************************************************
	* free editable filter options
	************************************************/
	QString prefilter   = m_qprofile->getValueString( "prefilter" );
//    QString prefilter = Settings::prefilter();
	if ( ! prefilter.isEmpty() ) {
		if (! filter.isEmpty()) {
			filter.append(",");
		}
		filter.append(prefilter);
	}
	return;
}

void KalvaCmd::setFilterPP( QString & filter)
{
	/************************************************
	* deinterlace, free editable pp options
	************************************************/
	QString pp = m_qprofile->getValueString( "pp" );
//    QString pp = Settings::pp();
	if ( ! pp.isEmpty() ) {
		if (! filter.isEmpty()) {
			filter.append(",");
		}
		filter.append( QString( "pp=%1" ).arg( pp ) );
	}
	return;
}

void KalvaCmd::setFilterScale( QString & filter)
{
	/************************************************
	* scale
	************************************************/
	QString filterScale   = m_qprofile->getValueString( "filterScale" );
//    QString filterScale = Settings::filter_scale();
	if ( (! (filterScale.isEmpty() ) )  and 
	     (filterScale != QString::null ) and
	     (filterScale.contains( "\[" ) <= 0 ) )  {
		filterScale    = filterScale.section( " ", 0, 0 );
		if (! filter.isEmpty()) {
			filter.append(",");
		}
		filter.append("scale=" + filterScale);
	}
	return;
}

void KalvaCmd::setFilterAspect( QString & filter )
{
   /************************************************
    * aspect ratio
    ************************************************/
///	double aspect   = getAspect();
    ///???QString aspect = Settings::aspect();
    ///if ( ! aspect.isEmpty() ) {
	if (! filter.isEmpty()) {
		filter.append(",");
	}
	filter.append("dsize=4/3");
    ///}
    return;
}

void KalvaCmd::setFilterDenoiser( QString & filter)
{
   /************************************************
    * denoiser
    ************************************************/
	QString denoiser   = m_qprofile->getValueString( "denoiser" );
//     QString denoiser = Settings::denoiser();
	if ( (! denoiser.isEmpty() )      and
	     ( denoiser != QString::null ) and
	     ( denoiser.contains( "\[" ) <= 0 ) )  {
		if (! filter.isEmpty() )
			filter.append(",");
		QString chroma = m_qprofile->getValueString( "chroma" );
		QString luma   = m_qprofile->getValueString( "luma" );
		QString time   = m_qprofile->getValueString( "time" );
		filter.append( denoiser + "=" );
		filter.append( QString("%1:%2:%3")
				.arg( chroma )
				.arg( luma )
				.arg( time )
			);
	}
	return;
}

void KalvaCmd::setFilterPost( QString & filter)
{
	/************************************************
	* free editable filter options
	************************************************/
	QString postfilter = m_qprofile->getValueString( "postfilter" );
//    QString postfilter = Settings::postfilter();
	if ( ! postfilter.isEmpty() ) {
		if (! filter.isEmpty() ) {
			filter.append( "," );
		}
		filter.append( postfilter );
	}
	return;
}

void KalvaCmd::setNice()
{
	/************************************************
	* optional use of nice
	************************************************/
	int niceValue = m_qprofile->getValueInt( "nice_value" );
//    int nice_value    = Settings::nice_value();
	if (niceValue > 0)  {
		append(QString("%1 %2 -%3 ")
			.arg( Settings::sudo() )
			.arg( Settings::nice() )
			.arg( niceValue ) );
	}
	return;
}

void KalvaCmd::setVerbosity()
{
	/************************************************
	* verbosity level
	************************************************/
	int verbositylevel = m_qprofile->getValueInt( "verbositylevel" );
//    int verbositylevel = Settings::verbosity_level();
	for (int i = 1; i <= verbositylevel; i++ )
	{
		append(" -v ");
	}
	return;
}

void KalvaCmd::setTitle( const QString & filmtitle,
			 const QString & station
			)
{
	QString path      = Settings::storage_path();
	QString myFilmtitle = filmtitle;

	if ( myFilmtitle.isEmpty() )
		myFilmtitle = i18n( "untitled" );

	path.append( QString("/%1").arg( myFilmtitle ) );

	QDir d( path );

	if ( !d.exists() )
	{
		d.mkdir( path );
	}

	QString film = QString("\"%1/%2_`%3 +%a_%d.%b.%G_%H%M%S`")
				.arg( path )
				.arg( station )
				.arg( Settings::date()
				);

	QString driver = m_hwprofile->getValueString( "driver" );

	if ( driver.contains( "DVB" ) )  {
		if ( Settings::convert_mpg2_to_divx() )  {
			film.append( ".avi\"" );
		} else {
			film.append( ".mpg\"" );
		}
	} else if ( driver.contains( "IVTV" ) )  {
		film.append( ".mpg\"" );
	} else {
		film.append( ".avi\"" );
	}
	append( " -o " + film );
	return;
}

QString KalvaCmd::getTuner()
{
	QString tuner = "";
	if ( m_hwprofile->getValueInt( "input" ) > 0 )  {
		kdDebug() << "not a tuner card, tuner will not be set " << endl;
		return tuner;
	}

	bool usefrq = m_hwprofile->getValueBoolean( "usefrq" );
//    if ( Settings::use_frq() )  {
	if ( usefrq )  {
		if ( m_freq.isEmpty() )  {
			KMessageBox::error (
				m_parent,
				i18n ("Frequency is not set") ,
				i18n ("Command not build") );
			truncate (0);
		}  else  {
			tuner.append(":freq=" + m_freq );
		}
	}  else  {
		if ( m_channel.isEmpty() )  {
			KMessageBox::error (
				m_parent,
				i18n ("Channel is not set") ,
				i18n ("Command not build") );
			truncate (0);
		}  else  {
			tuner.append(":channel=" + m_channel );
		}
	}
	return tuner;
}

/*************************************************************************
 * crop and aspect computation
 * (Allghorhythm by Matthias Wieser)
 *************************************************************************/
void KalvaCmd::computeCropAndAspect()
{
	kdDebug() << i18n( "computing crop values" ) << endl;
	float  overscan        = m_hwprofile->getValueFloat( "factor" );
	QString res            = m_qprofile->getValueString( "tvscale" );
	QString targetedAspect = m_qprofile->getValueString( "targetedAspect" );

	KalvaCropAndAspect* computer = new KalvaCropAndAspect(
			overscan, res, targetedAspect
		);
	computer->compute();
	aspect = computer->getAspect();
	crop = computer->getCrop();
	return;

	//kdDebug() << "tvscale  = " << res << endl;
	QString   resw   = res.section( ":", 0, 0 );
	QString   resh   = res.section( ":", 1, 1 );
	resh             = resh.section(" ", 0, 0 );
	//kdDebug() << "resw  = " << resw << endl;
	//kdDebug() << "resh  = " << resh << endl;

	int       realw  = resw.toInt();
	double    realh  = resh.toInt();
	//kdDebug() << "realw  = " << realw << endl;
	//kdDebug() << "realh  = " << realh << endl;

	double aspect_pal_4_3  = 1.333333;
	double aspect_pal_16_9 = 1.777778;
	float  exactw;
	float  exacth;

	double aspect_pal = 0;
	if ( targetedAspect.contains( "4/3" ) )  {
		aspect_pal  = aspect_pal_4_3;
		exactw      = realw - (2 * realw * overscan);
		exacth      = realh - (2 * realh * overscan);
	}  else  {
		aspect_pal  = aspect_pal_16_9;
		exactw      = realw - (2 * realw * overscan);
		float comph = realh * ( aspect_pal_4_3 / aspect_pal_16_9 );
		exacth      = comph - (2 * comph * overscan);
	}
	kdDebug() << "aspect_pal  = " << aspect_pal<< endl;
	kdDebug() << "exactw  = " << exactw << endl;
	kdDebug() << "exacth  = " << exacth << endl;

	double modw16    = std::fmod(exactw, 16);
	kdDebug() << "modw16  = " << modw16 << endl;
	double cropw     = exactw - modw16;
	if ( modw16 > 8 )
		cropw += 16;
	kdDebug() << "cropw  = " << cropw << endl;
	double modh16    = std::fmod(exacth, 16);
	kdDebug() << "modh16  = " << modh16 << endl;
	double croph     = exacth - modh16;
	if ( modh16 > 8 )
		croph += 16;
	kdDebug() << "croph  = " << croph << endl;
	double overscanw = (realw - cropw) / 2;
	double overscanh = (realh - croph) / 2;
	kdDebug() << "overscanw  = " << overscanw << endl;
	kdDebug() << "overscanh  = " << overscanh << endl;
	crop   = QString("%1:%2:%3:%4")
			.arg(cropw).arg(croph)
			.arg(overscanw).arg(overscanh);
	double aspect_capture = exactw / exacth;
	kdDebug() << "aspect_capture  = " << aspect_capture << endl;
	double aspect_crop = cropw / croph;
	kdDebug() << "aspect_crop  = " << aspect_crop<< endl;
	aspect = aspect_pal * aspect_crop / aspect_capture;
	kdDebug() << "aspect  = " << aspect<< endl;
}

void KalvaCropAndAspect::compute()  {
	kdDebug() << i18n( "computing crop values" ) << endl;

	//kdDebug() << "tvscale  = " << m_res << endl;
	QString   resw   = m_res.section( ":", 0, 0 );
	QString   resh   = m_res.section( ":", 1, 1 );
	resh             = resh.section(" ", 0, 0 );
	//kdDebug() << "resw  = " << resw << endl;
	//kdDebug() << "resh  = " << resh << endl;

	int       realw  = resw.toInt();
	double    realh  = resh.toInt();
	//kdDebug() << "realw  = " << realw << endl;
	//kdDebug() << "realh  = " << realh << endl;

	double aspect_pal_4_3  = 1.333333;
	double aspect_pal_16_9 = 1.777778;
	float  exactw;
	float  exacth;

	double aspect_pal = 0;
	if ( m_targetedAspect.contains( "4/3" ) )  {
		aspect_pal  = aspect_pal_4_3;
		exactw      = realw - (2 * realw * m_overscan);
		exacth      = realh - (2 * realh * m_overscan);
	}  else  {
		aspect_pal  = aspect_pal_16_9;
		exactw      = realw - (2 * realw * m_overscan);
		float comph = realh * ( aspect_pal_4_3 / aspect_pal_16_9 );
		exacth      = comph - (2 * comph * m_overscan);
	}
	kdDebug() << "aspect_pal  = " << aspect_pal<< endl;
	kdDebug() << "exactw  = " << exactw << endl;
	kdDebug() << "exacth  = " << exacth << endl;

	double modw16    = std::fmod(exactw, 16);
	kdDebug() << "modw16  = " << modw16 << endl;
	double cropw     = exactw - modw16;
	if ( modw16 > 8 )
		cropw += 16;
	kdDebug() << "cropw  = " << cropw << endl;
	double modh16    = std::fmod(exacth, 16);
	kdDebug() << "modh16  = " << modh16 << endl;
	double croph     = exacth - modh16;
	if ( modh16 > 8 )
		croph += 16;
	kdDebug() << "croph  = " << croph << endl;
	double overscanw = (realw - cropw) / 2;
	double overscanh = (realh - croph) / 2;
	kdDebug() << "overscanw  = " << overscanw << endl;
	kdDebug() << "overscanh  = " << overscanh << endl;
	m_crop   = QString("%1:%2:%3:%4")
			.arg(cropw).arg(croph)
			.arg(overscanw).arg(overscanh);
	double aspect_capture = exactw / exacth;
	kdDebug() << "aspect_capture  = " << aspect_capture << endl;
	double aspect_crop = cropw / croph;
	kdDebug() << "aspect_crop  = " << aspect_crop<< endl;
	m_aspect = aspect_pal * aspect_crop / aspect_capture;
	kdDebug() << "aspect  = " << m_aspect<< endl;
}
