#include "bootstrap_heuristic.h"

#include "../global_state.h"
#include "../option_parser.h"
#include "../plugin.h"
#include "../task_tools.h"

#include <cstddef>
#include <limits>
#include <utility>

using namespace std;

BootstrapHeuristic::BootstrapHeuristic(const Options &opts)
	: Heuristic(opts), bootstrap(task, opts){
    min_operator_cost = numeric_limits<int>::max();
	for(OperatorProxy op : task_proxy.get_operators()){
        min_operator_cost = min(min_operator_cost, op.get_cost());
	}
}

BootstrapHeuristic::~BootstrapHeuristic(){
}

void BootstrapHeuristic::initialize(){
	//cout << "Bootstrap heuristic initialized." << endl;
//	exit(-21);
}

int BootstrapHeuristic::compute_heuristic(const GlobalState &global_state){
	State state = convert_global_state(global_state);
	if(is_goal_state(task_proxy, state)){
		return 0;
	}else{
		//TODO: get features from state.
		vector<int> features;
		FeatureExtractor::extract_features(state, features);
		return abs(bootstrap.get_heuristic_from_neural_net(features));
	}
}

static Heuristic *_parse(OptionParser &parser){
	parser.document_synopsis("Bootstrap heuristic",
							 "Returns cost of new learned heuristic for "
							 "non-goal states, "
							 "0 for goal states");
	parser.document_language_support("action costs", "supported");
	parser.document_language_support("conditional effects", "supported");
	parser.document_language_support("axioms", "supported");
	parser.document_property("admissible", "no");
	parser.document_property("consistent", "no");
	parser.document_property("safe", "no");
	parser.document_property("preferred operators", "no");

//	parser.add_option<double>("t_max",
//							"This sets the time limit for bootstrap to solve a single instance in seconds",
//							"0.5");
//	parser.add_option<double>("t_inf",
//							"This sets the maximum time limit to what t_max can increase in seconds",
//							"2");
//    parser.add_option<int>("ins_min",
//    						"Sets the minimum number of instances that need to be solved, to start training the artificial neural network",
//							"200");
	parser.add_option<string>("method",
							"Specify the method that bootstrap will execute. Method can be one of the following: search, walk, sample, sample_random, estimate",
							"search");
	parser.add_option<string>("initial_heuristic",
							"This sets the initial heuristic which is used to learn a stronger heuristic from",
							"ff");
//    parser.add_option<bool>("use_local_registry", "Use a local state registry. This is used by bootstrap, to manage the states of different instances.", "false");
    parser.add_option<int>("number_of_rw",
    						"Specify the number of random walks that will be used to probe the state space.",
							"100");
    parser.add_option<int>("rw_length",
    						"Specify the length of a random walk.",
							"50");
    parser.add_option<string>("ann_topology",
    						"Specify the topology of the artificial neural network hidden layers, separated by |.",
							"50");
    parser.add_option<double>("eta",
    						"Specifies the speed how the neural network learns.",
							"0.001");
    parser.add_option<int>("epochs",
    						"Specifies how many epochs the neural net training should take.",
							"500");

	Heuristic::add_options_to_parser(parser);
	Options opts = parser.parse();
	if(parser.dry_run()){
		return 0;
	}else{
		return new BootstrapHeuristic(opts);
	}
}

static Plugin<Heuristic> _plugin("bootstrap", _parse);
