/*
  Copyright (c) 1998 - 2008
  ILK  -  Tilburg University
  CNTS -  University of Antwerp
 
  This file is part of Timbl

  Timbl 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.

  Timbl 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/>.

  For questions and suggestions, see:
      http://ilk.uvt.nl/software.html
  or send mail to:
      Timbl@uvt.nl
*/
#ifndef MBLCLASS_H
#define MBLCLASS_H

namespace Timbl {
  using namespace Common;

  class InstanceBase_base;

  class MBLClass {
    typedef double (MBLClass::*FFIntMemberFn)( FeatureValue *, 
					       FeatureValue *, 
					       Feature * ) const;
  public:
    bool SetOption( const std::string& );
    bool ShowSettings( std::ostream& ) const;
    LogStream& my_err() const { return *myerr; };
    LogStream& my_log() const { return *mylog; };
    LogStream& my_debug() const { return *mydebug; };
    void prettyPrintInstance( std::ostream&, Instance * ) const;
    bool Verbosity( VerbosityFlags v ) const { 
      return verbosity & v; };
    void SetVerbosityFlag( VerbosityFlags v ) { verbosity |= v; };
    void ResetVerbosityFlag( VerbosityFlags v ) { verbosity &= ~v; };
    const StringHash *getFeatureHash() { return  FeatureStrings; };
    const StringHash *getTargetHash() { return TargetStrings; };
    void setHashes( const StringHash *, const StringHash * );
  protected:
    enum PhaseValue { TrainWords, LearnWords, TestWords, TrainLearnWords };
    friend std::ostream& operator<< ( std::ostream&, const PhaseValue& );
    enum IB_Stat { Invalid, Normal, Pruned };

    bool writeArrays( std::ostream& );
    bool readArrays( std::istream& );
    bool writeWeights( std::ostream& ) const;
    bool readWeights( std::istream&, WeightType );
    bool writeNamesFile( std::ostream& ) const;
    bool ShowOptions( std::ostream& ) const;
    void writePermutation( std::ostream& ) const;
    void LearningInfo( std::ostream& );
    bool ShowWeights( std::ostream& ) const;
    MBLClass( const std::string& = "" );
    virtual ~MBLClass();
    void InitClass( const size_t );
    MBLClass& operator=( const MBLClass& );
    void Initialize( size_t = 0 );
    bool PutInstanceBase( std::ostream& ) const;
    VerbosityFlags get_s_verbosity() const { return *server_verbosity; };
    VerbosityFlags get_verbosity() const { return verbosity; };
    void set_verbosity( VerbosityFlags v ) { verbosity = v; };
    const Instance *chopped_to_instance( PhaseValue );
    bool Chop( const std::string& );
    bool HideInstance( const Instance& );
    bool UnHideInstance( const Instance&  );
    std::string formatInstance( const std::vector<FeatureValue *>&,
				std::vector<FeatureValue *>&,
				size_t,	size_t ) const;
    bool setInputFormat( const InputFormatType );
    size_t countFeatures( const std::string&, 
			  const InputFormatType ) const;
    InputFormatType getInputFormat( const std::string& ) const;
    size_t examineData( const std::string& );
    void time_stamp( const char *, int =-1 ) const;
    void TestInstance( const Instance& ,
		       InstanceBase_base * = NULL,
		       size_t = 0 );
    void show_org_input( std::ostream & ) const;
    bool similarityMetric() const 
      { return (do_dot_product || do_cos_metric); };
    const ValueDistribution *ExactMatch( const Instance& , int& ) const;
    bool ExpInvalid() const { 
      if ( err_count > 0 ){
	InvalidMessage();
	return true;
      }
      else
	return false;
    };
    void fillNeighborSet( neighborSet& ) const;
    void addToNeighborSet( neighborSet& ns, size_t n ) const;
    double getBestDistance() const;
    WValueDistribution *getBestDistribution( unsigned int =0 );
    bool IBAdd( const Instance& );
    IB_Stat IBStatus() const;
    bool get_ranges( const std::string& );
    bool get_IB_Info( std::istream&, bool&, int&, bool&, std::string& );
    size_t NumOfFeatures() const { return num_of_features; };
    size_t targetPos() const { return target_pos; };
    size_t NumNumFeatures() const { return num_of_num_features; };
    size_t EffectiveFeatures() const { return effective_feats; };
    void IBInfo( std::ostream&, InstanceBase_base * ) const;
    void IBInfo( std::ostream& os ) const { 
      return IBInfo( os, InstanceBase) ; };
    void MatrixInfo( std::ostream& ) const;
    int RandomSeed() const { return random_seed; };
    void Info( const std::string& ) const;
    void Warning( const std::string& ) const;
    void Error( const std::string& ) const;
    void FatalError( const std::string& ) const;
    size_t MaxFeats() const { return MaxFeatures; };
    void Socket( int so ){ tcp_socket = so ; };
    int Socket() const { return tcp_socket; };
    int Progress() const { return progress; };
    bool MBLInit() const { return MBL_init; };
    void MBLInit( bool b ) { MBL_init = b; };
    Target   *Targets;
    std::vector<Feature *> Features;
    std::vector<Feature *> PermFeatures;
    size_t *Permutation;
    InstanceBase_base *InstanceBase;
    LogStream *mylog;
    LogStream *myerr;
    LogStream *mydebug;
    InputFormatType InputFormat() const { return input_format; };
    size_t TRIBL_offset() const { return tribl_offset; };
    unsigned int igOffset() const { return igThreshold; };
    unsigned int IB2_offset() const { return ib2_offset; };
    void IB2_offset( unsigned int n ) { ib2_offset = n; };
    bool Do_Sloppy_LOO() const { return do_sloppy_loo; };
    bool doSamples() const { 
      return do_sample_weighting && !do_ignore_samples; };
    bool Do_Exact() const { return do_exact_match; };
    void Do_Exact( bool b ) { do_exact_match = b; };
    void InitWeights();
    void diverseWeights();
    bool KeepDistributions() const { return keep_distributions; };
    void KeepDistributions( bool f ){ keep_distributions = f; };

    WeightType CurrentWeighting() const { return Weighting; };
    MetricType CurrentMetric() const { return GlobalMetric; };
    DecayType CurrentDecay( double &a, double &b ) const {
      a = decay_alfa; b = decay_beta; return decay_flag; };
    
    bool IsClone() const { return is_copy; };
    void default_order();
    void set_order(void);
    void calc_perm( double * );
    void  calculate_fv_entropy( bool );
    OptionTableClass Options;
    PhaseValue runningPhase;
    WeightType Weighting;
    MetricType GlobalMetric;
    OrdeningType TreeOrder;
    size_t num_of_neighbors;
    bool dynamic_neighbors;
    DecayType decay_flag;
    StringHash *TargetStrings;
    StringHash *FeatureStrings;
    std::string exp_name;
    Instance CurrInst;
    BestArray bestArray;
    size_t MaxBests;
    neighborSet nSet;
    decayStruct *decay;
    static const int maxSimilarity = INT_MAX;
    int beamSize;
    normType normalisation;
    double norm_factor;
    bool is_copy;
    unsigned int ib2_offset;
    int random_seed;
    double decay_alfa;
    double decay_beta;
    bool MBL_init;
    bool do_diversify;
    bool initProbabilityArrays( bool );
    FFIntMemberFn *test_feature_val;
    void calculatePrestored();
  public:
    double test_vd( FeatureValue *, FeatureValue *, Feature * ) const;
    double test_jd( FeatureValue *, FeatureValue *, Feature * ) const;
    double test_ld( FeatureValue *, FeatureValue *, Feature * ) const;
    double test_ov( FeatureValue *, FeatureValue *, Feature * ) const;
    double n_test_ov( FeatureValue *, FeatureValue *, Feature * ) const;
  private:
    size_t MaxFeatures;
    std::vector<MetricType> UserOptions;
    InputFormatType input_format;
    const VerbosityFlags *server_verbosity;
    VerbosityFlags verbosity;
    mutable int err_count;
    size_t num_of_features;
    size_t num_of_num_features;
    size_t target_pos;
    size_t effective_feats;
    int F_length;
    int clip_factor;
    int Bin_Size;
    int tcp_socket;
    int progress;
    size_t tribl_offset;
    unsigned igThreshold;
    int mvd_threshold;
    MetricType mvdDefaultMetric;
    bool shared_hash;
    bool do_sparse;
    bool do_sloppy_loo;
    bool do_dot_product;
    bool do_cos_metric;
    bool do_exact_match;
    bool do_silly_testing;
    bool hashed_trees;
    bool need_all_weights;
    bool do_sample_weighting;
    bool do_ignore_samples;
    bool no_samples_test;
    bool chopExamples() const {
      return do_sample_weighting && 
	!( runningPhase == TestWords && no_samples_test ); }
    bool keep_distributions;
    double DBEntropy;
    std::vector<std::string>ChoppedInput;
    void fill_table();
    void InvalidMessage() const ;
    double calculate_db_entropy( Target * );
    void do_numeric_statistics( );
    bool (MBLClass::*ChopInput)( const std::string&, 
				 std::vector<std::string>&, 
				 size_t ) const;
    double innerProduct( FeatureValue *, FeatureValue * ) const;
    size_t (MBLClass::*testGraph)( const std::vector<FeatureValue *>&,
				   std::vector<FeatureValue *>&, 
				   std::vector<double>&,
				   size_t,
				   size_t,
				   size_t ) const;
    
    size_t test_in_graph_dot( const std::vector<FeatureValue *>&,
			      std::vector<FeatureValue *>&, 
			      std::vector<double>&,
			      size_t,
			      size_t,
			      size_t ) const;
    
    size_t test_in_graph_cos( const std::vector<FeatureValue *>&,
			      std::vector<FeatureValue *>&, 
			      std::vector<double>&,
			      size_t,
			      size_t,
			      size_t ) const;


    size_t test_in_graph( const std::vector<FeatureValue *>&, 
			  std::vector<FeatureValue *>&, 
			  std::vector<double>&,
			  size_t,
			  size_t,
			  size_t,
			  double ) const;
    void test_instance( const Instance& ,
			InstanceBase_base * = NULL,
			size_t = 0 );
    void test_instance_sim( const Instance& ,
			    InstanceBase_base * = NULL,
			    size_t = 0 );
    
    size_t (MBLClass::*testGraphEx)( const std::vector<FeatureValue *>&,
				     std::vector<FeatureValue *>&, 
				     std::vector<double>&,
				     size_t,
				     size_t,
				     size_t,
				     double,
				     double,
				     double& ) const;
    
    size_t test_in_graph_dot_ex( const std::vector<FeatureValue *>&,
				 std::vector<FeatureValue *>&, 
				 std::vector<double>&,
				 size_t,
				 size_t,
				 size_t,
				 double,
				 double,
				 double& ) const;
    
    size_t test_in_graph_cos_ex( const std::vector<FeatureValue *>&,
				 std::vector<FeatureValue *>&, 
				 std::vector<double>&,
				 size_t,
				 size_t,
				 size_t,
				 double,
				 double,
				 double& ) const;
    
    size_t test_in_graph_ex( const std::vector<FeatureValue *>&, 
			     std::vector<FeatureValue *>&, 
			     std::vector<double>&,
			     size_t,
			     size_t,
			     size_t,
			     double,
			     double& ) const;
    
    void test_instance_ex( const Instance&,
			   InstanceBase_base * = NULL,
			   size_t = 0 );
    void test_instance_sim_ex( const Instance& ,
			       InstanceBase_base * = NULL,
			       size_t = 0 );

    bool allocate_arrays();

    double test_value_diff_prestored( FeatureValue **, FeatureValue**,
				      double *, int, int );
    double test_value_diff( FeatureValue **, FeatureValue **,
			    double *, int, int );
    double RelativeWeight( unsigned int ) const;    
    void writePermSpecial(std::ostream&) const;
    bool chop_C4_5_string( const std::string&,
			   std::vector<std::string>&,
			   size_t ) const;
    bool chop_ARFF_string( const std::string&,
			   std::vector<std::string>&,
			   size_t ) const;
    bool chop_bin_string( const std::string&, 
			  std::vector<std::string>&,
			  size_t ) const;
    bool chop_Compact_string( const std::string&, 
			      std::vector<std::string>&,
			      size_t ) const;
    bool chop_COLUMNS_string( const std::string&, 
			      std::vector<std::string>&,
			      size_t ) const;
    bool chop_sparse_string( const std::string&, 
			     std::vector<std::string>&,
			     size_t ) const;
    bool read_the_vals( std::istream& );
    MBLClass( const MBLClass& );
  };
 
  inline std::ostream& operator<< ( std::ostream& os, 
				    const MBLClass::PhaseValue& ph ){
    switch( ph ){
    case MBLClass::TrainWords: 
      os << "TrainWords";
      break;
    case MBLClass::LearnWords: 
      os << "LearnWords";
      break;
    case MBLClass::TestWords:
      os << "TestWords";
      break;
    case MBLClass::TrainLearnWords: 
      os << "TrainlearnWords";
      break;
    default:
      os << "unknown phase";
    }
    return os;
  }
  
  bool empty_line( const std::string& , const InputFormatType );
}

#endif // MBLCLASS_H
