/***************************************************************************
 *   Copyright (C) 2005-2006 by Andreas Silberstorff   *
 *   ml@andreas-silberstorff.de   *
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.             *
 *                                                                         *
 *   In addition, as a special exception, the copyright holders give       *
 *   permission to link the code of this program with any edition of       *
 *   the Qt library by Trolltech AS, Norway (or with modified versions     *
 *   of Qt that use the same license as Qt), and distribute linked         *
 *   combinations including the two.  You must obey the GNU General        *
 *   Public License in all respects for all of the code used other than    *
 *   Qt.  If you modify this file, you may extend this exception to        *
 *   your version of the file, but you are not obligated to do so.  If     *
 *   you do not wish to do so, delete this exception statement from        *
 *   your version.                                                         *
 ***************************************************************************/

#include "kalva_recorder.h"
#include "kalvacmd.h"
#include "settings.h"
#include "prefs.h"

#include <cmath>

#include <qcheckbox.h>
#include <qdir.h>
#include <qstring.h>
#include <qlineedit.h>
#include <qtabwidget.h>

#include <kdebug.h>
#include <klocale.h>
#include <kprocess.h>
#include <ktimewidget.h>
#include <kdatepicker.h>
#include <kcombobox.h>
#include <kinputdialog.h>
#include <kapplication.h>
#include <kstandarddirs.h>
#include <kuser.h>

#include <kmessagebox.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

KalvaRecorder::KalvaRecorder(QWidget* parent, const char* name, WFlags fl)
    : kalva_recordergui(parent,name,fl)
{
   connect( m_film, SIGNAL( activated( const QString& )),
            m_film, SLOT( addToHistory( const QString& )));
   m_film->setMaxCount(100);
   m_film->setDuplicatesEnabled (false);
   m_user = 0;
   m_proc = 0;
   m_dcopProc = 0;
}

KalvaRecorder::~KalvaRecorder()
{}

/*$SPECIALIZATION$*/
void KalvaRecorder::setWeekends()
{
   m_monday->setChecked(false);
   m_tuesday->setChecked(false);
   m_wednesday->setChecked(false);
   m_thursday->setChecked(false);
   m_friday->setChecked(false);
   m_saturday->setChecked(true);
   m_sunday->setChecked(true);
}

void KalvaRecorder::setLaborDays()
{
   m_monday->setChecked(true);
   m_tuesday->setChecked(true);
   m_wednesday->setChecked(true);
   m_thursday->setChecked(true);
   m_friday->setChecked(true);
   m_saturday->setChecked(false);
   m_sunday->setChecked(false);
}

void KalvaRecorder::setDaily()
{
   m_monday->setChecked(true);
   m_tuesday->setChecked(true);
   m_wednesday->setChecked(true);
   m_thursday->setChecked(true);
   m_friday->setChecked(true);
   m_saturday->setChecked(true);
   m_sunday->setChecked(true);
}

void KalvaRecorder::stationChanged(const QString stat, const QString chan, const QString freq)
{
   m_station->setText(stat );
   m_channel->setText(chan );
   m_frq->setText(freq );
}


/* main control */

void KalvaRecorder::record()
{
   int recordMode = m_recordMode->currentPageIndex();
   switch (recordMode)
   {
      case 0:
         slotRecordNow();
         return;
      case 1:
         slotRecordMovie();
         return;
      case 2:
         slotRecordSerial();
         return;
   }
   cmd.append("***\nrecordMode = ");
   cmd.append(recordMode);
   KMessageBox::error ( this, cmd, i18n ("unsupported recordmode") );
}

void KalvaRecorder::slotDelete()
{
   int recordMode = m_recordMode->currentPageIndex();
   switch (recordMode)
   {
      case 0:
         return;
      case 1:
         if (! m_jobId->text().isEmpty() )  {
            emit signalDeleteMovie( m_jobId->text(), true );
         }
         return;
      case 2:
         emit signalDeleteSerialFromCron();
         return;
   }
}


/**
 * Record Now
 */
void KalvaRecorder::slotRecordNow()
{
    kdDebug() << "in slotRecordNow " << endl;
    kdDebug() << "videodev = " << Settings::videodev() << endl;

    cmd = recordCmd();

    if ( Settings::show_command() == true  ) {
#ifdef KDE_3_3_FEATURES
       bool ok;
       cmd = KInputDialog::getMultiLineText (
          i18n("Command to run"), 
          i18n("Command"), 
          cmd, 
          &ok,
          this,
          "cmdDlg"
       );
       if ( ok != true )  {
          return;
       }
#else
       int ret = KMessageBox::warningContinueCancel (
          this,
          cmd, 
          i18n("Command to run")
       );
       if ( ret != KMessageBox::Continue ) {
          return;
       }
#endif
   }

   if (m_proc)  {
      delete m_proc;
      m_proc = 0;
   }
   m_proc = new KProcess;
   QApplication::connect(m_proc, SIGNAL(processExited(KProcess *)),
                         this,   SLOT(slotMencRecNowExited(KProcess *)));
   m_proc->clearArguments();
   m_proc->setUseShell(true);
   (*m_proc) << cmd;
   kdDebug() << "Calling " << cmd << endl;
   m_proc->start(KProcess::NotifyOnExit, KProcess::Stderr);
}

void KalvaRecorder::slotMencRecNowExited(KProcess * proc)
{
   kdDebug() << "in slotMencRecNowExited(KProcess * proc)" << endl;
   if (! proc->normalExit() ) {
      KMessageBox::detailedSorry   (
         0,
         i18n("mencoder exited with errors."), 
         i18n("mencoder output was:\n%1").arg( proc->exitStatus() ), 
         i18n("mencoder failure")
      );
      kdWarning() << "mencoder exited with status"
                  << proc->exitStatus() << endl;
      kdWarning() << "mencoder exited abnormal" << endl;
      return;
   }
   //emit signalVideoRecorded();
}

/* Serial Recording */

void KalvaRecorder::slotRecordMovie()
{
//    ///@TODO this is a HACK, make it better!
//    if (Settings::driver().compare(
//		i18n("DVB (experimental!)")) == 0) {
//       if ( Settings::convert_mpg2_to_divx() ) {
//          cmd   = recordCmdDVBAsDivX4();
//       }  else  {
//          cmd   = recordCmdDVB();
//       }
//    }  else  {
       cmd   = recordCmd();
//     }

    if ( cmd.isEmpty() )  {
       return;
    }
    cmd.replace(QChar('"'), "\\\"");
    cmd.replace(QChar('`'), "\\`");
    cmd.prepend("echo \"");
    cmd.append("\" | at " + m_startMovie->time().toString ("hh:mm") + " " +
                            m_calender->date().toString("dd.MM.yyyy") );

    if ( Settings::show_command() == true  ) {
#ifdef KDE_3_3_FEATURES
       bool ok;
       cmd = KInputDialog::getMultiLineText (
          i18n("Command to run"), 
          i18n("Command"), 
          cmd, 
          &ok,
          this,
          "cmdDlg"
       );
       if ( ok != true )  {
          return;
       }
#else
       int ret = KMessageBox::warningContinueCancel (
          this,
          cmd, 
          i18n("Command to run")
       );
       if ( ret != KMessageBox::Continue ) {
          return;
       }
#endif
   }
   if (m_proc)  {
      delete m_proc;
      m_proc = 0;
   }
   m_proc = new KProcess;
   QApplication::connect(m_proc, SIGNAL(processExited(KProcess *)),
                         this,   SLOT(slotMencRecMovieExited(KProcess *)));
   m_proc->clearArguments();
   m_proc->setUseShell(true);
   (*m_proc) << cmd;
   kdDebug() << "Calling " << cmd << endl;
   m_proc->start(KProcess::NotifyOnExit, KProcess::Stderr);

   if ( m_dcopProc )
     delete m_dcopProc;
   m_dcopProc = 0;
   m_dcopProc = new KProcess;
   m_dcopProc->clearArguments();
   m_dcopProc->setUseShell(true);

   QTime dcoptime(m_startMovie->time());
   dcoptime = dcoptime.addSecs(180);
   cmd = "echo \"";
   cmd.append( "dcop --user $USER" );
   cmd.append( " --all-sessions" ); 
   cmd.append( " kalva DCOP_kalva DcopMovieManagerRead" );
   cmd.append( "\" | at " + dcoptime.toString ("hh:mm") + " " +
                           m_calender->date().toString("dd.MM.yyyy") );
   (*m_dcopProc) << cmd;
   kdDebug() << "Calling " << cmd << endl;
   m_dcopProc->start(KProcess::DontCare, KProcess::Stderr);
}

void KalvaRecorder::slotMencRecMovieExited(KProcess * proc)
{
   kdDebug() << "in slotMencRecMovieExited(KProcess * proc)" << endl;
   if (! proc->normalExit() ) {
      KMessageBox::detailedSorry   (
         0,
         i18n("at-command exited with errors."), 
         i18n("cmd output was:\n%1").arg( proc->exitStatus() ), 
         i18n("at-command failure")
      );
      kdWarning() << "at exited with status"
                  << proc->exitStatus() << endl;
      kdWarning() << "at exited abnormal" << endl;
      return;
   }
   QString jobid = m_jobId->text();
   if ( jobid.isEmpty() )  {
      kdDebug() << "emiting signalMovieScheduled ()" << endl;
      emit signalMovieScheduled();
   }  else  {
      kdDebug() << "emiting signalDeleteMovie (" << jobid << ")" << endl;
      emit signalDeleteMovie( jobid, false );
   }
}

void KalvaRecorder::slotNewMovie()
{
    m_jobId->clear();
    m_startMovie->setTime(QTime::currentTime());
    m_calender->setDate(QDate::currentDate());
    m_film->clear();
    m_film->setFocus();
}

void KalvaRecorder::slotMoviesRead()
{
   slotNewMovie();
}


/* Serial Recording */

void KalvaRecorder::slotRecordSerial()
{
//    ///@TODO this is a HACK, make it better!
//    if (Settings::driver().compare(
//		i18n( "DVB (experimental!)")) == 0 ) {
//       if ( Settings::convert_mpg2_to_divx() ) {
//          cmd   = recordCmdDVBAsDivX4();
//       }  else  {
//          cmd   = recordCmdDVB();
//       }
//    }  else  {
       cmd   = recordCmd();
//    }

    if ( cmd.isEmpty() )  {
       return;
    }
    cmd.replace(QChar('"'), "\\\"");
    cmd.replace(QChar('`'), "\\`");
    cmd.replace(QChar('%'), "\\%");
    cmd.prepend("perl /usr/bin/tvapp.pl -film \"" + m_film->currentText() + "\"" +
                                         " -hour "          +
                                         m_startSerial->time().toString("h") + 
                                         " -minute "        +
                                         m_startSerial->time().toString("m") + 
                                         " -daysoftheweek " + setDOWs() +
                                         " -cmd \""
               );
    cmd.append("\" -cronaddcmd ");

    if ( Settings::show_command() == true  ) {
#ifdef KDE_3_3_FEATURES
       bool ok;
       cmd = KInputDialog::getMultiLineText (
          i18n("Command to run"), 
          i18n("Command"), 
          cmd, 
          &ok,
          this,
          "cmdDlg"
       );
       if ( ok != true )  {
          return;
       }
#else
       int ret = KMessageBox::warningContinueCancel (
          this,
          cmd, 
          i18n("Command to run")
       );
       if ( ret != KMessageBox::Continue ) {
          return;
       }
#endif
   }

   if (m_proc)  {
      delete m_proc;
      m_proc = 0;
   }
   m_proc = new KProcess;
   QApplication::connect(m_proc, SIGNAL(processExited(KProcess *)),
                         this,   SLOT(slotMencRecSerialExited(KProcess *)));
   m_proc->clearArguments();
   m_proc->setUseShell(true);
   (*m_proc) << cmd;
   kdDebug() << "Calling " << cmd << endl;
   m_proc->start(KProcess::NotifyOnExit, KProcess::Stderr);
}

void KalvaRecorder::slotMencRecSerialExited(KProcess * proc)
{
   kdDebug() << "in slotMencRecSerialExited(KProcess * proc)" << endl;
   if (! proc->normalExit() ) {
      KMessageBox::detailedSorry   (
         0,
         i18n("tvapp.pl -cronaddcmd exited with errors."), 
         i18n("tvapp.pl output was:\n%1").arg( proc->exitStatus() ), 
         i18n("tvapp.pl failure")
      );
      kdWarning() << "tvapp.pl -cronaddcmd exited with status"
                  << proc->exitStatus() << endl;
      kdWarning() << "tvapp.pl exited abnormal" << endl;
      return;
   }
   emit signalSerialScheduled();
}

QString KalvaRecorder::setDOWs()  {
   dow = "";
   dow = setDayInDOWs ( m_sunday->isChecked(),    dow, ((QString)"0"));
   dow = setDayInDOWs ( m_monday->isChecked(),    dow, ((QString)"1"));
   dow = setDayInDOWs ( m_tuesday->isChecked(),   dow, ((QString)"2"));
   dow = setDayInDOWs ( m_wednesday->isChecked(), dow, ((QString)"3"));
   dow = setDayInDOWs ( m_thursday->isChecked(),  dow, ((QString)"4"));
   dow = setDayInDOWs ( m_friday->isChecked(),    dow, ((QString)"5"));
   dow = setDayInDOWs ( m_saturday->isChecked(),  dow, ((QString)"6"));
   ///@TODO: translation if there is a sequence in the list (f.i."1,2,3,4,5" should become "1-5")
   return dow;
}

QString KalvaRecorder::setDayInDOWs ( bool isChecked, QString dow, QString day )
{
   if (isChecked == true )  {
      if (! (dow.isEmpty() ))   {
          dow.append(",");
      }
      dow.append(day);
   }
   return dow;
}

///@TODO: translation if there is a sequence in the list (f.i."1,2,3,4,5" should become "1-5")
void KalvaRecorder::setYourDOWs ( const QString & yourDOWs )
{
   QStringList dows = QStringList::split( ",", yourDOWs, false );
   QString dow;
   bool ok;
   unsetDOWs();
   for ( QStringList::Iterator it = dows.begin(); it != dows.end(); ++it ) {
       dow = *it;
       kdDebug() << "dow = "  << dow << endl;
       setYourDayInDOWs ( dow.toInt( &ok, 10 ) );
   }
}

void KalvaRecorder::unsetDOWs ()
{
   m_sunday->setChecked(false);
   m_monday->setChecked(false);
   m_tuesday->setChecked(false);
   m_wednesday->setChecked(false);
   m_thursday->setChecked(false);
   m_friday->setChecked(false);
   m_saturday->setChecked(false);
}

void KalvaRecorder::setYourDayInDOWs ( const int & yourDOW )
{
   switch (yourDOW) {
      case 0: { m_sunday->setChecked(true);
                break; }
      case 1: { m_monday->setChecked(true);
                break; }
      case 2: { m_tuesday->setChecked(true);
                break; }
      case 3: { m_wednesday->setChecked(true);
                break; }
      case 4: { m_thursday->setChecked(true);
                break; }
      case 5: { m_friday->setChecked(true);
                break; }
      case 6: { m_saturday->setChecked(true);
                break; }
   }
}


// BUILD the mencoder call
QString KalvaRecorder::recordCmd()
{
    KalvaCmd *myCmd = new KalvaCmd( this );
    myCmd->recordCmd( m_film->currentText(),
                      m_station->text(),
                      m_duration->time().toString(),
                      m_channel->text(),
                      m_frq->text()
                     );
    return *myCmd;
}

// QString KalvaRecorder::recordCmdDVB()
// {
//     KalvaCmd *myCmd = new KalvaCmd( this );
//     myCmd->recordCmdDVB( m_film->currentText(),
//                       m_station->text(),
//                       m_duration->time().toString()
//                      );
//     return *myCmd;
// }
// 
// QString KalvaRecorder::recordCmdDVBAsDivX4()
// {
//     KalvaCmd *myCmd = new KalvaCmd( this );
//     myCmd->recordCmdDVBAsDivX4( m_film->currentText(),
//                       m_station->text(),
//                       m_duration->time().toString()
//                      );
//     return *myCmd;
// }


QString KalvaRecorder::recordNow(
                    const QString & yourTitel,
                    const QString & yourLength,
                    bool  run
                    )
{
   QString yourHours;
   QString yourMinutes;
   QString yourSeconds;
   QString yourTime;

   m_recordMode->setCurrentPage(0);
   m_film->setCurrentText( yourTitel );

   yourHours   = yourLength.section(":",0,0).rightJustify( 2, '0' );
   yourMinutes = yourLength.section(":",1,1).rightJustify( 2, '0' );
   yourSeconds = yourLength.section(":",2,2).rightJustify( 2, '0' );
   yourTime    = QString("%1:%2:%3").arg( yourHours )
                                    .arg( yourMinutes )
                                    .arg( yourSeconds );
   m_duration->setTime( QTime::fromString ( yourTime ) );

   if ( run )  {
     slotRecordNow();
   }
   return i18n("recording immediatly");
}

QString KalvaRecorder::recordMovie(
                    const QString & yourTitel,
                    const QString & yourLength,
                    const QString & yourStartTime,
                    const QString & yourStartDay,
                    const QString & jobId,
                    bool  run
                    )
{
   QString yourHours;
   QString yourMinutes;
   QString yourSeconds;
   QString yourTime;

   m_jobId->setText( jobId );
   m_recordMode->setCurrentPage(1);
   m_film->setCurrentText( yourTitel );

   yourHours   = yourLength.section(":",0,0).rightJustify( 2, '0' );
   yourMinutes = yourLength.section(":",1,1).rightJustify( 2, '0' );
   yourSeconds = yourLength.section(":",2,2).rightJustify( 2, '0' );
   yourTime    = QString("%1:%2:%3").arg( yourHours )
                                    .arg( yourMinutes )
                                    .arg( yourSeconds );
   m_duration->setTime( QTime::fromString ( yourTime ) );

   yourHours   = yourStartTime.section(":",0,0).rightJustify( 2, '0' );
   yourMinutes = yourStartTime.section(":",1,1).rightJustify( 2, '0' );
   yourSeconds = yourStartTime.section(":",2,2).rightJustify( 2, '0' );
   yourTime    = QString("%1:%2:%3").arg( yourHours )
                                    .arg( yourMinutes )
                                    .arg( yourSeconds );
   m_startMovie->setTime( QTime::fromString ( yourTime ) );

   m_calender->setDate( QDate::fromString ( yourStartDay, Qt::ISODate ) );
   if ( run )  {
     slotRecordMovie();
   }
   return i18n("recording Movie");
}

QString KalvaRecorder::recordSerial(
                    const QString & yourTitel,
                    const QString & yourLength,
                    const QString & yourStartTime,
                    const QString & yourDOWs,
                    bool  run
                    )
{
   QString yourHours;
   QString yourMinutes;
   QString yourSeconds;
   QString yourTime;

   m_recordMode->setCurrentPage(2);
   m_film->setCurrentText( yourTitel );

   yourHours   = yourLength.section(":",0,0).rightJustify( 2, '0' );
   yourMinutes = yourLength.section(":",1,1).rightJustify( 2, '0' );
   yourSeconds = yourLength.section(":",2,2).rightJustify( 2, '0' );
   yourTime    = QString("%1:%2:%3").arg( yourHours )
                                    .arg( yourMinutes )
                                    .arg( yourSeconds );
   m_duration->setTime( QTime::fromString ( yourTime ) );

   yourHours   = yourStartTime.section(":",0,0).rightJustify( 2, '0' );
   yourMinutes = yourStartTime.section(":",1,1).rightJustify( 2, '0' );
   yourSeconds = yourStartTime.section(":",2,2).rightJustify( 2, '0' );
   yourTime    = QString("%1:%2:%3").arg( yourHours )
                                    .arg( yourMinutes )
                                    .arg( yourSeconds );
   m_startSerial->setTime( QTime::fromString ( yourTime ) );

   setYourDOWs( yourDOWs );
   if ( run )  {
      slotRecordSerial();
   }
   return i18n("recording serial");
}

#include "kalva_recorder.moc"
