// file: $ISIP_TIE_STATE/class/dt_node/v1.0/dt_node.h
//

// make sure the definitions are made only once
//
#ifndef __ISIP_DT_NODE
#define __ISIP_DT_NODE

// isip include files
//
#ifndef __ISIP_INTEGRAL
#include <integral.h>
#endif

#ifndef __ISIP_LINK_LIST
#include <link_list.h>
#endif

#ifndef __ISIP_PHONE
#include <phone.h>
#endif

#ifndef __ISIP_HASH_TABLE
#include <hash_table.h>
#endif

#ifndef __ISIP_HASH_CELL
#include <hash_cell.h>
#endif

#ifndef __ISIP_QUESTION
#include <question.h>
#endif

// Dt_node is a class that is used to hold a decision tree node
//
class Dt_node {
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:
  
  // dt_node data
  //
  Dt_node* parent_d;            // parent node
  Dt_node* l_child_d;           // left child node
  Dt_node* r_child_d;           // right child node
  
  int_4 num_states_d;           // number of states in this node 
  int_4* state_index_d;         // global indices of these states
  
  float_4 likelihood_d;         // score at the current node
  float_4 split_lk_inc_d;       // likelihood increase after split
  Question* opt_question_d;     // optimal question for splitting this node
  
  logical_1 flag_leaf_d;        // flag showing leaf or not
  logical_1 flag_visit_d ;      // flag showing if the node has been visited
  int_4 label_d;                // new global index for leaf node   
  
  int_4 debug_level_d;          // debug level
  int_4 level_d;                // level in the current tree
  int_4 node_index_d;           // index of dt_nodes
  
  //---------------------------------------------------------------------------
  //
  // public methods
  //
  //---------------------------------------------------------------------------
public:
  
  // required methods
  //
  char_1* name_cc();
  volatile void error_handler_cc(char_1* mname, char_1* msg);
  logical_1 debug_cc(FILE* fp, char_1* message);
  logical_1 set_debug_cc(int_4 debug_level);
  int_4 size_cc();
  
  // destructor/constructor
  //
  ~Dt_node();
  Dt_node();
  Dt_node(const Dt_node& node);
  
  // set methods
  //
  logical_1 set_label_cc(int_4 label) {
    label_d = label;
    return ISIP_TRUE;
  }
  
  logical_1 set_visit_flag_cc() {
    flag_visit_d = ISIP_TRUE;
    return ISIP_TRUE;
  }

  logical_1 set_leaf_flag_cc(logical_1 flag) {
    flag_leaf_d = flag;
    return ISIP_TRUE;
  }
  
  logical_1 set_level_cc(int_4 level) {
    level_d = level;
    return ISIP_TRUE;
  }
  
  logical_1 set_opt_question_cc(Question* question) {
    opt_question_d = question;
    return ISIP_TRUE;
  }
  
  logical_1 set_parent_cc(Dt_node* parent) {
    parent_d = parent;
    return ISIP_TRUE;
  }
  
  logical_1 set_children_cc(Dt_node* l_child, Dt_node* r_child) {
    l_child_d = l_child;
    r_child_d = r_child;
    return ISIP_TRUE;
  }
  
  logical_1 set_l_child_cc(Dt_node* l_child) {
    l_child_d = l_child;
    return ISIP_TRUE;
  }

  logical_1 set_r_child_cc(Dt_node* r_child) {
    r_child_d = r_child;
    return ISIP_TRUE;
  }
  
  logical_1 set_states_cc(int_4 num_states, int_4* state_index);
  
  logical_1 set_node_index_cc(int_4 node_index) {
    node_index_d = node_index;
    return ISIP_TRUE; 
  }
  
  // get_methods
  //
  int_4 get_label_cc() {
    return label_d;
  }
  
  logical_1 get_visit_flag_cc() {
    return flag_visit_d;
  }
  
  logical_1 get_leaf_flag_cc() {
    return flag_leaf_d;
  }
  
  int_4 get_level_cc() {
    return level_d;
  }
  
  Question* get_opt_question_cc() {
    return opt_question_d;
  }
  
  Dt_node* get_parent_cc() {
    return parent_d;
  }
  
  Dt_node* get_l_child_cc() {
    return l_child_d;
  }
  
  Dt_node* get_r_child_cc() {
    return r_child_d;
  }
  
  int_4 get_num_states_cc() {
    return num_states_d;
  }
  
  int_4* get_state_index_cc() {
    return state_index_d;
  }
 
  float_4 get_likelihood_cc() {
    return likelihood_d;
  }
    
  float_4 get_split_lk_inc_cc() {
    return split_lk_inc_d;
  }
  
  int_4 get_node_index_cc() {
    return node_index_d;
  }
  
  // check answer for a question
  //
  logical_1 ask_question_cc(Question* question, int_4 state_index,
			    Hash_table* answers, int_4** l_context,
			    int_4** r_context);
  
  // check answer for the optimal quesiton 
  //
  logical_1 ask_opt_question_cc(int_4 state_index, Hash_table* answer,
				int_4** l_context, int_4** r_context); 
  
  // given the left and right context, check answer for the optical question
  //
  logical_1 ask_opt_question_cc(Hash_table* answer, int_4 l_context,
				int_4 r_context); 
  
  // find the optimal question for splitting this node
  //
  logical_1 find_opt_question_cc(Question** questions, Hash_table* answers,
				 State** states, float_4* occupy,
				 int_4** l_context, int_4** r_context,
				 float_4 occ_threshold,
				 float_4& l_num_occ, float_4& r_num_occ,
				 int_4 num_questions, int_4 num_feat,
				 int_4 num_mix);
  
  
  // split the dt_node given a question
  //
  logical_1 split_node_cc(Question* question, Hash_table* answer,
			  Dt_node* l_child, Dt_node* r_child,
			  int_4** l_context, int_4** r_context);
  
  // split the dt_node using its optimal question
  //
  logical_1 split_node_cc(Hash_table* answer, int_4** l_context,
			  int_4** r_context);
  
  
  // compute methods
  //
  float_4 compute_likelihood_cc(State** states, float_4* occupy,
				int_4 num_feat, int_4 num_mix);
  
  float_4 compute_split_lk_inc_cc(Question** questions, Hash_table* answers,
				  State** states, float_4* occupy,
				  int_4 num_questions, int_4 num_feat,
				  int_4 num_mix, int_4** l_context,
				  int_4** r_context, float_4 occ_threshold,
				  float_4& l_child_num_occ,
				  float_4& r_child_num_occ);
  
  logical_1 compute_covar_cc(float_4* covar, float_4& det_covar,
			     float_4& scale, State** states,
			     float_4* occupy, int_4 num_feat, int_4 num_mix);
  
  logical_1 compute_mean_cc(float_4* mean, State** states, float_4* occupy,
			    int_4 num_feat, int_4 num_mix);
  
  float_4 compute_occupancy_cc(float_4* occupy);
  
  // this method appends the state indices of another node
  //
  logical_1 append_states_cc(Dt_node* dtn);
  
  // clear the state index list and number of states
  // 
  logical_1 clear_cc();
};

// end of file
// 
#endif
