#include <qlabel.h>

#include "mainwindow.h"
#include "functions.h"
#include "zeipisdesktopepg.h"
#include <qgroupbox.h>
#include <qcombobox.h>
#include <qcheckbox.h>
#include <qlineedit.h>
#include <qtextedit.h>
#include <qdatetimeedit.h>
#include <qsplitter.h>
#include <qpushbutton.h>
#include <qspinbox.h>
#include <qslider.h>
#include <qwidgetstack.h>
#include <qdatatable.h>
#include <qsqlform.h>
#include <qsqlselectcursor.h>
#include <qsqldatabase.h>
#include <qmessagebox.h>
#include <qprocess.h>
#include <iostream>

MainWindow::MainWindow(QWidget* parent, QString& coreserverhost, int coreserverport, const char* name, WFlags fl)
        : MainWindowBase(parent, name, fl),
          myDB(QSqlDatabase::database("zeipisConn")),
          myCoreServerHostname(coreserverhost),
          myCoreServerPort(coreserverport),
          myRecordID(-1)
{
  // set splitter size
  QValueList<int> sizes;
  sizes.append(200);
  sizes.append(350);
  sizes.append(100);
  splitter2->setSizes(sizes);

  // Fill recording groups combobox
  QStringList groups;
  QSqlQuery groupQuery("SELECT DISTINCT rec_group FROM recording", myDB);
  if (groupQuery.isActive())
    while (groupQuery.next())
      groups.append(groupQuery.value(0).toString());
  if (groups.isEmpty())
  	groups.append(tr("Standard"));
  groupDropdown->insertStringList(groups);

  // Initial load
  overviewLoad();
  overviewTable->selectRow(0);
  detailsLoad(overviewTable->currentRecord());
}

MainWindow::~MainWindow()
{}

/*$SPECIALIZATION$*/
void MainWindow::fileExit()
{
}

void MainWindow::overviewLoad()
{
  // query / showtype dropdown
  QString where;
  int type = typeBox->currentItem();
  if (type == 0) // all
    where = "0 = 0";
  else if (type == 1) // movies
    where = "showtype = 'movie'";
  else if (type == 2) // series
    where = "showtype = 'series'";
  else if (type == 3) // new movies
    where = "showtype = 'movie'";
  else if (type == 4) // new series
    where = "showtype = 'series'";
  else if (type == 5) // all movies
    where = "showtype = 'movie'";
  else
    where = "0 = 0";

  if (commfreeBox->isChecked())
    where += " AND commercial_free > 0";
  if (!airdateFilterField->text().isEmpty())
    where += " AND firstshown >= " + QString::number(airdateFilterField->text().toInt());
  if (!customSqlField->text().isEmpty())
    where += " AND " + customSqlField->text();

  // Remove repetitions
  QString groupby;
  if (type == 3) // new series
    groupby = "title HAVING COUNT(title) = 1"; // All which appear only once. Doesn't work for this purpose (of finding new series).
  else if (type == 1 || type == 3 || type == 5)
    groupby = "filmid";
  else if (oneTitleBox->isChecked())
    groupby = "title";
  if (!groupby.isEmpty())
    where += " GROUP BY " + groupby;

  // Sort
  QString orderby;
  int sortType = sortBox->currentItem();
  if (sortType == 0)
    orderby = "preset ASC, short_name ASC, starttime ASC";
  else if (sortType == 1)
    orderby = "starttime ASC, preset ASC, short_name ASC";
  else if (sortType == 2)
    orderby = "title ASC";
  else if (sortType == 3)
    orderby = "genre ASC, quality_rating DESC, firstshown DESC";
  else if (sortType == 4)
    orderby = "quality_rating DESC, firstshown DESC";
  else if (sortType == 5)
    orderby = "firstshown DESC, quality_rating DESC";

#define OVERVIEWFIELDS "film.filmid, broadcast.broadcastid, broadcast.stationid, station.short_name, station.long_name, broadcast.starttime, broadcast.endtime, film.title, film.subtitle, film.genre, film.showtype, film.description, ROUND(film.quality_rating * 10) AS stars, film.firstshown"
#define OVERVIEWTABLE "broadcast LEFT JOIN film USING (filmid) LEFT JOIN station USING (stationid)"
//includes series, but too slow #define PLANNEDREC "recording LEFT JOIN recording_plan USING (recordid) LEFT JOIN film as film1 USING (filmid) RIGHT JOIN film USING (title) LEFT JOIN broadcast ON (film.filmid=broadcast.filmid) LEFT JOIN station USING (stationid) WHERE done = false AND starttime > NOW() GROUP BY recording.recordid"
#define PLANNEDREC "recording LEFT JOIN recording_plan USING (recordid) LEFT JOIN film USING (filmid) LEFT JOIN broadcast USING (filmid) LEFT JOIN station USING (stationid) WHERE done = false AND starttime > NOW() GROUP BY recording.recordid"
//#define ALLPROGRAMS OVERVIEWFIELDS " FROM film LEFT JOIN broadcast USING (filmid) LEFT JOIN station USING (stationid)"
#define ALLPROGRAMS "NULL AS broadcastid, NULL AS stationid, NULL AS short_name, NULL AS long_name, NULL AS starttime, NULL AS endtime, 0 AS preset, film.filmid, film.title, film.subtitle, film.genre, film.showtype, film.description, ROUND(film.quality_rating * 10) AS stars, film.firstshown FROM film"
 
  QString select = "SELECT " OVERVIEWFIELDS " FROM " OVERVIEWTABLE
                   " WHERE endtime > NOW()"
                   " AND " + where + " ORDER BY " + orderby;
  if (type == 5) // all movies
    select = "SELECT " ALLPROGRAMS " WHERE " + where + " ORDER BY " + orderby;
  else if (type == 6) // planed recordings
  	select = "SELECT " OVERVIEWFIELDS " FROM " PLANNEDREC " ORDER BY " + orderby;

  // TODO description is only for details, make a new query for that
  debug("Reloading overview with %s", select.data());
  QSqlSelectCursor* cursor = new QSqlSelectCursor(select, myDB);
  overviewTable->setSqlCursor(cursor, FALSE, TRUE);
  overviewTable->setColumnWidth(0, 70);
  overviewTable->setColumnWidth(1, 140);
  overviewTable->setColumnWidth(2, 300);
  overviewTable->setColumnWidth(3, 150);
  overviewTable->setColumnWidth(4, 70);
  overviewTable->setColumnWidth(5, 50);
  overviewTable->refresh();
}


void MainWindow::detailsLoad(QSqlRecord* r)
{
  if (!r)
  	return;
  //debug("Details load");
  QSqlForm form(this);
  form.setRecord(r);
  form.insert(titleField, "title");
  form.insert(subtitleField, "subtitle");
  form.insert(categoryField, "genre");
  form.insert(stationField, "long_name");
  form.insert(starttimeField, "starttime");
  form.insert(endtimeField, "endtime");
  form.insert(descrField, "description");
  form.insert(airdateField, "firstshown");
  ratingSlider->setValue(int(r->value("stars").toDouble() * 10));
  form.readFields();

  // Other airings
#if 0 // find only same film
  QString select = "SELECT broadcast.broadcastid, broadcast.starttime, film.subtitle, station.short_name, broadcast.stationid"
                   " FROM broadcast LEFT JOIN film USING (filmid) LEFT JOIN station ON (broadcast.stationid = station.stationid)"
                   " WHERE broadcast.filmid = " + QString::number(r->value("filmid").toInt()) +
                   " AND broadcastid != " + QString::number(r->value("broadcastid").toInt()) +
                   " AND endtime > NOW()" +
                   " ORDER BY starttime ASC";
#else // find per title, to find other episodes of same series
  QString select = "SELECT broadcast.broadcastid, broadcast.starttime, film.subtitle, station.short_name, broadcast.stationid FROM " OVERVIEWTABLE
                   " WHERE title='" + sqlSafe(r->value("title").toString()) + "' " +
                   " AND broadcastid != " + QString::number(r->value("broadcastid").toInt()) +
                   " AND endtime > NOW()" +
                   " ORDER BY starttime ASC";
#endif
  debug("other airings: %s", select.data());
  QSqlSelectCursor* cursor = new QSqlSelectCursor(select, myDB);
  airingsTable->setSqlCursor(cursor, FALSE, TRUE);
  airingsTable->setColumnWidth(0, 140);
  airingsTable->setColumnWidth(1, 300);
  airingsTable->setColumnWidth(2, 70);
  airingsTable->refresh();

  // Credits
  select = "SELECT credits.personid, credits.function, person.realname, credits.role FROM credits LEFT JOIN person USING (personid)"
           " WHERE filmid=" + QString::number(r->value("filmid").toInt());
  //debug("credits: %s", select.data());
  cursor = new QSqlSelectCursor(select, myDB);
  creditsTable->setSqlCursor(cursor, FALSE, TRUE);
  creditsTable->setColumnWidth(0, 60);
  creditsTable->setColumnWidth(1, 150);
  creditsTable->setColumnWidth(2, 150);
  creditsTable->refresh();

  // Record (query)
  QSqlQuery recordQuery(myDB);
  select = "SELECT recording.recordid, recording.done, recording_plan.searchtype, recording_plan.priority, recording.rec_group FROM recording LEFT JOIN recording_plan USING (recordid)"
           " WHERE filmid=" + QString::number(r->value("filmid").toInt());
  recordQuery.exec(select);
  debug("checking recording: %s", recordQuery.lastQuery().data());

  // OK, Qt is really crap *here*. If I don't do that,
  // valueChanged()->record() gets called when I do setValue/setChecked.
  recordBox->blockSignals(true);
  groupDropdown->blockSignals(true);
  priorityField->blockSignals(true);

  if (recordQuery.isActive() && recordQuery.next())
  {
    myRecordID = recordQuery.value(0).toInt();
    debug("Found recordid %d", myRecordID);
    bool done = recordQuery.value(1).toBool();
    debug("is done %d", done);
    //int recordtype = recordQuery.value(2).toInt();
    int priority = recordQuery.value(3).toInt();
    QString group = recordQuery.value(4).toString();

    recordBox->setChecked(TRUE);
    recordBox->setEnabled(TRUE);
    groupDropdown->setEnabled(TRUE);
    moreButton->setEnabled(TRUE);
    priorityField->setEnabled(TRUE);

    groupDropdown->setCurrentText(group);
    priorityField->setValue(priority);

	recordStack->raiseWidget(done ? 1 : 0);
  }
  else
  {
    debug("Found no recording");
    myRecordID = -1;
	recordStack->raiseWidget(0);
    recordGroup->setEnabled(TRUE);
    recordBox->setChecked(FALSE);
    groupDropdown->setEnabled(FALSE);
    moreButton->setEnabled(FALSE);
    priorityField->setEnabled(FALSE);
    myStarttime = r->value("starttime").toDateTime();
  }

  recordBox->blockSignals(false);
  groupDropdown->blockSignals(false);
  priorityField->blockSignals(false);

  myFilmID = r->value("filmid").toInt();
  myShowtype = r->value("showtype").toString();
}

void MainWindow::recordToggle(bool checked)
{
    groupDropdown->setEnabled(checked);
    moreButton->setEnabled(checked);
    priorityField->setEnabled(checked);
}

void MainWindow::record()
{
  if (recordBox->isChecked())
  {
    int recordtype;
    if (myShowtype == "movie")
      recordtype = 2; // Find one
    else if (myShowtype == "series")
      recordtype = 4; // Always channel
    else if (myShowtype == "sports")
      recordtype = 1; // At this time
    else
      recordtype = 2; // Find one

    QSqlQuery recordQuery(myDB);
    if (myRecordID < 0) // add new record (otherwise change existing)
    {
      recordQuery.exec("INSERT INTO recording SET filmid=-1"); // create ID (needs *some* SET)
      recordQuery.exec("SELECT LAST_INSERT_ID()");
      if (recordQuery.next())
        myRecordID = recordQuery.value(0).toInt();
      else
        error(tr("Could not get new record id: ") + recordQuery.lastQuery());
      debug("got new record ID %d", myRecordID);
    }
    recordQuery.exec("REPLACE INTO recording SET recordid=" + QString::number(myRecordID) + ", filmid=" + QString::number(myFilmID) + ", rec_group='" + sqlSafe(groupDropdown->currentText()) + "'");
    debug("recording: %s", recordQuery.lastQuery().data());
    recordQuery.exec("REPLACE INTO recording_plan SET recordid=" + QString::number(myRecordID) + ", searchtype=" + QString::number(recordtype) + ", priority=" + QString::number(priorityField->value()));
    debug("recording: %s", recordQuery.lastQuery().data());
  }
  else // don't record
  {
    if (myRecordID >= 0) // delete
    {
      QSqlQuery recordQuery("DELETE FROM recording WHERE done=false AND recordid=" + QString::number(myRecordID), myDB);
      QSqlQuery recordQuery2("DELETE FROM recording_plan WHERE recordid=" + QString::number(myRecordID), myDB);
      recordQuery.exec();
      recordQuery2.exec();
      debug("deleting recording: %s", recordQuery.lastQuery().data());
    }
    // else nothing to do
  }
  // TODO ping backend
}

void MainWindow::creditsGo()
{
  QSqlRecord* r = creditsTable->currentRecord();
  int personid = r->value("personid").toInt();
  debug("searching for credits personid %d", personid);
  QString select = "SELECT " OVERVIEWFIELDS " FROM credits LEFT JOIN broadcast USING (filmid) LEFT JOIN film USING (filmid) LEFT JOIN station USING (stationid)"
                   " WHERE credits.personid=" + QString::number(personid) +
                   " AND endtime > NOW()" +
                   " GROUP BY filmid";
  debug("reloading overview for credits with %s", select.data());
  QSqlSelectCursor* cursor = new QSqlSelectCursor(select, myDB);
  overviewTable->setSqlCursor(cursor, FALSE, TRUE);
  overviewTable->refresh();
}

void MainWindow::airingsGo()
{
  QSqlRecord* r = airingsTable->currentRecord();
  QString select = "SELECT " OVERVIEWFIELDS " FROM " OVERVIEWTABLE
                   " WHERE broadcast.broadcastid=" + QString::number(r->value(0).toInt()) +
                   " AND endtime > NOW()";
  debug("Reloading overview for other airing with %s", select.data());
  QSqlSelectCursor* cursor = new QSqlSelectCursor(select, myDB);
  cursor->select();
  if (!cursor->next())
  {
    error(tr("other airing not found: ") + select);
    return;
  }
  detailsLoad(cursor);
}

void MainWindow::search()
{
  if (searchField->text().isEmpty())
  {
    overviewLoad();
    return;
  }
  QString searchText = sqlSafe(searchField->text());
  QString select = "SELECT " OVERVIEWFIELDS " FROM person RIGHT JOIN credits USING (personid) LEFT JOIN film USING (filmid) LEFT JOIN broadcast USING (filmid) LEFT JOIN station USING (stationid)"
                   " WHERE endtime > NOW() "
                   " AND film.title LIKE '%" + sqlSafe(searchText) + "%' OR person.realname LIKE '%" + sqlSafe(searchText) + "%'"
                   " GROUP BY filmid";
  debug("Reloading overview for search %s", select.data());
  QSqlSelectCursor* cursor = new QSqlSelectCursor(select, myDB);
  overviewTable->setSqlCursor(cursor, FALSE, TRUE);
  overviewTable->refresh();
}


#define PLAYERCOMMAND "mplayer -fs"

void MainWindow::watch()
{
  if (myRecordID < 0)
    return;

  QString url = "http://";
  url += myCoreServerHostname;
  url += ":";
  url += QString::number(myCoreServerPort);
  url += "/recorded/video/";
  url += QString::number(myRecordID);

  std::cout << "Starting movie player " << PLAYERCOMMAND << " " << url << std::endl;
  QProcess* player = new QProcess(this);
  QStringList args = QStringList::split(" ", PLAYERCOMMAND);
  for (QStringList::iterator i = args.begin(); i != args.end(); i++)
    player->addArgument(*i);
  player->addArgument(url);
  
  if ( ! player->start())
  {
    QMessageBox::critical(this,
       tr("Could not start player"),
       tr("Could not start the command\n" + args.join(" ") + " " + url));
  }

#if 0
  connect( proc, SIGNAL(readyReadStdout()),
          this, SLOT(readFromStdout()) );
  connect( proc, SIGNAL(processExited()),
          this, SLOT(scrollToTop()) );
#endif
}
