/*-----------------------------------------------------*/
bool NOMAD::Cache::erase ( const NOMAD::Eval_Point & x )
{
    // check the eval types:
    if ( x.get_eval_type() != _eval_type )
        throw NOMAD::Cache::Cache_Error ( "Cache.cpp" , __LINE__ ,
                                         "NOMAD::Cache:erase(x): x.eval_type != cache.eval_type" );
    
    std::set<NOMAD::Cache_Point>::iterator it;
    NOMAD::cache_index_type       cache_index;
    
    // search in cache:
    const NOMAD::Eval_Point * cache_x = find ( x , it , cache_index );
    
    // the point has been found:
    if ( cache_x ) {
        
        // remove the point from the list of extern points:
        if ( cache_x->get_current_run() || x.get_current_run() ) {
            std::list<const NOMAD::Eval_Point*>::const_iterator end2 = _extern_pts.end();
            std::list<const NOMAD::Eval_Point*>::iterator       it2  = _extern_pts.begin();
            while ( it2 != end2 ) {
                if ( *it2 == cache_x || *it2 == &x ) {
                    _extern_pts.erase ( it2 );
                    break;
                }
                ++it2;
            }
        }
        
        // erase the point in cache if its address is different from &x:
        if ( cache_x != &x )
            delete cache_x;
        
        // remove the point from the cache:
        _sizeof -= x.size_of();
        
        switch ( cache_index ) {
            case NOMAD::CACHE_1:
                _cache1.erase ( it );
                break;
            case NOMAD::CACHE_2:
                _cache2.erase ( it );
                break;
            case NOMAD::CACHE_3:
                _cache3.erase ( it );
                break;
            case NOMAD::UNDEFINED_CACHE:
                break;
        }
        return true;
    }
    return false;
}
/*------------------------------------------------*/
void NOMAD::Cache::insert ( const NOMAD::Eval_Point & x )
{
    // check the eval types:
    if ( x.get_eval_type() != _eval_type )
        throw NOMAD::Cache::Cache_Error ( "Cache.cpp" , __LINE__ ,
                                         "NOMAD::Cache:insert(x): x.eval_type != cache.eval_type" );
    
    // insertion in _extern_pts:
    insert_extern_point ( x );
    
    // insertion in _cache2:
    NOMAD::Cache_Point cp  ( &x );
    _cache2.insert  (  cp  );
    x.set_in_cache ( true );
    _sizeof += x.size_of();
}
/*-----------------------------------------------------------------*/
void NOMAD::Cache::update ( NOMAD::Eval_Point       & cache_x ,
                           const NOMAD::Eval_Point & x         ) const
{
    const NOMAD::Point & bbo_x = x.get_bb_outputs();
    
    if ( &cache_x == &x         ||
        !x.is_eval_ok()        ||
        !cache_x.is_in_cache() ||
        bbo_x.empty()          ||
        cache_x != x              )
        return;
    
    // check the eval types:
    if ( x.get_eval_type      () != _eval_type ||
        cache_x.get_eval_type() != _eval_type    )
        throw NOMAD::Cache::Cache_Error ( "Cache.cpp" , __LINE__ ,
                                         "NOMAD::Cache:update(): problem with the eval. types" );
    
    const NOMAD::Point & bbo_cache_x = cache_x.get_bb_outputs();
    int                  m           = bbo_cache_x.size();
    
    _sizeof -= cache_x.size_of();
    
    // if the current point could not evaluate and x did,
    // or if the number of bb outputs is different, we set cache_x = x:
    if ( !cache_x.is_eval_ok() || m != bbo_x.size() )
    {
        cache_x.set_eval_status ( NOMAD::EVAL_OK     );
        cache_x.set_bb_output   ( bbo_x              );
        cache_x.set_signature   ( x.get_signature () );
        cache_x.set_direction   ( x.get_direction () );
        
        _sizeof += cache_x.size_of();
        return;
    }
    
    // we complete _bb_outputs:
    int c1 = 0;
    int c2 = 0;
    
    for ( int i = 0 ; i < m ; ++i ) {
        
        if ( bbo_cache_x[i].is_defined() )
            ++c1;
        
        if ( bbo_x[i].is_defined() )
            ++c2;
        
        if ( !bbo_cache_x[i].is_defined() && bbo_x[i].is_defined() )
            cache_x.set_bb_output ( i , bbo_x[i] );
    }
    
    // the two points are 'eval_ok' and have comparable outputs:
    // we select the best as the one with the more defined bb_outputs:
    if ( c2 > c1 ) {
        cache_x.set_signature  ( x.get_signature () );
        cache_x.set_direction  ( x.get_direction () );
        
    }
    
    _sizeof += cache_x.size_of();
}
/*----------------------------------------------------*/
bool NOMAD::Cache::read_points_from_cache_file ( std::ifstream & fin             ,
                                                const int     * p_nb_bb_outputs ,
                                                bool            display           )
{
    try {
        
        NOMAD::Clock c;
        
        // the stream is placed at the first point (after the CACHE_FILE_ID tag):
        fin.seekg ( sizeof ( NOMAD::CACHE_FILE_ID ) , std::ios::beg );
        
        NOMAD::Cache_File_Point   cfp;
        NOMAD::Eval_Point       * cur;
        const NOMAD::Eval_Point * cache_x;
        
        // main loop:
        while ( !fin.eof() ) {
            
            // reading of the Cache_File_Point:
            if ( !cfp.read ( fin ) ) {
                if ( fin.eof() )
                    break;
                return false;
            }
            
            // we ignore this cache file point if it has a different
            // number of blackbox outputs than *p_nb_bb_outputs:
            if ( p_nb_bb_outputs && cfp.get_m() != *p_nb_bb_outputs )
                continue;
            
            // creation of the Eval_Point:
            cur = new NOMAD::Eval_Point ( cfp , _eval_type );
            
            // we look if the current point is already in cache:
            cache_x = find ( *cur );
            
            // the current point is already in cache:
            if ( cache_x ) {
                update ( get_modifiable_point ( *cache_x ) , *cur );
                delete cur;
            }
            
            // point not in cache: insertion:
            else {
                
                // insertion in _extern_pts:
                insert_extern_point ( *cur );
                
                // insertion in _cache1:
                NOMAD::Cache_Point cp ( cur );
                _cache1.insert    ( cp   );
                cur->set_in_cache ( true );
                _sizeof += cur->size_of();
            }
            
        } // end of main loop
        
        // display stats on the cache load:
        if ( display ) {
            _out << "number of points: " << static_cast<int>(_cache1.size()) << std::endl
            << "size            : ";
            _out.display_size_of ( _sizeof );
            _out << std::endl
            << "load time       : " << c.get_real_time() << 's' << std::endl;
        }
    }
    catch ( ... ) {
        return false;
    }
    return true;
}