#ifndef NEWSBEUTER_KEYMAP__H
#define NEWSBEUTER_KEYMAP__H

#include <string>
#include <map>
#include <utility>
#include <vector>

#include <configparser.h>

// in configuration: bind-key <key> <operation>


enum { 
	KM_FEEDLIST		= 1<<0,
	KM_FILEBROWSER	= 1<<1,
	KM_HELP			= 1<<2,
	KM_ARTICLELIST	= 1<<3,
	KM_ARTICLE		= 1<<4,
	KM_TAGSELECT	= 1<<5,
	KM_FILTERSELECT	= 1<<6,
	KM_URLVIEW		= 1<<7,
	KM_PODBEUTER	= 1<<8,
	KM_SYSKEYS		= 1<<9,
	KM_INTERNAL		= 1<<10,
	KM_DIALOGS		= 1<<11,
	KM_NEWSBEUTER	= KM_FEEDLIST | KM_FILEBROWSER | KM_HELP | KM_ARTICLELIST | KM_ARTICLE | KM_TAGSELECT | KM_FILTERSELECT | KM_URLVIEW | KM_DIALOGS,
	KM_BOTH			= KM_NEWSBEUTER | KM_PODBEUTER
};

namespace newsbeuter {

	enum operation {	OP_NIL = 0, 
						// general and newsbeuter-specific operations:
						OP_NB_MIN,
						OP_QUIT, 
						OP_HARDQUIT, 
						OP_RELOAD, 
						OP_RELOADALL, 
						OP_MARKFEEDREAD, 
						OP_MARKALLFEEDSREAD, 
						OP_OPEN, 
						OP_SAVE, 
						OP_NEXTUNREAD, 
						OP_PREVUNREAD,
						OP_NEXT,
						OP_PREV,
						OP_OPENINBROWSER, 
						OP_OPENBROWSER_AND_MARK,
						OP_HELP, 
						OP_TOGGLESOURCEVIEW, 
						OP_TOGGLEITEMREAD, 
						OP_TOGGLESHOWREAD, 
						OP_SHOWURLS,
						OP_CLEARTAG, 
						OP_SETTAG, 
						OP_SEARCH,
						OP_GOTO_URL,
						OP_ENQUEUE,
						OP_REDRAW,
						OP_CMDLINE,
						OP_SETFILTER,
						OP_CLEARFILTER,
						OP_SELECTFILTER,
						OP_RELOADURLS,
						OP_BOOKMARK,
						OP_EDITFLAGS,
						OP_NEXTUNREADFEED,
						OP_PREVUNREADFEED,
						OP_NEXTFEED,
						OP_PREVFEED,
						OP_MACROPREFIX,
						OP_DELETE,
						OP_PURGE_DELETED,
						OP_EDIT_URLS,
						OP_CLOSEDIALOG,
						OP_VIEWDIALOGS,
						OP_NEXTDIALOG,
						OP_PREVDIALOG,
						OP_PIPE_TO,
						OP_RANDOMUNREAD,
						OP_SORT,
						OP_REVSORT,
						OP_NB_MAX,

						// podbeuter-specific operations:
						OP_PB_MIN = 1000, 
						OP_PB_DOWNLOAD, 
						OP_PB_CANCEL, 
						OP_PB_DELETE,
						OP_PB_PURGE, 
						OP_PB_TOGGLE_DLALL, 
						OP_PB_MOREDL, 
						OP_PB_LESSDL, 
						OP_PB_PLAY, 
						OP_PB_MAX,
						
						OP_SK_MIN = 1500,
						OP_SK_UP,
						OP_SK_DOWN,
						OP_SK_PGUP,
						OP_SK_PGDOWN,
						/* TODO: add more user-defined keys here */
						OP_SK_HOME,
						OP_SK_END,
						
						OP_SK_MAX,

						OP_INT_MIN = 2000,

						OP_INT_END_CMDLINE,
						OP_INT_END_SETFILTER,
						OP_INT_BM_END,
						OP_INT_EDITFLAGS_END,
						OP_INT_START_SEARCH,

						OP_INT_GOTO_URL,

						OP_INT_END_QUESTION,
						OP_INT_CANCEL_QNA,
						OP_INT_QNA_NEXTHIST,
						OP_INT_QNA_PREVHIST,

						OP_INT_RESIZE,
						OP_INT_SET,

						OP_INT_MAX,
						OP_1 = 3001,
						OP_2,
						OP_3,
						OP_4,
						OP_5,
						OP_6,
						OP_7,
						OP_8,
						OP_9,
						OP_0
						};

	struct keymap_desc {
		std::string key;
		std::string cmd;
		std::string desc;
		std::string ctx;
		unsigned short flags;
	};

	struct macrocmd {
		operation op;
		std::vector<std::string> args;
	};

	class keymap : public config_action_handler {
		public:
			keymap(unsigned int flags);
			~keymap();
			void set_key(operation op, const std::string& key, const std::string& context);
			void unset_key(const std::string& key, const std::string& context);
			operation get_opcode(const std::string& opstr);
			operation get_operation(const std::string& keycode, const std::string& context);
			std::vector<macrocmd> get_macro(const std::string& key);
			char get_key(const std::string& keycode);
			std::string getkey(operation op, const std::string& context);
			virtual void handle_action(const std::string& action, const std::vector<std::string>& params);
			virtual void dump_config(std::vector<std::string>& config_output);
			void get_keymap_descriptions(std::vector<keymap_desc>& descs, unsigned short flags);
			unsigned short get_flag_from_context(const std::string& context);
		private:
			bool is_valid_context(const std::string& context);
			std::string getopname(operation op);
			std::map<std::string, std::map<std::string, operation> > keymap_;
			std::map<std::string,std::vector<macrocmd> > macros_;
	};

}


#endif
