/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
 *            mainwindow.cc
 *
 *  Wed Sep 17 09:41:09 CEST 2008
 *  Copyright 2008 Bent Bisballe Nyeng
 *  deva@aasimon.org
 ****************************************************************************/

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

#include <QApplication>
#include <QDomDocument>
#include <QDomNodeList>
#include <QDomNode>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QScrollArea>
#include <QSettings>
#include <QStatusBar>
#include <QMessageBox>
#include <QToolBar>
#include <QAction>
#include <QEvent>
#include <QCloseEvent>
#include <QLabel>

#include "macrodrawer.h"
#include "macrowindow.h"

#include "debug.h"

class Dbg : public QLabel {
public:
  Dbg() {
    setText("dbg");
  }

  void mousePressEvent(QMouseEvent *)
  {
    dbg_toggle();
  }
};

MainWindow::MainWindow(QString cpr, QString templ, QString host,
                       quint16 port, QString user)
  : QMainWindow(0, Qt::WindowContextHelpButtonHint),
    netcom(host, port)
{
  isStored = false;

  header = NULL;

  this->cpr = cpr;
  this->user = user;

  setWindowTitle("Pracro - " + cpr);
  setWindowIcon(QIcon(":/icons/icon.png"));

  QStatusBar *status = statusBar();
  status->addPermanentWidget(new QLabel("Pracro v."VERSION));
  status->addPermanentWidget(new Dbg());

  QToolBar *toolbar = addToolBar("controls");
  toolbar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
  QAction *close_commit = toolbar->addAction("Close and commit");
  close_commit->setIcon(QPixmap(":icons/icon_close_commit.png"));

  QAction *close_no_commit = toolbar->addAction("Close no commit");
  close_no_commit->setIcon(QPixmap(":icons/icon_close_no_commit.png"));
  /*
  QAction *close_discard = toolbar->addAction("Close discard");
  close_discard->setIcon(QPixmap(":icons/icon_discard.png"));
  connect(close_discard, SIGNAL(triggered()), this, SLOT(closeDiscard()));
  */
  toolbar->addSeparator();

  QAction *show_sessions = toolbar->addAction("Show sessions");
  show_sessions->setIcon(QPixmap(":icons/icon_current_sessions.png"));

  connect(close_commit, SIGNAL(triggered()), this, SLOT(closeCommit()));
  connect(close_no_commit, SIGNAL(triggered()), this, SLOT(closeNoCommit()));
  connect(show_sessions, SIGNAL(triggered()), this, SLOT(showSessions()));

  QScrollArea *s = new QScrollArea();
  setCentralWidget(s);
  w = new QWidget();
  s->setWidget(w);
  s->setWidgetResizable(true);

  w->setLayout(new QVBoxLayout());
  this->templ = templ;

  setStatusBar(status);

  init();

  if(sessions.isEmpty()) {
    show_sessions->setEnabled(false);
  }
}

MainWindow::~MainWindow()
{
}

void MainWindow::closeCommit()
{
  netcom.commit();
  sessions.remove(cpr);
  isStored = true;
  close();
}

void MainWindow::closeNoCommit()
{
  QMessageBox::information(this,
   "Closing without commit",
   "This session will be stored on this computer only."
   " To reopen it at a later time, simply open the same patient again.");
  sessions.add(cpr, user, netcom.sessionid);
  isStored = true;
  close();
}

void MainWindow::closeDiscard()
{
  if(QMessageBox::question(this,
     "Discard",
     "This session will <strong>NOT</strong> be stored in the journal.<br/>"
     "Are you sure you want to continue?",
     QMessageBox::Yes | QMessageBox::No)
     == QMessageBox::Yes) {
    netcom.discard();
    sessions.remove(cpr);
    isStored = true;
    close();
  }
}

void MainWindow::showSessions()
{
  sessions.show();
}

extern QWidget *viewer;
//#include <QApplication>
void MainWindow::closeEvent(QCloseEvent *event)
{
  if(isStored || QMessageBox::question(this,
     "Discard",
     "This session will <strong>NOT</strong> be stored in the journal.<br/>"
     "Are you sure you want to continue?",
     QMessageBox::Yes | QMessageBox::No)
     == QMessageBox::Yes) {
    if(!isStored) {
      netcom.discard();
      sessions.remove(cpr);
    }

    QSettings settings("Aasimon.org", "Pracro");

    settings.beginGroup("MainWindow");
    settings.setValue("size", size());
    settings.setValue("pos", pos());
    settings.setValue(QString("sessions"), sessions.toVariant());
    settings.endGroup();

    event->accept();
    if(viewer) viewer->close();
    dbg_free();
  } else {
    event->ignore();
  }
}

void MainWindow::init()
{
  QSettings settings("Aasimon.org", "Pracro");

  settings.beginGroup("MainWindow");
  resize(settings.value("size", QSize(700, 800)).toSize());
  move(settings.value("pos", QPoint(0, 0)).toPoint());
  sessions.fromVariant(settings.value("sessions"));
  settings.endGroup();

  netcom.patientid = cpr;
  netcom.user = user;

  if(sessions.contains(cpr)) {
    netcom.sessionid = sessions.getSessionID(cpr);
    if(sessions.getUser(cpr) != user) {
      // What to do? We are running an old session with a new user!
    }
  }

  netcom.initConnection();

  initialising = true;
  update();
  initialising = false;
}

void MainWindow::updateTemplateHeaders(QDomNode templatenode)
{
  QDomElement template_elem = templatenode.toElement();
  QString template_title = template_elem.attribute("title");
  QString template_name = template_elem.attribute("name");

  if(!header) {
    header = new QLabel();
    header->setText(template_title);
    QFont headerfont = header->font();
    headerfont.setBold(true);
    headerfont.setPointSize(headerfont.pointSize() + 4);
    header->setFont(headerfont);
    header->setAlignment(Qt::AlignHCenter);
    w->layout()->addWidget(header);
  }

  statusBar()->showMessage(template_title + " (" + template_name + 
                           ") - SessionID: " + netcom.sessionid);
}

void MainWindow::update()
{
  QDomDocument xml_doc = netcom.send(templ);

  QDomNodeList templates = xml_doc.documentElement().childNodes();
  // There can be only one! (Swush, flomp)
  QDomNode templatenode = templates.at(0);
  
  if(templatenode.toElement().tagName() == "error") {
    QMessageBox::critical(this, "Error",
                          templatenode.toElement().text());
    return;
  }


  updateTemplateHeaders(templatenode);

  QDomNodeList macronodes = templatenode.childNodes();
  for(int j = 0; j < macronodes.count(); j++) {

    QDomNode macronode = macronodes.at(j);
    QDomElement macroelement = macronode.toElement();

    //    printf("%s\n", macroelement.tagName().toStdString().c_str());

    QString macroname = macroelement.attribute("name");

    bool found = false;
    Macros::iterator i = macros.begin();
    while(i != macros.end()) {
      if(i->name == macroname) found |= true;
      i++;
    }

    // if(found == false || macroelement.hasAttribute("header")) {
    if(found == false || macroelement.tagName() == "header") {
      QString num;
      num.sprintf("%04d", j);
      Macro macro(macronode);
      macros[num + macro.name] = macro;
    }

    if(found) {

      Macros::iterator i = macros.begin();
      while(i != macros.end()) {
        if(i->name == macroname && macroname != "") {
          i->update(macronode);
        }
        i++;
      }
            
    }
  }

  {
    Macros::iterator i = macros.begin();
    while(i != macros.end()) {
      Macro &macro = i.value();
      macro.init((QBoxLayout*)w->layout(), macros, initialising, netcom, templ);
      if(macro.window != NULL) {
        // Remove old connection (if any), to avoid multiple connections.
        disconnect(macro.window, SIGNAL(updateOnCommit()),
                   this, SLOT(update()));
      
        connect(macro.window, SIGNAL(updateOnCommit()), this, SLOT(update()));
      }
      i++;
    }
  }

  // Make sure that all macros will collapse when a new one is expanded.
  Macros::iterator i = macros.begin();
  while(i != macros.end()) {
    Macro &_m1 = i.value();
    MacroWindow *m1 = _m1.window;
    
    Macros::iterator j = macros.begin();
    while(j != macros.end()) {
      Macro &_m2 = j.value();
      MacroWindow *m2 = _m2.window;

      if(m1 && m2 && m1 != m2 && _m2.isstatic == false) {
        // Remove old connection (if any), to avoid multiple connections.
        disconnect(m1, SIGNAL(expanding()), m2, SLOT(collapseWrapper()));

        connect(m1, SIGNAL(expanding()), m2, SLOT(collapseWrapper()));
      }

      j++;
    }

    i++;
  }
}