/*-------------------------------------------------------------------------------------*/
/*  NOMAD - Nonsmooth Optimization by Mesh Adaptive Direct search - version 3.0.0      */
/*                                                                                     */
/*  Copyright (C) 2001-2008  Mark Abramson        - the Boeing Company, Seattle        */
/*                           Charles Audet        - Ecole Polytechnique, Montreal      */
/*                           Gilles Couture       - Ecole Polytechnique, Montreal      */
/*                           John Dennis          - Rice University, Houston           */
/*                           Sebastien Le Digabel - Ecole Polytechnique, Montreal      */
/*                                                                                     */
/*  funded in part by AFOSR and Exxon Mobil                                            */
/*                                                                                     */
/*  Author: Sebastien Le Digabel                                                       */
/*                                                                                     */
/*  Contact information:                                                               */
/*    Ecole Polytechnique de Montreal - GERAD                                          */
/*    C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada                  */
/*    e-mail: Sebastien.Le.Digabel@gerad.ca                                            */
/*    phone : 1-514-340-6053 #6673                                                     */
/*    fax   : 1-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, either version 3 of the License, or (at your option) any later         */
/*  version.                                                                           */
/*                                                                                     */
/*  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, see <http://www.gnu.org/licenses/>.                               */
/*                                                                                     */
/*  You can find information on the NOMAD software at www.gerad.ca/nomad               */
/*-------------------------------------------------------------------------------------*/
#include "Cache_File_Point.hpp"
#include "Eval_Point.hpp"
using namespace std;

/*-----------------------------------*/
/*   static members initialization   */
/*-----------------------------------*/
#ifdef DEBUG
int Cache_File_Point::_cardinality     = 0;
int Cache_File_Point::_max_cardinality = 0;
#endif

/*---------------------------------------------------------------------*/
/*                             constructor 1                           */
/*---------------------------------------------------------------------*/
Cache_File_Point::Cache_File_Point ( void ) : _n         (0   ) ,
					      _m         (0   ) ,
					      _m_def     (0   ) ,
					      _eval_ok   (0   ) ,
					      _coords    (NULL) ,
					      _bbo_def   (NULL) ,
					      _bbo_index (NULL)   {
#ifdef DEBUG
  ++Cache_File_Point::_cardinality;
  if ( Cache_File_Point::_cardinality > Cache_File_Point::_max_cardinality )
    ++Cache_File_Point::_max_cardinality;
#endif
}

/*---------------------------------------------------------------------*/
/*                             constructor 2                           */
/*---------------------------------------------------------------------*/
Cache_File_Point::Cache_File_Point ( const Eval_Point & x ) :
  _n         ( x.size()                 ) ,
  _m         ( 0                        ) ,
  _m_def     ( 0                        ) ,
  _eval_ok   ( (x.is_eval_ok()) ? 1 : 0 ) ,
  _coords    ( NULL                     ) ,
  _bbo_def   ( NULL                     ) ,
  _bbo_index ( NULL                     )   {

  int i;
  
  // inputs:
  if ( _n > 0 ) {
    _coords = new double [_n];
    for ( i = 0 ; i < _n ; ++i )
      _coords[i] = x[i].value();
  }
  else
    _n = 0;

  // outputs:
  const Point & bbo = x.get_bb_outputs();
  _m = bbo.size();
  if ( _m > 0 ) {

    vector<double> vd;
    vector<int>    vi;

    for ( i = 0 ; i < _m ; ++i )
      if ( bbo[i].is_defined() ) {
	vd.push_back ( bbo[i].value() );
	vi.push_back ( i              );
      }

    _m_def = static_cast<int> ( vd.size() );
    if ( _m_def > 0 ) {
      _bbo_def   = new double [_m_def];
      _bbo_index = new int    [_m_def];
      for ( i = 0 ; i < _m_def ; ++i ) {
	_bbo_def  [i] = vd[i];
	_bbo_index[i] = vi[i];
      }
    }

  }
  else
    _m = 0;

#ifdef DEBUG
  ++Cache_File_Point::_cardinality;
  if ( Cache_File_Point::_cardinality > Cache_File_Point::_max_cardinality )
    ++Cache_File_Point::_max_cardinality;
#endif
}

/*---------------------------------------------------------------------*/
/*                              destructor                             */
/*---------------------------------------------------------------------*/
Cache_File_Point::~Cache_File_Point ( void ) {
  delete [] _coords;
  delete [] _bbo_def;
  delete [] _bbo_index;
#ifdef DEBUG
  --Cache_File_Point::_cardinality;
#endif
}

/*---------------------------------------------------------------------*/
/*                             get_coord(i)                            */
/*---------------------------------------------------------------------*/
double Cache_File_Point::get_coord ( int i ) const {
  if ( !_coords || i < 0 || i >= _n )
    throw NOMAD::Exception ( __FILE__ , __LINE__ ,
			     "bad access in Cache_File_Point::get_coord()" );
  return _coords[i];
}

/*---------------------------------------------------------------------*/
/*                               get_bbo                               */
/*---------------------------------------------------------------------*/
const Point Cache_File_Point::get_bbo ( void  ) const {
  Point bbo (_m);
  for ( int i = 0 ; i < _m_def ; ++i )
    bbo [ _bbo_index[i] ] = _bbo_def[i];
  return bbo;
}

/*---------------------------------------------------------*/
/*                          reset                          */
/*---------------------------------------------------------*/
void Cache_File_Point::reset ( void ) {

  _n = _m = _m_def = _eval_ok = 0;

  delete [] _coords;
  delete [] _bbo_def;
  delete [] _bbo_index;

  _coords    = NULL;
  _bbo_def   = NULL;
  _bbo_index = NULL;
}

/*---------------------------------------------------------*/
/*                   write in binary file                  */
/*---------------------------------------------------------*/
bool Cache_File_Point::write ( ofstream & out ) const {

  // do nothing if no point:
  if ( _n <= 0 )
    return true;

  // 1. _eval_ok:
  out.write ( (char *) &_eval_ok   , sizeof(_eval_ok)      );

  // 2. _n:
  out.write ( (char *) &_n         , sizeof(_n)            );

  // 3. _m:
  out.write ( (char *) &_m         , sizeof(_m)            );

  // 4. _m_def:
  out.write ( (char *) &_m_def     , sizeof(_m_def)        );

  // 5. _coords:
  out.write ( (char *)  _coords    , _n*sizeof(double)     );

  if ( _m_def > 0 ) {

    // 6. _bbo_def:
    out.write ( (char *)  _bbo_def   , _m_def*sizeof(double) );

    // 7. _bbo_index:
    out.write ( (char *)  _bbo_index , _m_def*sizeof(int)    );
  }

  return !out.fail();
}

/*---------------------------------------------------------*/
/*                    read in binary file                  */
/*---------------------------------------------------------*/
bool Cache_File_Point::read ( ifstream & in ) {

  reset();

  // 1. _eval_ok:
  in.read ( (char *) &_eval_ok , sizeof(_eval_ok) );
  if ( in.fail() || ( _eval_ok != 0 && _eval_ok != 1 ) )
    return false;

  // 2. _n:
  in.read ( (char *) &_n , sizeof(_n) );
  if ( in.fail() || _n <= 0 ) {
    _n = 0;
    return false;
  }

  // 3. _m:
  in.read ( (char *) &_m , sizeof(_m) );
  if ( in.fail() || _m < 0 ) {
    _n = _m = 0;
    return false;
  }

  // 4. _m_def:
  in.read ( (char *) &_m_def , sizeof(_m_def) );
  if ( in.fail() || _m_def < 0 ) {
    _m_def = _n = _m = 0;
    return false;
  }

  // 5. _coords:
  _coords = new double [_n];
  in.read ( (char *) _coords , _n*sizeof(double) );
  if ( in.fail() ) {
    reset();
    return false;
  }

  if ( _m_def > 0 ) {

    // 6. _bb_def:
    _bbo_def = new double [_m_def];
    in.read ( (char *) _bbo_def , _m_def*sizeof(double) );
    if ( in.fail() ) {
      reset();
      return false;
    }
  
    // 7. _bbo_index:
    _bbo_index = new int [_m_def];
    in.read ( (char *) _bbo_index , _m_def*sizeof(int) );
    if ( in.fail() ) {
      reset();
      return false;
    }
  }

  return true;
}

/*---------------------------------------------------------*/
/*                         display                         */
/*---------------------------------------------------------*/
void Cache_File_Point::display ( ostream & out ) const {
  out << "\tn      : " << _n     << endl
      << "\tm      : " << _m     << endl
      << "\tm_def  : " << _m_def << endl;
  int i;
  if ( _n > 0 ) {
    out << "\tcoords    : ( ";
    for ( i = 0 ; i < _n ; ++i )
      out << _coords[i] << " ";
    out << ")\n";
  }
  if ( _m_def > 0 ) {
    out << "\tbbo_def   : [ ";
    for ( i = 0 ; i < _m_def ; ++i )
      out << _bbo_def[i] << " ";
    out << "]" << endl;
    out << "\tbbo_index : [ ";
    for ( i = 0 ; i < _m_def ; ++i )
      out << _bbo_index[i] << " ";
    out << "]" << endl;
  }
}
