#include "Panel_monitors.h"

#include "Path.h"
#include "Model.h"
#include "Model_kit.h"
#include "Monitor.h"
#include "Simulator.h"
#include "Project.h"
#include "Collect_scalar.h"
#include "Panel_graph_plot.h"
#include "Panel_gnuplot_graph.h"
#include "Main_window_user.h"

#include "Log.h"

#include <QCheckBox>
#include <QComboBox>
#include <QSpinBox>
#include <QHeaderView>

namespace MM
{

Panel_monitors::
Panel_monitors ()
:
    Panel ("Monitor", "middle"),
    update_flag_(true)
{
    setupUi (this);

    listWidget->hide();
    frame->hide();

    tableWidget->setColumnWidth (0,20);
    tableWidget->setColumnWidth (1,65);
    tableWidget->setColumnWidth (2,250);


    toolButton_plot->
        setIcon (QIcon((Path::icon() + "flush_camera.png").c_str()));
    //connect(toolButton_flush_camera,    SIGNAL(clicked()), 
    //        this,                       SLOT(flush_camera()));

    connect(toolButton_make,            SIGNAL(clicked()), 
            this,                       SLOT(make_monitor()));

    connect(toolButton_plot,             SIGNAL(clicked()), 
            this,                       SLOT(show_plot()));

    connect(&qtimer_,                   SIGNAL(timeout()), 
            //this,                       SLOT(renew_values()));
            this,                       SLOT(update_ready()));
    qtimer_.start(200);

}

void Panel_monitors::
showEvent (QShowEvent * /*event*/)
{
    QList<int> sizes = splitter->sizes ();
    int sizes_sum = sizes[0] + sizes[1];
    sizes[0] = 3. / 10. * sizes_sum;
    sizes[1] = sizes_sum - sizes[0];
    splitter->setSizes (sizes);

    renew (Model_event::Monitors_changed);
    renew (Model_event::Conformation_changed);
}

void Panel_monitors::
renew_current_model (Model &)
{
    renew (Model_event::Monitors_changed);
    renew (Model_event::Conformation_changed);
}

void Panel_monitors::
renew (Model_event::Hint hint)
{
    try
    {
        static bool reinter_flag = false;
        if (reinter_flag)
        {
            log() << "Panel_monitors::  reinter";
            return;
        }
        reinter_flag = true;

        if (hint == Model_event::Monitors_changed)
        {
            tableWidget->setRowCount (0);
            tableWidget->horizontalHeader()->setMaximumSize (10000, 20);

            if (Project::singleton().model_count() == 0)
            {
                reinter_flag = false;
                return;
            }

            Simulator & simulator = model().kit().simulator();
            int         count     = simulator.monitor_count();

            for (int i=0;  i<count;  ++i)
            {
                Monitor & monitor = simulator.monitor (i);

                int row = tableWidget->rowCount();
                tableWidget->insertRow (row);

                QCheckBox * checkBox = new QCheckBox;
                tableWidget->setCellWidget (row, 0, checkBox);
                checkBox->setCheckState (monitor.is_on() ? Qt::Checked : Qt::Unchecked);
                connect(checkBox,   SIGNAL(stateChanged(int)), 
                        this,       SLOT(turn_on (int)));

                QSpinBox * spinBox = new QSpinBox;
                tableWidget->setCellWidget (row, 1, spinBox);
                spinBox->setMinimum (1);
                spinBox->setMaximum (1000000);
                spinBox->setSingleStep (monitor.observation_period());
                spinBox->setValue      (monitor.observation_period());
                connect(spinBox,    SIGNAL(valueChanged(int)), 
                        this,       SLOT(set_observation_period (int)));
                spinBox->update();

                tableWidget->setItem (row, 2, new QTableWidgetItem (monitor.title()));
                tableWidget->setItem (row, 3, new QTableWidgetItem ());
                tableWidget->setItem (row, 4, new QTableWidgetItem ());

                //QComboBox * comboBox = new QComboBox;
                //comboBox->addItem ("Common");
                //comboBox->addItem ("Model");
                //comboBox->addItem ("Simulator");
                //comboBox->addItem ("-");
                //if      (monitor.in() == "Common")      comboBox->setCurrentIndex (0);
                //else if (monitor.in() == "Model")       comboBox->setCurrentIndex (1);
                //else if (monitor.in() == "Simulator")   comboBox->setCurrentIndex (2);
                //else                                    comboBox->setCurrentIndex (3);
                //tableWidget->setCellWidget (row, 5, comboBox);
            
                //tableWidget->resizeRowToContents (row);
                tableWidget->setRowHeight (row, 18);
            }
        }
        //else if (hint == Model_event::Conformation_changed)
        {
            renew_values ();
        }

        reinter_flag = false;
    }
    catch(...)
    {
        to_user().fatal_error("in Panel_monitors::renew ()");
    }
}

void Panel_monitors::
update_ready ()
{
    update_flag_ = true;
}

void Panel_monitors::
renew_values ()
{
    if (Main_window_user::clock_performed())
        return;

    try
    {
        if (!update_flag_)
            return;

    try
    {
        if (Project::singleton().model_count() == 0)
            return;
    }
    catch(...)
    {
        to_user().error("model_count in Panel_monitors::renew_values ()");
    }

        Simulator & simulator = model().kit().simulator();
        int count = simulator.monitor_count();

        double elapsed = timer_.elapsed();
        if (elapsed < 0.5)
            return;

        tableWidget->setUpdatesEnabled(false);
        tableWidget->blockSignals (true);

    try
    {
        for (int i=0;  i<count;  ++i)
        {
            double value;
            double average;

            //try
            //{
            Collect_scalar * monitor = dynamic_cast<Collect_scalar *>
                (&simulator.monitor (i));
            //}
            //catch(...)
            //{
            //    to_user().fatal_error("cast monitor in Panel_monitors::renew_values ()");
            //}
            
            try
            {
            if (monitor == 0)               continue;
            if (!monitor->has_values())     continue;
            }
            catch(...)
            {
                to_user().fatal_error("monitor has_values in Panel_monitors::renew_values ()");
            }

            try
            {
            /*double*/ value   = monitor->last_value();
            }
            catch(...)
            {
                to_user().fatal_error("monitor last_value in Panel_monitors::renew_values ()");
            }
            try
            {
            /*double*/ average = monitor->average();
            }
            catch(...)
            {
                to_user().fatal_error("monitor average in Panel_monitors::renew_values ()");
            }


            try
            {
            QTableWidgetItem * item = tableWidget->item (i, 3);
            if (item == 0)
            {
                to_user().error("item3==0 in Panel_monitors::renew_values ()");
                return;
            }
            item->setText (QString::number(value));
            
            item = tableWidget->item (i, 4);
            if (item == 0)
            {
                to_user().error("item4==0 in Panel_monitors::renew_values ()");
                return;
            }
            item->setText (QString::number(average));
            }
            catch(...)
            {
                to_user().fatal_error("item in Panel_monitors::renew_values ()");
            }
        }    
    }
    catch(...)
    {
        to_user().fatal_error("set values in Panel_monitors::renew_values ()");
    }

        tableWidget->blockSignals (false);
        tableWidget->setUpdatesEnabled(true);
    }
    catch(...)
    {
        to_user().fatal_error("get simulator in Panel_monitors::renew_values ()");
    }

    try
    {
        tableWidget->update();
        timer_.restart();

        update_flag_ = false;
    }
    catch(...)
    {
        to_user().fatal_error("tableWidget->update in Panel_monitors::renew_values ()");
    }
}

void Panel_monitors::
make_monitor ()
{
    QList<QListWidgetItem *> list = listWidget->selectedItems ();
    if (list.isEmpty())
        return;

    //QTableWidgetItem * item;
    int row = tableWidget->rowCount();
    tableWidget->insertRow (row);

    QCheckBox * checkBox = new QCheckBox;
    tableWidget->setCellWidget (row, 0, checkBox);

    QSpinBox * spinBox = new QSpinBox;
    spinBox->setMinimum (1);
    spinBox->setMaximum (1000000);
    spinBox->setSingleStep (1000);
    tableWidget->setCellWidget (row, 1, spinBox);

    QString type_name = list[0]->text();
    //item = tableWidget->item (row, 1);
    tableWidget->setItem (row, 2, new QTableWidgetItem (type_name));

    QComboBox * comboBox = new QComboBox;
    comboBox->addItem ("Common");
    comboBox->addItem ("Model");
    comboBox->addItem ("Simulator");
    tableWidget->setCellWidget (row, 5, comboBox);
    
    tableWidget->resizeRowToContents (row);
}

void Panel_monitors::
show_plot ()
{
    Panel_graph_plot::singleton()->popup();
    //Panel_gnuplot_graph::singleton()->popup();
}

void Panel_monitors::
turn_on (int)
{
    Simulator & simulator = model().kit().simulator();
    int         count     = simulator.monitor_count();

    for (int i=0;  i<count;  ++i)
    {
        Monitor & monitor = simulator.monitor (i);
        QCheckBox * checkBox = (QCheckBox *)tableWidget->cellWidget(i, 0);
        bool on = checkBox->checkState () == Qt::Checked;
        monitor.turn_on (on);
    }
}

void Panel_monitors::
set_observation_period (int p)
{
    Simulator & simulator = model().kit().simulator();
    int         count     = simulator.monitor_count();

    for (int i=0;  i<count;  ++i)
    {
        Monitor & monitor = simulator.monitor (i);
        QSpinBox * spinBox = (QSpinBox *)tableWidget->cellWidget(i, 1);
        int p = spinBox->value ();
        monitor.set_observation_period (p);
    }
}

}//MM
