// file: dec_prune_0.cc
//

// isip include files
//
#include "decoder.h"
#include "decoder_constants.h"

// method: inst_compare_cc
//
// arguments:
//  Link_node* node1 : (input) node containing the first instance
//  Link_node* node2 : (input) node containing the second instance
//
// return: an int_4 containing result of comparison
//
// this method compares two instances purely by score
//
static int inst_compare_cc(const void* inst1_a, const void* inst2_a) {

  // result value of comparison
  //
  int_4 value = (int_4)0;
  
  // scores of the two traces
  //
  float_4 score1 = (*((Instance**)inst1_a))->get_score_cc();
  float_4 score2 = (*((Instance**)inst2_a))->get_score_cc();

  // compare the two and set value
  //
  if (score1 >= score2) {
    value = (int_4)-1;
  }
  if (score1 < score2) {
    value = (int_4)1;
  }

  // exit gracefully
  //
  return (int)value;
}

// method: prune_inst_cc
//
// arguments: none
//
// return: a logical_1 to indicate status
//
// this method sorts all active model instances and prunes the state
// level traces based on the instance cutoff threshold
//
logical_1 Decoder::prune_inst_cc() {
  
  // dummy variables
  //
  int_4 ind = (int_4)0;
  float_4 score = (float_4)0;
  Instance* inst = (Instance*)NULL;
  Link_node* nd = (Link_node*)NULL;
  Link_node* pd = (Link_node*)NULL;
  
  // initialize the threshold
  //
  mapmi_thresh_d = INSTANCE_ACTIVE_SCORE;
  
  // create the instances array
  //
  Instance** inst_array = new Instance*[inst_count_d];
  
  // loop over all instances in the instance list
  //
  for (nd = inst_list_d->get_head_cc(); nd != (Link_node*)NULL;
       nd = pd) {

    // get the instance in this node and add it to the array of
    // instances, and update the active frame index of the instance
    //
    pd = nd->get_next_cc();
    inst_array[ind] = (Instance*)(nd->get_item_cc());
    inst_array[ind]->set_frame_cc(frame_d);
    ind++;

  } // end for all instances in list
  
  // sort all the instances by score if mapmi pruning is needed
  //
  if ((inst_count_d > mapmi_limit_d) && (mapmi_limit_d > (int_4)0)) {
    
    // now sort this array in descending order according to the trace
    // scores
    //
    qsort(inst_array, ind, sizeof(Instance*), inst_compare_cc);
    
    // get the score at the cut-off instance
    //
    inst = inst_array[mapmi_limit_d];
    mapmi_thresh_d = inst->get_score_cc();
  }

  // free memory
  //
  delete [] inst_array;
  
  // set the alignment mode flag
  //
  logical_1 flag = ISIP_FALSE;
  if (align_mode_d == DEC_STATE_ALIGN_MODE) {
    flag = ISIP_TRUE;
  }

  // loop over all instances in the instance list
  //
  for (nd = inst_list_d->get_head_cc(); nd != (Link_node*)NULL; nd = pd) {

    // get the instance in this node and its score
    //
    pd = nd->get_next_cc();
    inst = (Instance*)(nd->get_item_cc());
    score = inst->get_score_cc();

    // make sure mapmi pruning is necessary, and compare scores and
    // prune away instance if below threshold
    //
    if ((mapmi_thresh_d > INSTANCE_ACTIVE_SCORE) &&
	(score > INSTANCE_ACTIVE_SCORE) &&
	(mapmi_thresh_d > score)) {
      
      // remove traces from this instance and remove this node from
      // the instance list
      //
      inst->prune_cc(flag, num_traces_del_d[DEC_STATE_LEVEL]);
      inst_list_d->remove_cc(nd);
      inst_count_d--;
    }
    
    // otherwise reset scores and reposition markers in the tokens
    //
    else {
      inst->set_score_cc(INSTANCE_ACTIVE_SCORE);
      inst->reset_markers_cc();    
    }
  } // end for loop

  // if it is time perform garbage collection and cleanup on the
  // instance table
  //
  active_instances_cc();

  // exit gracefully
  //
  return ISIP_TRUE;
}
