/*
 Copyright (C) 2010 - 2015 by Gabriel Morin <gabrielmorin (at) gmail (dot) com>
 Part of the Battle for Wesnoth Project http://www.wesnoth.org

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY.

 See the COPYING file for more details.
 */

/**
 * @file
 */

#ifndef WB_HIGHLIGHTER_HPP_
#define WB_HIGHLIGHTER_HPP_

#include "visitor.hpp"

static lg::log_domain log_whiteboard_highlight("whiteboard/highlight");
#define ERR_WB_H LOG_STREAM(err, log_whiteboard_highlight)
#define WRN_WB_H LOG_STREAM(warn, log_whiteboard_highlight)
#define LOG_WB_H LOG_STREAM(info, log_whiteboard_highlight)
#define DBG_WB_H LOG_STREAM(debug, log_whiteboard_highlight)

namespace wb
{

/**
 * Class that handles highlighting planned actions as you hover over them
 * and determine the right target for contextual execution.
 */
class highlighter
{

public:
	highlighter(unit_map& unit_map, side_actions_ptr side_actions);
	virtual ~highlighter();

	void set_mouseover_hex(const map_location& hex);
	const map_location& get_mouseover_hex() const {return mouseover_hex_; }

	void highlight();
	void clear();

	action_ptr get_execute_target();
	action_ptr get_delete_target();
	action_ptr get_bump_target();
	unit* get_selection_target();

	/// @return the action that currently receives the highlight focus
	weak_action_ptr get_main_highlight() { return main_highlight_; }
	typedef std::deque<weak_action_ptr> secondary_highlights_t;
	/// @return the collection of actions that are highlighted but don't have the focus
	secondary_highlights_t get_secondary_highlights() { return secondary_highlights_; }

private:
	/** Unhighlight a given action (main or secondary). */
	class unhighlight_visitor;

	/** Highlight the given main action. */
	class highlight_main_visitor;

	/** Highlight the given secondary action. */
	class highlight_secondary_visitor;

	void unhighlight();
	void find_main_highlight();
	void find_secondary_highlights();

	/** Redraw the given move action when needed. */
	void last_action_redraw(move_ptr);

	unit_map& unit_map_;

	map_location mouseover_hex_;
	std::set<map_location> exclusive_display_hexes_;
	unit* owner_unit_;
	unit* selection_candidate_;

	weak_action_ptr selected_action_;
	weak_action_ptr main_highlight_;
	secondary_highlights_t secondary_highlights_;

	side_actions_ptr side_actions_;
};

class highlighter::highlight_main_visitor: public visitor {
public:
	highlight_main_visitor(highlighter &h): highlighter_(h) {}
	void visit(move_ptr);
	void visit(attack_ptr);
	void visit(recruit_ptr);
	/// @todo: find some suitable effect for mouseover on planned recall.
	void visit(recall_ptr){}
	void visit(suppose_dead_ptr){}
private:
	highlighter &highlighter_;
};

class highlighter::highlight_secondary_visitor: public visitor {
public:
	highlight_secondary_visitor(highlighter &h): highlighter_(h) {}
	void visit(move_ptr);
	void visit(attack_ptr);
	void visit(recruit_ptr){}
	void visit(recall_ptr){}
	void visit(suppose_dead_ptr){}
private:
	highlighter &highlighter_;
};

class highlighter::unhighlight_visitor: public visitor {
public:
	unhighlight_visitor(highlighter &h): highlighter_(h) {}
	void visit(move_ptr);
	void visit(attack_ptr);
	void visit(recruit_ptr){}
	void visit(recall_ptr);
	void visit(suppose_dead_ptr){}
private:
	highlighter &highlighter_;
};

} // end namespace wb

#endif /* WB_HIGHLIGHTER_HPP_ */
