#pragma once
#include <iostream>

#include "AI_QValues.h"
#include "LogicPlayer.h"
#include "util/Interval_skip_list.h"
#include "util/Interval_skip_list_interval.h"

class AI_Tree: public AI_QValues
{
public:
	AI_Tree(LogicPlayer* _player) : AI_QValues(qv_standard), player(_player), ai_player(0),
									root(0), m_size(0) {}
	~AI_Tree() { clear(); }

	q_info get_qinfo(const AI_State& state);
	STATE_VALUE update_qvalue(const AI_State& state, MOVE_ID move, STATE_VALUE q);
	STATE_VALUE update_reward(const AI_State& state, MOVE_ID move, STATE_VALUE rdelta);
	void load(PLAYER_ID player_id);
	void save(PLAYER_ID player_id);
	size_t size() { return m_size; }
	void clear();

	struct AI_Tree_Node;
	typedef util::Interval_skip_list_interval<STATE_VALUE, AI_Tree_Node*> AI_Interval;
	typedef util::Interval_skip_list<AI_Interval> AI_Interval_list;
	typedef AI_Interval_list::iterator il_iter;

	struct AI_Tree_Node
	{
		AI_Tree_Node(AI_Tree_Node* _parent, unsigned int _id, STATE_VAR_ID _branch_var, 
						const AI_Interval& I, AI_PARAM r) : 
				parent(_parent), branch_var(_branch_var), id(_id), interval(I), lr(r), num_visits(0) 
				{ interval.set_element(this); }

		STATE_VAR_ID branch_var;
		MQV_Map mqv_map;
		
		AI_Tree_Node* parent;
		
		AI_Interval interval;
		AI_Interval_list children;

		unsigned int id;
		int num_visits;
		AI_PARAM lr;

		bool is_leaf() { return branch_var == 0; }
	};

private:
	void rec_delete(AI_Tree_Node* cn);
	void save(AI_Tree_Node* cn, std::ostream& qvalues);
	AI_Interval interval_rep(STATE_VAR_ID sid, STATE_VALUE sv);
	AI_Tree_Node* next(AI_Tree_Node* cn, const AI_State& state, int level);


	size_t m_size;
	AI_Tree_Node* root;
	LogicPlayer* player;
	AI_Player* ai_player;
};
