// file: ts_tree_1.cc
//

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

// method: merge_tree_cc
// arguments :
//   Decision_tree*& decision_tree: (input/output) the tree to be split
//   Link_list* leaf_list: (output) a new leaf list after merge
//   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 merge_threshd: (input) the likelihood threshold of split
//   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 merges some leaf nodes
//
logical_1 merge_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 merge_threshd_a, int_4 num_features_a,
			int_4 num_mixtures_a, int_4 debug_level_a) {
  
  // local variables about likelihood 
  //
  float_4 merge_lk_dec = 0.0;
  float_4 min_lk_dec = 10.0;

  // other local variables
  //
  logical_1 flag = ISIP_FALSE;
  int_4 label = 0;
  
  // leaf list
  //
  Link_list* leaf_list = decision_tree_a->get_leaf_list_cc();
  
  // variables for looping throught the leaf list
  //
  Link_node* start_lnd = (Link_node*)NULL;
  Link_node* next_lnd = (Link_node*)NULL;
  Link_node* opt_lnd = (Link_node*)NULL;

  Dt_node* start_dtn = (Dt_node*)NULL;
  Dt_node* next_dtn = (Dt_node*)NULL;
  Dt_node* opt_dtn = (Dt_node*)NULL;
  Dt_node* parent_dtn = (Dt_node*)NULL;
  Dt_node* temp_dtn = (Dt_node*)NULL;
  Dt_node* new_dtn = (Dt_node*)NULL;  

  int_4 start_label = 0;

  start_lnd = leaf_list->get_head_cc();
  
  while(start_lnd != (Link_node*)NULL) {
    flag = ISIP_FALSE;
    min_lk_dec = merge_threshd_a;
    start_dtn = (Dt_node*)(start_lnd->get_item_cc());
    next_lnd = start_lnd->get_next_cc();
   
    while(next_lnd != (Link_node*)NULL) {
      next_dtn = (Dt_node*)(next_lnd->get_item_cc());
      
      merge_lk_dec = decision_tree_a->compute_lk_dec_cc(start_dtn, next_dtn,
							states_a, occupancy_a,
							num_features_a,
							num_mixtures_a);

      if(merge_lk_dec < min_lk_dec) {
	min_lk_dec = merge_lk_dec;
	opt_dtn = next_dtn;
	opt_lnd = next_lnd;
	flag = ISIP_TRUE;
      }
      next_lnd = next_lnd->get_next_cc();
    }
            
    // if minimum decrease is below threshold, remove the opt_lnd from leaf
    // list, assign its label same to that of the start node, and update the
    // state information
    //
    if ((flag == ISIP_TRUE) && (min_lk_dec < merge_threshd_a)) {
      start_label = start_dtn->get_label_cc();
      opt_dtn->set_label_cc(start_label);

      // merge my moving states from the optimal node to the start node
      //
      start_dtn->append_states_cc(opt_dtn);

      // reset the dt_node in the optimal leaf node to start_dtn
      // need to do that by changing the child of the parent
      //
      parent_dtn = opt_dtn->get_parent_cc();
      temp_dtn = parent_dtn->get_l_child_cc();
      if (opt_dtn == temp_dtn) {
	label = opt_dtn->get_label_cc();
	delete opt_dtn;
	new_dtn = new Dt_node((Dt_node)*start_dtn);
	new_dtn->set_label_cc(label);
	parent_dtn->set_l_child_cc(new_dtn);
	new_dtn = (Dt_node*)NULL;
      }
      else {
	label = opt_dtn->get_label_cc();
	delete opt_dtn;
	new_dtn = new Dt_node((Dt_node)*start_dtn);
	new_dtn->set_label_cc(label);
	parent_dtn->set_r_child_cc(new_dtn);
	new_dtn = (Dt_node*)NULL;
      }

      // remove the link node from the leaf list
      //
      leaf_list->remove_cc(opt_lnd);
    }    
    start_lnd = start_lnd->get_next_cc() ;
  }

  // exit gracefully
  //
  return (ISIP_NO_ERROR);
}
