/*-------------------------------------------------------------------------------------*/
/*  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               */
/*-------------------------------------------------------------------------------------*/

//  to browse the cache:
//  ---------------------
//    const Eval_Point * cur = cache.begin();
//    while (cur) {
//      ...
//      cur = cache.next();
//    }

#ifndef __CACHE__
#define __CACHE__

#include "Cache_File_Point.hpp"
#include "Cache_Point.hpp"
#include "Clock.hpp"


// the Cache class:
class Cache : private Uncopyable {

private:
  
  // static list of locked files:
  static std::set<std::string> _locked_files;

  std::set<Cache_Point> _cache1;          // points read in the (optional) initial cache file
  std::set<Cache_Point> _cache2;          // points of the cache to write in the cache file
  std::set<Cache_Point> _cache3;          // points of the cache already saved in the file

  std::string           _locked_file;     // cache file that is currently in use for load/save
                                          // (this file is locked)

  std::ostream        & _out;             // display
  int                   _display_degree;

  bool                  _surrogate;       // if the cache contains surrogate eval points

  // iterator to browse the cache with begin() and next():
  mutable std::set<Cache_Point>::const_iterator _it;

  // read method:
  bool read_points_from_cache_file ( std::ifstream & in              ,
				     const int     * p_nb_bb_outputs   );

  // locking process:
  bool is_locked ( const std::string & file_name );
  bool lock      ( const std::string & file_name );
  void unlock    ( void                          );

  // update a point already in cache from another
  // point with the same coordinates:
  void update ( Eval_Point & cache_x , const Eval_Point & x ) const;

  // search in cache (private version):
  const Eval_Point * find ( const Eval_Point                      * x           ,
			    std::set<Cache_Point>::const_iterator & it          ,
			    cache_index_type                      & cache_index   ) const;

  /*------------------------------------------------------------------*/

public:

  // constructor:
  explicit Cache ( std::ostream & out            = std::cout ,
		   int            display_degree = 0         ,
		   bool           surrogate      = false       ) :
    _out            (out           ) ,
    _display_degree (display_degree) ,
    _surrogate      (surrogate     )   {};
  
  // destructor:
  ~Cache ( void ) { clear(); }

  // sizeof:
  int size_of ( void ) const;

  // number of points:
  int size ( void ) const {
    return static_cast<int>(_cache1.size() + _cache2.size() + _cache3.size());
  }

  // transforms a const Eval_Point & into a Eval_Point &:
  static Eval_Point & get_modifiable_point ( const Eval_Point & x ) {
    return const_cast<Eval_Point&> (x);
  }

  // display:
  void display ( std::ostream & out ) const;
  void display ( void               ) const { display(_out); }

  // other methods:
  const Eval_Point * find      ( const Eval_Point  * x         ) const;

  const Eval_Point * begin     ( void                          ) const;
  const Eval_Point * next      ( void                          ) const;

  bool               erase     ( const Eval_Point  * x         );
  void               insert    ( const Eval_Point  * x         );
  void               insert    ( Cache             & c         );
  bool               load      ( const std::string & file_name               ,
				 const         int * p_nb_bb_outputs = NULL    );
  bool               save      ( bool                overwrite       = false   );
  void               clear     ( void                                          );
};

// display:
inline std::ostream & operator << ( std::ostream & out , const Cache & c ) {
  c.display(out); return out;
}

#endif
