/******************************************************************************
* NOMAD -  Nonlinear Optimization for Mixed vAriables and Derivatives.        *
* Copyright (C) 2001-2004  Gilles Couture - Ecole Polytechnique,              *
*                          Charles Audet - Ecole Polytechnique,               *
*		           John Dennis - Rice University.                     *
*                                                                             *
* Author: Gilles Couture                                                      *
* École Polytechnique de Montréal - GERAD                                     *
* C.P. 6079, Succ. Centre-ville, Montréal (Québec) H3C 3A7 Canada             *
* Tel:  (514) 340-6053 x6928                                                  *
* Email: Gilles.Couture@gerad.ca                                              *
* Fax: (514) 340-5665                                                         *
*                                                                             *
* 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. You can find the              *
* GNU General Public License at:                                              *
*             http://www.gnu.org/copyleft/gpl.html                            *
*                                                                             *
* 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. *
*                                                                             *
* You can find information on the NOMAD software at:                          *
*             http://www.gerad.ca/NOMAD/                                      *
******************************************************************************/

// resultwindow.cpp -- class methods for ResultWindow.

#include <iostream>
#include <QGroupBox>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QString>
using namespace std;
#include "defines.h"
#include "graph.h"
#include "resultwindow.h"
#include "solver.h"
#include "texteditor.h"

// Public methods:
//*****************************************************************************

  // Class constructor. QWidget's constructor parameters:
  // - The parent object, which is the MainWindow object
  //   (see "mainwindow.cpp").
ResultWindow::ResultWindow(QWidget * parent)
  : QWidget(parent)
{
  // These pointers are initialized to NULL.
  filter_graph = NULL;
  results_edit = NULL;

  // A 1x1 grid is created. Its parent is "this" object (the "main" widget).
  grid = new QGridLayout(this);

  /*******************/
  /* Problem results */
  /*******************/

  // Section title.
  QGroupBox * results_box = new QGroupBox("Problem results", this);
  // results_box->setPaletteBackgroundColor(Qt::gray);
  results_box->setBackgroundRole(QPalette::Background);
  results_box->setAlignment(Qt::AlignHCenter);
  results_box->setFlat(true);
  results_box->setMinimumHeight(20);
  results_box->setMaximumHeight(20);
  // grid->addMultiCellWidget(results_box, 0, 0, 0, 3);
  grid->addWidget(results_box, 0, 0, 1, 4);

  // On the second row we put two text editors where the best point found by
  // Nomad and its truth value will be displayed.
  grid->addWidget(new QLabel("Best point:", this), 1, 0);
  point_coord = new QLineEdit(this);
  point_coord->setReadOnly(TRUE);
  point_coord->setFrame(FALSE);
  grid->addWidget(point_coord, 1, 1);
  grid->addWidget(new QLabel("Objective function\n"
			     "value at best point:", this), 1, 2);
  function_value = new QLineEdit(this);
  function_value->setReadOnly(TRUE);
  function_value->setFrame(FALSE);
  grid->addWidget(function_value, 1, 3);

  // Third row.
  grid->addWidget(new QLabel("New truth\n"
			     "evaluations:", this), 2, 0);
  nteval = new QLineEdit(this);
  nteval->setReadOnly(TRUE);
  nteval->setFrame(FALSE);
  grid->addWidget(nteval, 2, 1);
  grid->addWidget(new QLabel("Temporary/permanent\n"
			     "cache hits:", this), 2, 2);
  ceval = new QLineEdit(this);
  ceval->setReadOnly(TRUE);
  ceval->setFrame(FALSE);
  grid->addWidget(ceval, 2, 3);

  // 4th row.
  grid->addWidget(new QLabel("Termination:", this), 3, 0);
  criterion = new QLineEdit(this);
  criterion->setReadOnly(true);
  criterion->setFrame(false);
  grid->addWidget(criterion, 3, 1);

  /****************/
  /* Output graph */
  /****************/

  // Section title for the output graph.
  QGroupBox * graph_box = new QGroupBox("Output graph", this);
  // graph_box->setPaletteBackgroundColor(Qt::gray);
  graph_box->setBackgroundRole(QPalette::Background);
  graph_box->setAlignment(Qt::AlignHCenter);
  graph_box->setFlat(true);
  graph_box->setMinimumHeight(20);
  graph_box->setMaximumHeight(20);
  // grid->addMultiCellWidget(graph_box, 4, 4, 0, 3);
  grid->addWidget(graph_box, 4, 0, 1, 4);

  // The output graph is shown, displaying the objective function value
  // according to the number of truth evaluations.
  graph = new Graph("LIBRARY/graph.txt", "Number of function evaluations ",
  		    "Objective function value ", false, this);
  // grid->addMultiCellWidget(graph, 5, 5, 0, 3);
  grid->addWidget(graph, 5, 0, 1, 4);
  grid->setRowMinimumHeight(5, 250);

  /****************/
  /* Filter graph */
  /****************/

  // Section title for the filter graph.
  QGroupBox * filter_graph_box = new QGroupBox("Filter graph", this);
  // filter_graph_box->setPaletteBackgroundColor(Qt::gray);
  filter_graph_box->setBackgroundRole(QPalette::Background);
  filter_graph_box->setAlignment(Qt::AlignHCenter);
  filter_graph_box->setFlat(true);
  filter_graph_box->setMinimumHeight(20);
  filter_graph_box->setMaximumHeight(20);
  // grid->addMultiCellWidget(filter_graph_box, 6, 6, 0, 3);
  grid->addWidget(filter_graph_box, 6, 0, 1, 4);

  // The filter graph is shown, displaying the objective function value
  // according to the number of truth evaluations.
  filter_graph = new Graph("LIBRARY/filter_graph.txt", "h(x) ", "f(x) ",
			   true, this);
  // grid->addMultiCellWidget(filter_graph, 7, 7, 0, 3);
  grid->addWidget(filter_graph, 7, 0, 1, 4);
  grid->setRowMinimumHeight(7, 250);

  // Columns 1 and 3 are given a minimum width.
  grid->setColumnMinimumWidth(1, 100);
  grid->setColumnMinimumWidth(3, 100);
  // We tell the application to resize itself.
  resize(minimumSizeHint());
}

// Destructor. All QT child objects are destroyed automatically.
ResultWindow::~ResultWindow()
{
  // The graphs are destroyed.
  delete filter_graph;
  delete graph;
  delete results_edit;
}

// This method clears the problem outputs.
void ResultWindow::clearOutputs()
{
  // The GUI's outputs are reset.
  ceval->clear();
  criterion->clear();
  function_value->clear();
  point_coord->clear();
  nteval->clear();
  // The graphs are erased.
  if (filter_graph != NULL)
    filter_graph->setOutput(false);
  graph->setOutput(false);
}

// The run is finished, it's time to display the results.
void ResultWindow::outputSolution(const int dimension, const int gen_cons_nb,
				  Solver & solver)
{
  // Some local variables we'll need.
  QString qs, qs_buffer;
  int i;

  // Once the problem is solved, we have to write the correct data in the
  // output window, and to draw the graph.

  // In the next block the best iterate's truth value is written in the text
  // editor 'function_value', and the best iterate's coordinates are written in
  // 'point_coord'.
  double truth = solver.getTruth();
  // If 'truth' is infinite, No feasible point was found in the run.
  if (truth == INFINIT)
    {
      point_coord->setText("No feasible point was found");
      function_value->setText("N/A");
    }
  else
    {
      // "coord" will be the best point found, in unscaled coordinates.
      double * coord = new double[dimension];
      // 'coord' is initialized.
      for (i = 0; i < dimension; i++)
	coord[i] = 0.0;
      // The 'coord' array is sent to Solver: it will be filled by the
      // unscaled values of the best point found during the run.
      solver.fillWithBestPoint(coord);

      // The 'coord' array is copied into a QString object, 'qs'.
      qs.append("(");
      for (i = 0; i < dimension; i++)
	{
	  qs.append(qs_buffer.setNum(coord[i], 'g', 3));
	  if (i < (dimension - 1))
	    qs.append(", ");
	  else
	    qs.append(")");
	}
      // The strings are built, and written in the text editors.
      point_coord->setText(qs);
      function_value->setText(qs_buffer.setNum(truth, 'g', 6));

      // The memory is freed.
      delete [] coord;
    }

  // We output the number of new truth evaluations in the text editor "nteval".
  int new_truth_eval = solver.returnNewTruthEvaluations();
  nteval->setText(qs_buffer.setNum(new_truth_eval));
  // We output the number of cache evaluations in the text editor "ceval". The
  // format is 'temporary cache hits / permanent cache hits'.
  qs.setNum(solver.returnTempCacheHits());
  qs.append(" / ");
  qs_buffer.setNum(solver.returnPermCacheHits());
  qs.append(qs_buffer);
  ceval->setText(qs);

  // We output the activated termination criterion in the 'criterion'
  // 'QLineEdit' object.
  switch(solver.returnTerminationFlag())
    {
      case 1  : criterion->setText("Poll size");
                break;
      case 2  : criterion->setText("Function evaluations");
                break;
      case 3  : criterion->setText("Consecutive failures");
                break;
      case 4  : criterion->setText("Truth evaluations");
                break;
      case 5  : criterion->setText("Iteration number");
	        break;
      default : cerr << "No termination criterion activated!\n";
    }

  // Finally the graphs are drawn.
  graph->setOutput(true);
  bool gen_cons = (gen_cons_nb > 0) ? true : false;
  filter_graph->setOutput(gen_cons);

  // The result window is shown.
  show();
}

// This method lets the user view the current results file.
void ResultWindow::viewResults(const char * file)
{
  QString results_file(file);
  // The text editor is created.
  if (results_edit == NULL)
    results_edit = new TextEditor(results_file);
  // The results file is loaded in the text editor.
  results_edit->load(results_file);
  // The text editor is shown.
  results_edit->show();
}
