/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
 *            mainwindow.cc
 *
 *  Sat Aug 21 19:49:34 2004
 *  Copyright  2004  deva
 *  deva@aasimon.org
 ****************************************************************************/

/*
 *    This file is part of MIaV.
 *
 *    MIaV 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.
 *
 *    MIaV 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 MIaV; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 */
#include "mainwindow.h"

#include <QPainter>
#include <QPicture>
#include <QPushButton>
#include <QFont>
#include <QPixmap>
#include <QBitmap>
#include <QImage>
#include <QLayout>
#include <QGroupBox>
#include <QStatusBar>

#include <math.h>

#include <config.h>

#include "miav_config.h"

// Control fade speed of record bar.
#define SPEED 0.07f

//#define WITH_DV
MainWindow::MainWindow(QApplication *_qApp, QWidget* parent, const char* name )
	: QWidget( parent, Qt::FramelessWindowHint )
{
  info = new InfoGui(_qApp, this, config);

  info->log("Starting MIaV v. %s.", VERSION);

  video_width = config->readInt("video_width");
  video_height = config->readInt("video_height");

  int resolution_w = config->readInt("pixel_width");
  int resolution_h = config->readInt("pixel_height");

  unit = ((float)resolution_w / config->readFloat("screensize")) / INCH_IN_CM;

  //printf("Unit: %f\n", unit);

  move(0,0);
  resize(resolution_w, resolution_h);

  // Load icons
  img_record = loadButtonIcon( PIXMAP_RECORD );
  img_stop = loadButtonIcon( PIXMAP_STOP );
  img_freeze = loadButtonIcon( PIXMAP_FREEZE );
  img_unfreeze = loadButtonIcon( PIXMAP_UNFREEZE );
  img_cpr = loadButtonIcon( PIXMAP_CPR );
  img_clear = loadButtonIcon( PIXMAP_CLEAR );
  img_snapshot = loadButtonIcon( PIXMAP_SNAPSHOT );
  img_logo = loadButtonIcon( PIXMAP_LOGO_SMALL, 1 );
  img_mute = loadButtonIcon( PIXMAP_MUTE );
  img_unmute = loadButtonIcon( PIXMAP_UNMUTE );

  img_dummy = loadImage( PIXMAP_DUMMY );
  
  timer = new QTimer(this);
  connect(timer, SIGNAL(timeout()), SLOT(redraw_edge()));
  rec_edge_counter = 0.0f;

  // This must be defined before the gui i created (img_live uses it as parameter)
  camera = new Camera(info);

  createGui();
  show();

  camera->connect(config->readString("server_addr")->c_str(), 
                  config->readInt("server_port"),
                  img_live->width(), img_live->height());

  // Make sure this is created *after* the camera object!
  taskbartimer = new QTimer(this);
  connect(taskbartimer, SIGNAL(timeout()), SLOT(taskbar_update()));
  taskbartimer->start(200);

  recording = false;
  frozen = false;
  muted = false;

  info->log("MIaV is ready.");

  // Open the CPR Dialog
  cpr_clicked();

}

MainWindow::~MainWindow()
{
  info->log("MIaV is shutting down.");

  delete img_history;
  delete camera;
  delete btn_cpr;

  info->log("MIaV is shut down.");
}

QImage *MainWindow::loadButtonIcon( const char *name, int height )
{

  QImage scaled;
  QImage *img;

  img = new QImage();
  img->load( name );

  int h = (int)(height * unit);
  int w = (int)((float)img->width() / (float)(img->height() / (float)h));

  scaled = img->scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation);
  delete img;
  img = new QImage(scaled);

  return img;
}

QImage *MainWindow::loadImage( const char *name )
{
  QImage *img;

  img = new QImage();
  img->load( name );

  return img;
}

void MainWindow::createGui()
{
  QPixmap p;
  // Layout widgets

  /*  __________________________________________________
   *(0) ___________________________  |  ______________  |
   * | |      |      |      |      | | |              | |
   * |(1)     |      |      |      | |(2)             | |
   * | |      |      |      |      | | |              | |
   * | |      |      |      |      | | |              | |
   * | |      |      |      |      | | |______________| |
   * | |      |      |      |      | | |              | |
   * | |      |      |      |      | | |              | |
   * | |      |      |      |      | | |              | |
   * | |______|______|______|______| | |              | |
   * | |      |      |      |      | | |______________| |
   * | |______|______|______|______| | |              | |
   * | |      |      |      |      | | |              | |
   * | |______|______|______|______| | |              | |
   * | |      |      |      |      | | |              | |
   * | |______|______|______|______| | |______________| |
   * |_______________________________|__________________|
   * |_______________________________|__________________|
   */

	QGridLayout *g0 = new QGridLayout(this);//, 2, 2, 0, -1);
	QGridLayout *g1 = new QGridLayout();//4, 4, -1);
  g0->addLayout(g1, 0, 0);

  QGroupBox *gb = new QGroupBox(this);
  gb->setLayout(new QVBoxLayout());
  /* // TODO
  //  gb->setRows(NUM_HISTORY);
  gb->setColumns(1);
  //  gb->setTitle("fisk");
  //	QGridLayout *g2 = new QGridLayout(1, NUM_HISTORY, -1);
  //	QVBoxLayout *g2 = new QVBoxLayout(this);
  //  g0->addLayout(g2, 0, 1);
  
  gb->setInsideMargin(HISTORY_LIST_MARGIN);
  gb->setInsideSpacing(HISTORY_LIST_SPACING);
  */
  gb->setFlat(true);
  g0->addWidget(gb, 0, 1);

  int resolution_w = config->readInt("pixel_width");
  int resolution_h = config->readInt("pixel_height");

  int output_width = resolution_w - // this->width() - 
    (int)(BUTTON_WIDTH * unit) - 
    //    (gb->insideMargin() * 2) -  // TODO
    g1->margin() * 2 -
    g0->margin() * 2;

  int output_height = resolution_h - // this->height() - 
    (int)(3 * BUTTON_HEIGHT * unit) - 
    g1->margin() * 5 -
    g0->margin() * 3;

  img_recedge = new RecEdge();
  img_recedge->setFixedSize(output_width, output_height);
  
  img_live = new VideoWidget(img_recedge, camera);
  img_recedge->setInnerWidget(img_live);

  img_live->setFixedSize(output_width - 20, output_height - 20);
  img_live->move(10,10);
  //g1->addWidget ( img_recedge, 0, 0, 0, 3, Qt::AlignHCenter);
  g1->addWidget ( img_recedge, 0, 0, 1, 4, Qt::AlignHCenter);
  //  QObject::connect( img_live, SIGNAL(clicked()), this, SLOT(live_clicked()) );
  img_recedge->setIdle(true);

  // CPR/NAME LABEL + CPR button
  lbl_cpr = createLabel("", output_width - (int)(BUTTON_WIDTH * unit), BUTTON_HEIGHT);
  //g1->addWidget ( lbl_cpr, 1, 1, 0, 2);
  g1->addWidget ( lbl_cpr, 1, 0, 1, 2);

  btn_cpr = createButton("");
  btn_cpr->setFocus();
  btn_cpr->setIcon(QPixmap(PIXMAP_CPR));
  QObject::connect( btn_cpr, SIGNAL(clicked()), this, SLOT(cpr_clicked()) );
  // Will also be connected in the MGUI code
  g1->addWidget(btn_cpr, 1, 3);

  lbl_name = createLabel("",  output_width, (int)(BUTTON_HEIGHT * 0.8f));
  //g1->addWidget ( lbl_name, 2, 2, 0, 3);
  g1->addWidget ( lbl_name, 2, 0, 1, 2);
/*
  btn_clear = createButton("");
  btn_clear->setIcon(QPixmap(PIXMAP_CLEAR));
  QObject::connect( btn_clear, SIGNAL(clicked()), this, SLOT(clear_clicked()) );
  // Will also be connected in the MGUI code
  g1->addWidget(btn_clear, 1, 2);
*/
  // Rec + Shot + Freeze buttons
  btn_rec = createButton("");
  btn_rec->setIcon(QPixmap(PIXMAP_RECORD));
  QObject::connect( btn_rec, SIGNAL(clicked()), this, SLOT(rec_clicked()) );
  g1->addWidget(btn_rec, 3, 0);
  
  btn_shoot = createButton("");
  btn_shoot->setIcon(QPixmap(PIXMAP_SNAPSHOT));
  QObject::connect( btn_shoot, SIGNAL(clicked()), this, SLOT(shoot_clicked()) );
  g1->addWidget(btn_shoot, 3, 1);
  
  btn_freeze = createButton("");
  btn_freeze->setIcon(QPixmap(PIXMAP_FREEZE));
  QObject::connect( btn_freeze, SIGNAL(clicked()), this, SLOT(freeze_clicked()) );
  g1->addWidget(btn_freeze, 3, 2);
  
  btn_mute = createButton("");
  btn_mute->setIcon(QPixmap(PIXMAP_UNMUTE));
  QObject::connect( btn_mute, SIGNAL(clicked()), this, SLOT(mute_clicked()) );
  g1->addWidget(btn_mute, 3, 3);
  
  // History widgets
  int w = (int)((float)BUTTON_WIDTH * unit);
  int h = (int)(576.0f / (720.0f / ((float)BUTTON_WIDTH * unit)));

  int window_height = config->readInt("pixel_height");
  this->num_history = (window_height - 
                       ((int)unit * BUTTON_HEIGHT + HISTORY_LIST_SPACING ) - 
                       (2 * HISTORY_LIST_MARGIN)) / (h + HISTORY_LIST_SPACING);
  img_history = new HistoryWidget*[this->num_history];

  for(unsigned int i = 0; i < num_history; i++) {
    img_history[i] = new HistoryWidget(gb);
    img_history[i]->set_image(img_dummy);
    img_history[i]->setFixedSize(w, h);
    img_history[i]->show();
    gb->layout()->addWidget(img_history[i]);
  }

  // Clear button
  btn_clear = createButton("", gb);
  btn_clear->setIcon(QPixmap(PIXMAP_CLEAR));
  QObject::connect( btn_clear, SIGNAL(clicked()), this, SLOT(clear_clicked()) );
  gb->layout()->addWidget(btn_clear);

  // Statusbar
  status = new QStatusBar(this);
  status->setSizeGripEnabled(FALSE);
  //  status->setFont(QFont( "Sans Serif", (int)(unit * height / 3), QFont::Normal ));
  //g0->addWidget(status, 4, 4, 0, 1);
  g0->addWidget(status, 4, 0, 1, 2);

  lbl_recordtime = createLabel("", BUTTON_WIDTH, 1);
  /*
  lbl_recordtime->setFixedWidth((int)(BUTTON_WIDTH * unit) + 
                                //(gb->insideMargin() * 2) + 
                                g1->margin() * 2 +
                                g0->margin() * 2);
  */
  status->addPermanentWidget(lbl_recordtime);//, 0, TRUE);

  // About button
  btn_about = new QPushButton("", this);
  btn_about->setFixedHeight((int)unit);
  btn_about->setIcon(QPixmap(PIXMAP_LOGO_SMALL));
  QObject::connect( btn_about, SIGNAL(clicked()), this, SLOT(about_clicked()) );
  status->addPermanentWidget(btn_about);//, 0, TRUE);

  // Version label
  lbl_version = createLabel("MIaV-Grab v" VERSION, BUTTON_WIDTH, 1);
  lbl_version->setFixedWidth((int)(BUTTON_WIDTH * unit) +
                             //(gb->insideMargin() * 2) + 
                                g1->margin() * 2 +
                                g0->margin() * 2);
  status->addPermanentWidget(lbl_version);//, 0, TRUE);

  status->showMessage( TXT_READY );
}


QPushButton *MainWindow::createButton(const char *caption, int width, int height)
{
  return createButton(caption, this);//, width, height);
}


QPushButton *MainWindow::createButton(const char *caption, QWidget *parent, int width, int height)
{
  QPushButton *btn = new QPushButton(caption, parent);
  btn->setFont( QFont( "Sans Serif", (int)(unit * height / 2), QFont::Bold ) );
  btn->setFixedHeight((int)(unit * height));
  //  btn->setFixedWidth((int)(unit * width));
  btn->setIconSize(QSize(2 * unit * height, unit * height));
  btn->setContentsMargins(0,0,0,0);
  return btn;
}


QLabel *MainWindow::createLabel(const char *caption, int width, int height)
{
  QLabel *lbl = new QLabel(caption, this);
  lbl->setFont( QFont( "Sans Serif", 
                       //(height>1)?(int)(unit * height / 2):(int)(unit * height / 2), 
                       (int)(unit * height / 2), 
                       (height>1)?QFont::Bold:QFont::Normal ) );
  lbl->setFixedHeight((int)(unit * height));
  //  lbl->setFixedWidth((int)(unit * width));
  return lbl;
}

#include <sys/time.h>
static struct timeval starttime; 
static int h = 0;
static int m = 0;
static int s = 0;
static int watchdog = 0;

void MainWindow::taskbar_update()
{
  struct timeval time;
  watchdog++;

  if(recording) {
    if((watchdog % 300 == 0) || ((camera->getQueueLength() > 1000) && (watchdog % 50 == 0))) 
      info->log("Queue length: %d (active)", camera->getQueueLength());

    gettimeofday(&time, NULL);
    
    s = time.tv_sec - starttime.tv_sec;

    h = s / (60 * 60);
    s -= h * (60 * 60);
    m = s / 60;
    s -= m * 60;
  } else {
    if((camera->getQueueLength() > 0)  && (watchdog % 300 == 0))
      info->log("Queue length: %d (passive)", camera->getQueueLength());
    gettimeofday(&starttime, NULL);
  }

  char msg[256];
  int l = camera->getQueueLength();
  sprintf(msg, TXT_TIME " %.02d:%.02d:%.02d " TXT_QUEUELENGTH " %d", h, m, s, l);
  lbl_recordtime->setText(msg);
}

void MainWindow::redraw_edge()
{
  rec_edge_counter += SPEED;
  float val = fabs(sin(rec_edge_counter));
  img_recedge->setLevel(val);
}

void MainWindow::message(char *msg)
{
  status->showMessage(msg);
  info->log("Message: %s", msg);
}

void MainWindow::clear()
{
  info->log("Clearing screen.");


  // History widgets
  for(unsigned int i = 0; i < num_history; i++) {
    img_history[i]->set_image(img_dummy);
  }

  lbl_name->setText("");
  lbl_cpr->setText("");
}

#include "aboutwindow.h"
void MainWindow::about_clicked()
{
  AboutWindow about;
  about.exec();
}

void MainWindow::clear_clicked()
{
  if(MessageBox(this, 
                TXT_ASK_CLEAR_SCREEN_TITLE, 
                TXT_ASK_CLEAR_SCREEN, 
                TYPE_YES_NO, 
                ICON_QUESTION).exec() == MSG_YES) {
    clear();
  }
}

void MainWindow::cpr_clicked()
{
  char oldcpr[256];
  char oldname[256];

  // If recording, stop recording before changingcpr
  if(recording) {
    MessageBox(this, 
               TXT_STOP_RECORDING_TITLE, 
               TXT_STOP_RECORDING, 
               TYPE_OK, 
               ICON_WARNING).exec();
    return;
  }
  info->log("Activated CPR chooser.");

  // Save CPR and name, from the labels.
  strcpy(oldname, lbl_name->text().toStdString().c_str());
  strcpy(oldcpr, lbl_cpr->text().toStdString().c_str());

  clear();

  // Create and call the CPRQueryDialog.
  CPRQueryDialog dlg(lbl_cpr, lbl_name, this, TXT_CPRDLG_TITLE, status);

  if(dlg.exec() == 0) {
    // Restore old CPR and name, in the labels. 
    lbl_name->setText(oldname);
    lbl_cpr->setText(oldcpr);
    info->log("Cancelled CPR chooser.");
  } else {
    // Change CPR camera.
    info->log("New CPR %s (old %s).", (char*)lbl_cpr->text().toStdString().c_str(), oldcpr);
    strcpy(oldname, lbl_name->text().toStdString().c_str());
    strcpy(oldcpr, lbl_cpr->text().toStdString().c_str());
    clear();
    lbl_name->setText(oldname);
    lbl_cpr->setText(oldcpr);
    camera->setCpr((char*)lbl_cpr->text().toStdString().c_str(), (char*)lbl_name->text().toStdString().c_str());
  }
}

void MainWindow::rec_clicked()
{
  QPixmap p;
  if(!recording) {
    info->log("Start recording.");
    recording = 1;
    // Start flashing the edge
    rec_edge_counter = 0.0f;
    timer->start(100);
    btn_rec->setIcon(QPixmap(PIXMAP_STOP));
    camera->start();
  } else {
    switch(MessageBox(this, 
                      TXT_ASK_SAVE_TITLE, 
                      TXT_ASK_SAVE, 
                      TYPE_YES_NO_MAYBE_CANCEL, 
                      ICON_QUESTION).exec()) {
    case MSG_YES:
      info->log("Stop recording (Said yes to save).");
      recording = 0;
      camera->stop(SAVE);
      timer->stop();
      img_recedge->setIdle(true);
      btn_rec->setIcon(QPixmap(PIXMAP_RECORD));
      break;

    case MSG_NO:
      info->log("Stop recording (Said no to save).");
      recording = 0;
      camera->stop(DELETE);
      timer->stop();
      img_recedge->setIdle(true);
      btn_rec->setIcon(QPixmap(PIXMAP_RECORD));
      break;

    case MSG_MAYBE:
      info->log("Stop recording (Said maybe to save).");
      recording = 0;
      camera->stop(LATER);
      timer->stop();
      img_recedge->setIdle(true);
      btn_rec->setIcon(QPixmap(PIXMAP_RECORD));
      break;

    case MSG_CANCEL:
      info->log("Didn't stop recording (canceled).");
      break;
    }
  }
}

void MainWindow::shoot_clicked()
{
  QPixmap p;
  //  unsigned char pixels[720*576*3];
  info->log("Snapshot (%s).", frozen?"frozen":"unfrozen");

  QImage screenshot(720, 576, QImage::Format_RGB32);

  camera->snapshot(screenshot.bits());

  QImage *image;
  for(int cnt = (num_history-1); cnt > 0; cnt--) {
    image = img_history[cnt-1]->get_image();
    img_history[cnt]->set_image(image);
  }
  img_history[0]->set_image(&screenshot);

  if(frozen) {
    camera->unfreeze();
    btn_freeze->setIcon(QPixmap(PIXMAP_FREEZE));
    btn_freeze->setChecked(false);
    frozen = false;
  }
}

void MainWindow::freeze_clicked()
{
  QPixmap p;
  if(frozen) {
    info->log("Unfreeze.");
    camera->unfreeze();
    btn_freeze->setIcon(QPixmap(PIXMAP_FREEZE));
    btn_freeze->setChecked(false);
    frozen = false;
  } else {
    info->log("Freeze.");
    camera->freeze();
    btn_freeze->setIcon(QPixmap(PIXMAP_UNFREEZE));
    btn_freeze->setChecked(true);
    frozen = true;
  }
}

void MainWindow::mute_clicked()
{
  QPixmap p;
  muted = !muted;
  if(muted) {
    btn_mute->setIcon(QPixmap(PIXMAP_MUTE));
  } else {
    btn_mute->setIcon(QPixmap(PIXMAP_UNMUTE));
  }

  camera->setMute(muted);
}