// file: hist_add_0.cc
//

// isip include files
//
#include "history.h"
#include "history_constants.h"
#include <word.h>
#include <ngram_node.h>

// method: add_prev_cc
//
// arguments:
//  History* hist: (input) the path back pointer to be set
//  float_4 pscore: (input) path score for this history
//  int_4 max_num: (input) maximum number of histories allowed
//
// return: a logical_1 indicating status
//
// this method inserts the input history in the history back pointer list
//
logical_1 History::add_prev_cc(History* hist_a, float_4 pscore_a,
			       int_4 max_num_a) {
  
  // define local variables
  //
  float_4 score = (float_4)0;
  History* hist = (History*)NULL;
  Link_node* lnd = (Link_node*)NULL;
  Link_node* node = (Link_node*)NULL;
  Link_node* lnode = (Link_node*)NULL;
  
  // memory manager
  //
  Memory_manager* manager = Link_list::get_manager_cc();
    
  // if the history node to add is null return ungracefully
  //
  if (hist_a == (History*)NULL) {
    return ISIP_FALSE;
  }

  // if no other histories exist allocate memory for the list
  //
  if (hist_num_d == (int_4)0) {
    prev_d = new Link_list();
  }

  // insert the new history at the right place
  //
  node = prev_d->get_head_cc();
  
  // loop over previous histories and compare
  //
  for (int_4 i = 0; i < max_num_a; i++) {

    // if this is the correct place insert here
    //
    if (node == (Link_node*)NULL) {
      
      // create node for history
      //
      lnode = manager->new_node_cc();
      lnode->set_item_cc((void_p)hist_a);
      
      // insert history
      //
      if (lnd == (Link_node*)NULL) {
	lnode->insert_cc(node);
	prev_d->set_head_cc(lnode);
      }
      else {
	lnd->insert_cc(lnode);
      }
      prev_d->set_curr_cc(lnode);
      
      // insert history path score
      //
      add_score_cc(i, pscore_a, max_num_a);
      
      // update reference counts
      //
      hist_a->ref_count_d++;
      hist_num_d++;
      break;
    }
    
    // get the history in the node
    //
    hist = (History*)(node->get_item_cc());
    score = prevsc_d[i];

    // make sure this is not a duplication of paths
    //
    if (hist == hist_a) {

      // update score if necessary
      //
      if (pscore_a > score) {
	prevsc_d[i] = pscore_a;
      }

      // break the loop
      //
      break;
    }
    
    // insert new link node
    //
    if (pscore_a > score) {
      
      // create node for history
      //
      lnode = manager->new_node_cc();
      lnode->set_item_cc((void_p)hist_a);
      
      // insert history
      //
      lnd = node->get_prev_cc();
      if (lnd == (Link_node*)NULL) {
	lnode->insert_cc(node);
	prev_d->set_head_cc(lnode);
      }
      else {
	lnd->insert_cc(lnode);
      }
      
      // insert history path score
      //
      add_score_cc(i, pscore_a, max_num_a);
      
      // update reference counts
      //
      hist_a->ref_count_d++;
      hist_num_d++;
      break;
    }
    
    // get the next node
    //
    lnd = node;
    node = node->get_next_cc();
    
  } // end for all nodes
  
  // if the history list is full then we need to replace an existing
  // history
  //
  if (hist_num_d > max_num_a) {
    
    // get the last node in the history node list
    //
    lnode = prev_d->get_curr_cc();
    
    // get the item in this node
    //
    hist = (History*)(lnode->get_item_cc());

    // decrement its reference count
    //
    hist->decr_ref_count_cc();

    // remove it from the current list
    //
    prev_d->remove_cc(lnode);

    // decrement history count
    //
    hist_num_d--;

    // if there are no more histories remaining release list memory
    //
    if (hist_num_d == (int_4)0) {
      delete prev_d;
      prev_d = (Link_list*)NULL;
    }
  }
  
  // exit gracefully
  //
  return ISIP_TRUE;
}
