/****************************************************************
 *      Program Solving the KNAPSACK problem    		*
 *      Author Jakub Holy                                       *
 *      For the subject PAA, LS2002                             *
 *	main.cc - read input file and run the search algorihm	*
 ****************************************************************
 */
// 	$Id: main.cc.html,v 1.1.1.1 2003/11/08 13:19:49 aja Exp $	

#include <stdlib.h>	// atoi()
#include <assert.h>
#include <time.h>	// needed to get time
#include <sys/timeb.h>	// ftime
#include <iomanip>	// time printing formatting
#include <string>

#include "heuristic2.hh"

#ifndef _KSACK_IN_HH
#include "ksack_in.hh" //# includes Item
#endif

#ifndef _COMMON_H
#include "common.hh"   // class SearchAlgorithm
#endif

#ifndef _BRANCH_BOUND_HH
#include "branch_bound.hh"
#endif

#ifndef _DYNAMIC_PROGR_H
#include "dynamic_progr.hh"
#endif

#define BB	1
#define HR	2
#define DP	3

/** Defines which algorithm to use
 * @param algorithm = (BB|HR|DP)
 */
SearchAlgorithm *createAlgorithm(unsigned algorithm,  KnapsackInput *in ){
  assert(in);
  assert( algorithm==BB || algorithm==HR || algorithm==DP );
  //Algorithms: Branch_BoundAlgorithm  HeuristicAlgorithm Dynamic_ProgrAlgorithm
  switch( algorithm ){
  case 1:
    return new Branch_BoundAlgorithm (in->getTaskID(), in->getNr_items(), 
				   in->getMax_load(), in->getItems() );
    break;
  case 2:
    return new HeuristicAlgorithm (in->getTaskID(), in->getNr_items(), 
				   in->getMax_load(), in->getItems() );
    break;
  case 3:
    return new Dynamic_ProgrAlgorithm (in->getTaskID(), in->getNr_items(), 
				   in->getMax_load(), in->getItems() );
    break;
  default:
    return NULL;
  }//switch type of algorithm
}//createAlgorithm

/** Print the current time and the input string
 */
void printTime( char *info ){
  time_t tmp_t;
  struct tm stime;
  time( &tmp_t );			// get the current time
  localtime_r( &tmp_t, &stime);		// change it into a readable form
  cout << info <<" "<< stime.tm_hour <<":"<< setw(2)<< stime.tm_min <<":"<< setw(2) << stime.tm_sec << endl;
}// printTime     time_t *start_time; time( start_time );

 struct timeb *getTime(){
  struct timeb *tmp_t = new struct timeb;
  ftime( tmp_t );			// get the current time
  return tmp_t;
}

//****************************************************************** MAIN
// 0     1             2         3
// solve -a=(bb|hr|dp) taskfile [taskID]
#define ARG_ALG			1
#define ARG_TASKFILE		2			// position of the taskfile in argv[]
#define ARG_TASKID		ARG_TASKFILE + 1	// position if taskID in argv[]
//---
#define NR_ARGS_MINIMAL		ARG_TASKFILE + 1	// default mode; taskfile is the last + 0
#define NR_ARGS_ALL_TASKS	NR_ARGS_MINIMAL		// default mode = run on all tasks
#define NR_ARGS_ONE_TASK	NR_ARGS_ALL_TASKS + 1	// run on the specified task only

 int main(int argc, char **argv){
   unsigned algorithm = 999;	// Algorithm to use; a dummy number
  //Open data file and load the 1st task
  if ( argc < NR_ARGS_MINIMAL || NR_ARGS_ONE_TASK < argc ) {
    cerr << "Error: Wrong number of parameters.\n";
    cerr << "Usage: solve -a=(bb|hr|dp) taskfile [taskID]\n";
    cerr << " (bb=Branch and Bound, hr=Heuristics, dp=DynamicProgramming)\n";
    cerr << "Input file format (separators: spaces and newlines):\n";
    cerr << "\ttaskID numberOfItems CapacityOfKnapsack weight cost weight cost ...\n";
    cerr << "Output format:\n";
    cerr << "\ttaskID lengthOfPath2solution cost\n";
    return 2;
  } else {
    // Type of the algorithm to use
    const string alg_arg   	= argv[ARG_ALG];
    const string alg_type 	= alg_arg.substr(3);
    if (alg_type == "bb"){
      algorithm = BB;
    } else if (alg_type == "hr"){
      algorithm = HR;
    } else if (alg_type == "dp"){
      algorithm = DP;
    } else {
      cerr << "ERROR: Wrong algorithm type\n";
      cerr << "Allowed values are -a=bb, -a=hr, -a=dp; you typed ";
      cerr << argv[ARG_ALG] << endl;
      exit(2);
    }// *switch* type of algorithm
  }// if-else wrong input

  //Process the intput file
  KnapsackInput *in = new KnapsackInput( argv[ARG_TASKFILE] );

  // An algorithm instance to solve the problem
  SearchAlgorithm *problem = NULL;


  //Load the given task, if any
  if( argc == NR_ARGS_ONE_TASK ){

    int maxid = 0, minid = in->getTaskID();
    while ( (maxid = in->getTaskID()) != atoi(argv[ARG_TASKID]) ) {
      if( !in->loadNextTask() ){
	cerr << "ERROR: A task with ID "<< argv[ARG_TASKID];
	cerr <<" doesn't exist in the given file "<< argv[ARG_TASKFILE] << endl;
	cerr << "IDs in the file are between "<< minid <<" and "<< maxid <<endl;
	return 1;
      }// if not found
    }//while task not found or eof

    // SOLVE the given task
    problem = createAlgorithm( algorithm, in ); 
    problem->solve();
    problem->printResult(cout);

  } else {

    // Print&remember  start time
//     printTime( "MAIN: Start search at" );
    struct timeb *start_time = getTime();

//     cout << "TaskID steps cost\n";
    // SOLVE all tasks in the file:
    do {

      problem = createAlgorithm( algorithm, in ); 
      problem->solve();
      problem->printResult(cout);
      delete problem; problem = NULL;

    } while ( in->loadNextTask() );

    // Print finish time
//     printTime( "MAIN: Start finished at" );
    struct timeb *end_time = getTime();
    // Print length of run in ms:
    cerr <<difftime(end_time->time, start_time->time)*1000+
      end_time->millitm   - start_time->millitm << endl;
//     cout <<"MAIN: Search runned for "<< difftime(end_time->time, start_time->time);
//     cout <<":"<< -start_time->millitm +  end_time->millitm <<" [s:ms]\n";

  }//if-else a taskID given (= run 1 task/all tasks in the file)

  //---------
  return 0;
 }// main