// file: ts_tree_0.cc
//

// isip include files
//
#include "tie_state.h"
#include "tie_state_constants.h"

// method: split_tree_cc
// arguments :
//   Decision_tree*& decision_tree: (input/output) the tree to be split
//   Question** questions: (input) all the questions
//   Hash_table* answers: (input) hash table containing answers
//   State** states: (input) all the states
//   float_4* occupancy: (input) the states occupancy
//   int_4** l_context: (input) the left context of states
//   int_4** r_context: (input) the right context of states
//   float_4 split_threshd: (input) the likelihood threshold of split
//   int_4 num_occ_threshd: (input) the minimum number of states threshold
//   int_4 num_features: (input) the number of features
//   int_4 num_mixtures: (input) the number of mixtures
//   int_4 debug_level: (input) the debug level
//
//  return: a logical_1 indicating status
//

// this function is to split one decision tree
//
logical_1 split_tree_cc(Decision_tree* decision_tree_a,
			Question** questions_a, Hash_table* answers_a,
			State** states_a, float_4* occupancy_a, 
			int_4** l_context_a, int_4** r_context_a,
			float_4 split_threshd_a, float_4 num_occ_threshd_a,
			int_4 num_questions_a, int_4 num_features_a,
			int_4 num_mixtures_a, int_4 debug_level_a) {
    
  // local variables 
  //
  Link_list* leaf_list = (Link_list*)NULL;
  Link_node* link_nd = (Link_node*)NULL;
  
  float_4 split_lk_inc = 0.0;
  float_4 max_lk_inc = 0.0;
  
  Dt_node* opt_split_node = (Dt_node*)NULL;
  Dt_node* dt_node = (Dt_node*)NULL;
  Dt_node* l_child = (Dt_node*)NULL;
  Dt_node* r_child = (Dt_node*)NULL;
      
  float_4 l_child_num_occ = 0;
  float_4 r_child_num_occ = 0;
  float_4 node_num_occ = 0;

  // split this tree
  //
  // get the link list of all leaf nodes
  //
  leaf_list = decision_tree_a->get_leaf_list_cc();
  
  // a flag to decide if conitnuing spilting the tree
  //
  logical_1 flag = ISIP_TRUE;
    
  while(flag == ISIP_TRUE) {
      
    link_nd = leaf_list->get_head_cc();
    max_lk_inc = 0;
      
    // loop all the leaf nodes and find the optimal node to split
    //
    while(link_nd != (Link_node*)NULL) {
	
      l_child_num_occ = 0;
      r_child_num_occ = 0;
      node_num_occ = 0;

      // get the Dt_node
      //
      dt_node = (Dt_node*)(link_nd->get_item_cc());
	
      // compute or get the likelihood increase if splitting this node
      // with its optimal question
      //
      if(dt_node->get_visit_flag_cc() == ISIP_FALSE) {
	split_lk_inc = dt_node->
	  compute_split_lk_inc_cc(questions_a, answers_a, states_a,
				  occupancy_a, num_questions_a, num_features_a,
				  num_mixtures_a, l_context_a, r_context_a,
				  num_occ_threshd_a, l_child_num_occ,
				  r_child_num_occ);
      }
      else {
	split_lk_inc = dt_node->get_split_lk_inc_cc();
      }
      
      // get the node occupancy
      //      
      node_num_occ = l_child_num_occ + r_child_num_occ;
      
      if (split_lk_inc > max_lk_inc) {
	max_lk_inc = split_lk_inc;
	opt_split_node = dt_node;	
      }
      
      // set this node visited
      //
      dt_node->set_visit_flag_cc();

      // get next node
      //
      link_nd = link_nd->get_next_cc();
    }
    
    if (opt_split_node == NULL) {
      break;
    }
    else if (max_lk_inc > split_threshd_a) {

      opt_split_node->split_node_cc(answers_a, l_context_a, r_context_a);
        
      // set the flag to continue splitting 
      //
      
      // compute the likelihood for the new leaf nodes
      //
      l_child = opt_split_node->get_l_child_cc();
      r_child = opt_split_node->get_r_child_cc();
      l_child->compute_likelihood_cc(states_a, occupancy_a, num_features_a,
				     num_mixtures_a);
      r_child->compute_likelihood_cc(states_a, occupancy_a, num_features_a,
				     num_mixtures_a);
      
      // remove this node from the leaf node list, add its child nodes
      // into it
      //
      leaf_list->remove_cc(opt_split_node);
      leaf_list->insert_cc(l_child);
      leaf_list->insert_cc(r_child);
      decision_tree_a->set_num_leaf_cc();
    
      // print debug information if needed
      //
      if(debug_level_a > 0) {
	fprintf(stdout, "%s[%ld]: %f occupancy: %f best_question: %s\n\n",
		decision_tree_a->get_cph_cc(),
		decision_tree_a->get_state_pos_cc(),
		max_lk_inc,
		opt_split_node->compute_occupancy_cc(occupancy_a),
		opt_split_node->get_opt_question_cc()->get_attribute_cc());
      }

      // reset the optimal node
      //
      opt_split_node = NULL;
    }
    else {
      break;
    }
  }
  
  // exit gracefully
  //
  return ISIP_TRUE;
}


