// file: ts_tree_4.cc
//

// system include files
//
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <ctype.h>

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

// method: read_trees_cc
//
// arguments:
//   Decision_tree**& decision_trees: (output) the decision trees
//   int_4& num_trees : (output) number of trees read
//   Questions***& questions : (output) test questions
//   int_4*& num_questions : (output) number of questions
//   FILE* fp_in: (input) the input decision tree file
//
// return: a logical_1 indicating status
//
// this method reads in the decision trees from a file
//
logical_1 read_trees_cc(Decision_tree**& decision_trees_a,
			int_4& num_trees_a, 
			Question***& questions_a,
			int_4*& num_questions_a,
			FILE* fp_in_a) {
  
  // define some local variables
  //
  char_1* buffer = new char_1[ISIP_MAX_STRING_LENGTH];
  char_1* buffer_pos = buffer;
  char_1* temp_buf = (char_1*)NULL;
  char_1* delimiter = (char_1*)"=";
  
  // parameters for decision trees
  //
  int_4 tree_ind = (int_4)0;
  float_4 split_threshd = 0.0;
  float_4 merge_threshd = 0.0;
  float_4 num_occ_threshd = 0;
  int_4 tree_count = 0;
  char_1* cph = (char_1*)NULL;
  int_4 st_pos = 0;
  
  // paramenters for dt_node
  //  
  Dt_node** dt_nodes = (Dt_node**)NULL;     // all the dt_nodes in a tree
  int_4 level = (int_4)0;
  int_4 label = (int_4)0;
  
  Question* opt_question = (Question*)NULL;
  
  int_4 num_nodes = (int_4)0;
  int_4 curr_nd_ind = (int_4)0;
  int_4 l_child_ind = (int_4)0;
  int_4 r_child_ind = (int_4)0;

  // define memory
  //
  memset((char*)buffer, 0, ISIP_MAX_STRING_LENGTH);
  
  // read in the number of trees and common decision tree parameters
  // such as thresholds
  //
  
  while (fgets((char*)buffer_pos, ISIP_MAX_STRING_LENGTH, fp_in_a) &&
	 (*buffer_pos != 't')) {

    // ignore the comment lines
    //
    if (buffer_pos[0] == (char_1)'#') {
      
      // do nothing
      //
      continue;      
    }
    
    else {
      
      // find the delimited value
      //
      temp_buf = (char_1*)strtok((char*)buffer_pos, (char*)delimiter);
      
      // parse this string
      //
      while (temp_buf != (char_1*)NULL) {
	
	// move the pointer to first non-whitespace
	//
	while (isspace((char)(*temp_buf))) {
	  temp_buf++;
	}
	
	// read the number of trees
	//
	if (strcmp((char*)temp_buf, (char*)NUM_TREES) == 0) {
	  temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
	  num_trees_a = atoi((char*)temp_buf);

	  // initialize the decision trees
	  //	
	  decision_trees_a = new Decision_tree*[num_trees_a];
	  questions_a = new Question**[num_trees_a];
	  num_questions_a = new int_4[num_trees_a];
	  break;
	}
	
	// read the split, merge and num_occupancy  thresholds
	//
	else if (strcmp((char*)temp_buf, (char*)SPLIT_THRESHOLD) == 0) {
	  temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
	  split_threshd =  atof((char*)temp_buf);
	  break;
	}
	
	else if (strcmp((char*)temp_buf, (char*)MERGE_THRESHOLD) == 0) {
	  temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
	  merge_threshd =  atof((char*)temp_buf);
	  break;
	}
	
	else if (strcmp((char*)temp_buf, (char*)NUM_OCC_THRESHOLD) == 0) {
	  temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
	  num_occ_threshd =  atof((char*)temp_buf);	
	  break;
	}
	break;
	
      } // end while temp_buf is not null
    } // end of else loop
  } // end while fgets

  // start reading each tree
  //
  
  // find the delimited value
  //
  temp_buf = (char_1*)strtok((char*)buffer_pos, (char*)delimiter);
  
  // while the line is not empty
  //
  while (temp_buf != (char_1*)NULL) {
    
    // move the pointer to first non-whitespace
    //
    while (isspace((char)(*temp_buf))) {
      temp_buf++;
    }
    
    // read in the tree index and number of node
    //
    if (strcmp((char*)temp_buf, "tree_index") == 0) {
      
      temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
      tree_ind = atoi((char*)temp_buf);
      
      // initialize a new decision tree
      //
      decision_trees_a[tree_ind] = new Decision_tree();
      decision_trees_a[tree_ind]->set_split_threshd_cc(split_threshd);
      decision_trees_a[tree_ind]->set_merge_threshd_cc(merge_threshd);
      decision_trees_a[tree_ind]->set_num_occ_threshd_cc(num_occ_threshd);
      
      // read number of nodes in this tree and initialize these nodes
      // 
      fgets((char*)buffer_pos,ISIP_MAX_STRING_LENGTH,fp_in_a);
      temp_buf = (char_1*)strtok((char*)buffer_pos, (char*)delimiter);
      temp_buf = (char_1*)strtok((char*)NULL, "\n");
      num_nodes = atoi((char*)temp_buf);

      // set up for next tree
      //
      if (dt_nodes != (Dt_node**)NULL) {
	delete [] dt_nodes;
	dt_nodes = (Dt_node**)NULL;
      }
      dt_nodes = new Dt_node*[num_nodes];
      questions_a[tree_ind] = new Question*[num_nodes];
      num_questions_a[tree_ind] = num_nodes;
      
      fgets((char*)buffer_pos,ISIP_MAX_STRING_LENGTH,fp_in_a);
      temp_buf = (char_1*)strtok((char*)buffer_pos, (char*)delimiter);
      temp_buf = (char_1*)strtok((char*)NULL, "\n");
      cph = temp_buf;
      decision_trees_a[tree_ind] ->set_cph_cc(cph);
      
      fgets((char*)buffer_pos,ISIP_MAX_STRING_LENGTH,fp_in_a);
      temp_buf = (char_1*)strtok((char*)buffer_pos, (char*)delimiter);
      temp_buf = (char_1*)strtok((char*)NULL, "\n");
      st_pos = atoi((char*)temp_buf);
      decision_trees_a[tree_ind] ->set_state_pos_cc(st_pos);
      
      for(int_4 i = 0; i< num_nodes; i++) {
	dt_nodes[i] = new Dt_node();
	questions_a[tree_ind][i] = new Question();
      }
      
      tree_count++;
      
      // move on to the next word
      //	
      temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
    }
  }

  while ((fgets((char*)buffer_pos,ISIP_MAX_STRING_LENGTH,fp_in_a)) &&
	 (tree_count <= num_trees_a)) {
  
    // find the delimited value
    //
    temp_buf = (char_1*)strtok((char*)buffer_pos, (char*)delimiter);
    
    // while the line is not empty
    //
    while (temp_buf != (char_1*)NULL) {
      
      // move the pointer to first non-whitespace
      //
      while (isspace((char)(*temp_buf))) {
	temp_buf++;
      }
      
      // read in the tree index and number of node
      //
      if (strcmp((char*)temp_buf, "tree_index") == 0) {

	temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
	tree_ind = atoi((char*)temp_buf);
	
	// initialize a new decision tree
	//
	decision_trees_a[tree_ind] = new Decision_tree();
	decision_trees_a[tree_ind]->set_split_threshd_cc(split_threshd);
	decision_trees_a[tree_ind]->set_merge_threshd_cc(merge_threshd);
	decision_trees_a[tree_ind]->set_num_occ_threshd_cc(num_occ_threshd);
	
	// read number of nodes in this tree and initialize these nodes
	// 
	fgets((char*)buffer_pos,ISIP_MAX_STRING_LENGTH,fp_in_a);
	temp_buf = (char_1*)strtok((char*)buffer_pos, (char*)delimiter);
	temp_buf = (char_1*)strtok((char*)NULL, "\n");
	num_nodes = atoi((char*)temp_buf);

	// set up for next tree
	//
	if (dt_nodes != (Dt_node**)NULL) {
	  delete [] dt_nodes;
	  dt_nodes = (Dt_node**)NULL;
	}
	dt_nodes = new Dt_node*[num_nodes];
	questions_a[tree_ind] = new Question*[num_nodes];
	num_questions_a[tree_ind] = num_nodes;
      
	fgets((char*)buffer_pos,ISIP_MAX_STRING_LENGTH,fp_in_a);
	temp_buf = (char_1*)strtok((char*)buffer_pos, (char*)delimiter);
	temp_buf = (char_1*)strtok((char*)NULL, "\n");
	cph = temp_buf;
	decision_trees_a[tree_ind] ->set_cph_cc(cph);

	fgets((char*)buffer_pos,ISIP_MAX_STRING_LENGTH,fp_in_a);
	temp_buf = (char_1*)strtok((char*)buffer_pos, (char*)delimiter);
	temp_buf = (char_1*)strtok((char*)NULL, "\n");
	st_pos = atoi((char*)temp_buf);
	decision_trees_a[tree_ind]->set_state_pos_cc(st_pos);
	
	for(int_4 i = 0; i< num_nodes; i++) {
	  dt_nodes[i] = new Dt_node();
	  questions_a[tree_ind][i] = new Question();
	}

	tree_count++;
	
	// move on to the next word
	//	
	temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
      }

      // current node index
      //
      else if (strcmp((char*)temp_buf, "N") == 0) {
	temp_buf = (char_1*)strtok((char*)NULL, " ");
	curr_nd_ind = atoi((char*)temp_buf) - 1;
	
	// if it is the root node
	//
	if(curr_nd_ind == 0) {
	  decision_trees_a[tree_ind]->set_root_cc(dt_nodes[curr_nd_ind]);
	}
	
	temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
      }
      
      // level of current node
      //
      else if (strcmp((char*)temp_buf, "Level") == 0) {
	temp_buf = (char_1*)strtok((char*)NULL, " ");
	level = atoi((char*)temp_buf);
	
	// set the level
	//
	dt_nodes[curr_nd_ind]->set_level_cc(level);

	temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
      }

      // read leaf flag
      //
      else if (strcmp((char*)temp_buf, "LF") == 0) {
	
	temp_buf = (char_1*)strtok((char*)NULL, " ");
	
	if(strcmp((char*)temp_buf, "N") == 0) {

	  // this is not a leaf node
	  //
	  dt_nodes[curr_nd_ind]->set_leaf_flag_cc(ISIP_FALSE);

	  // read the following non-leaf node information 
	  //		  
	  temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
	  	    
	  while (temp_buf != (char_1*)NULL) {
	    
	    // read the left child node
	    //
	    if(strcmp((char*)temp_buf, "Y_CH") == 0) {
	      temp_buf = (char_1*)strtok((char*)NULL, " ");
	    
	      l_child_ind = atoi((char*)temp_buf) - 1;
	      dt_nodes[curr_nd_ind]->set_l_child_cc(dt_nodes[l_child_ind]);
	      dt_nodes[l_child_ind]->set_parent_cc(dt_nodes[curr_nd_ind]);
	      
	      temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
	    }
	    
	    // read the right child node
	    //
	    if(strcmp((char*)temp_buf, "N_CH") == 0) {
	      temp_buf = (char_1*)strtok((char*)NULL, " ");
	      
	      r_child_ind = atoi((char*)temp_buf) - 1;
	      dt_nodes[curr_nd_ind]->set_r_child_cc(dt_nodes[r_child_ind]);
	      dt_nodes[r_child_ind]->set_parent_cc(dt_nodes[curr_nd_ind]);

	      temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
	    }
	  
	    // read optimal question
	    //
	    if(strcmp((char*)temp_buf, "Q") == 0) {
	      opt_question = questions_a[tree_ind][curr_nd_ind];
	      temp_buf = (char_1*)strtok((char*)NULL, " ");	    
	      if(strcmp((char*)temp_buf, "L")==0) {
		opt_question->set_direction_cc(ISIP_TRUE);
	      }
	      else {
		opt_question->set_direction_cc(ISIP_FALSE);
	      }
	      temp_buf = (char_1*)strtok((char*)NULL, "\n");
	      opt_question->set_attribute_cc(temp_buf);
	      dt_nodes[curr_nd_ind]->set_opt_question_cc(opt_question);
	      
	      temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
	    }
	  } // end read non-leaf information
	} 
	
	else {
	  
	  // this is a leaf node
	  //
	  dt_nodes[curr_nd_ind]->set_leaf_flag_cc(ISIP_TRUE);
	  
	  // read the following leaf node information 
	  //	  
	  temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);	 
	  
	  while (temp_buf != (char_1*)NULL) {
	    
	    if(strcmp((char*)temp_buf, "State") == 0) {
	      temp_buf = (char_1*)strtok((char*)NULL, " ");
	      
	      label = atoi((char*)temp_buf);
	      dt_nodes[curr_nd_ind]->set_label_cc(label);
	      temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
	    }
	    
	    else {
	      temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
	    }
	  }
	} // end read leaf node information
      }

      // move on to the next word
      //      
      else {
	temp_buf = (char_1*)strtok((char*)NULL, (char*)delimiter);
      }
    }
  }
    
  // free memory
  //
  delete [] buffer;
  buffer = (char_1*)NULL;

  if (dt_nodes != (Dt_node**)NULL) {
    delete [] dt_nodes;
    dt_nodes = (Dt_node**)NULL;
  }
  
  // exit gracefully
  //
  return ISIP_TRUE;
}
