/*! \file piscreen.h
 * \brief Console GUI class
*/
/*
	PIP - Platform Independent Primitives
	Console GUI
	Ivan Pelipenko peri4ko@yandex.ru

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 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; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef PISCREEN_H
#define PISCREEN_H

#include "pip_console_export.h"
#include "piscreentile.h"
#include "piscreendrawer.h"


class PIP_CONSOLE_EXPORT PIScreen: public PIThread, public PIScreenTypes::PIScreenBase
{
	PIOBJECT_SUBCLASS(PIScreen, PIThread)
	class SystemConsole;
public:
	
	//! Constructs %PIScreen with key handler "slot" and if "startNow" start it
	PIScreen(bool startNow = true, PIKbdListener::KBFunc slot = 0);
	
	~PIScreen();
	
	//! Directly call function from \a PIKbdListener
	void enableExitCapture(int key = 'Q') {listener->enableExitCapture(key);}
	
	//! Directly call function from \a PIKbdListener
	void disableExitCapture() {listener->disableExitCapture();}
	
	//! Directly call function from \a PIKbdListener
	bool exitCaptured() const {return listener->exitCaptured();}
	
	//! Directly call function from \a PIKbdListener
	int exitKey() const {return listener->exitKey();}
	
	int windowWidth() const {return console.width;}
	int windowHeight() const {return console.height;}

	bool isMouseEnabled() const {return mouse_;}
	void setMouseEnabled(bool on);
	
	PIScreenTile * rootTile() {return &root;}
	PIScreenTile * tileByName(const PIString & name);
	
	void setDialogTile(PIScreenTile * t);
	PIScreenTile * dialogTile() const {return tile_dialog;}
	
	PIScreenDrawer * drawer() {return &drawer_;}
	void clear() {drawer_.clear();}
	void resize(int w, int h) {console.resize(w, h);}
	
	EVENT_HANDLER0(void, waitForFinish);
	EVENT_HANDLER0(void, start) {start(false);}
	EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();}
	EVENT_HANDLER0(void, stop) {stop(false);}
	EVENT_HANDLER1(void, stop, bool, clear);
	
	EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
	EVENT2(tileEvent, PIScreenTile * , tile, PIScreenTypes::TileEvent, e)
	
//! \handlers
//! \{
	
	//! \fn void waitForFinish()
	//! \brief block until finished (exit key will be pressed)
	
	//! \fn void start(bool wait = false)
	//! \brief Start console output and if "wait" block until finished (exit key will be pressed)
	
	//! \fn void stop(bool clear = false)
	//! \brief Stop console output and if "clear" clear the screen
	
//! \}
//! \events
//! \{
	
	//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data)
	//! \brief Raise on key "key" pressed, "data" is pointer to %PIConsole object
	
	//! \fn void tileEvent(PIScreenTile * tile, PIScreenTypes::TileEvent e)
	//! \brief Raise on some event "e" from tile "tile"
	
//! \}
	
private:
	class PIP_CONSOLE_EXPORT SystemConsole {
	public:
		SystemConsole();
		~SystemConsole();
		void begin();
		void end();
		void prepare();
		void clear();
		void print();
		void resize(int w, int h);
		void toUpperLeft();
		void moveTo(int x = 0, int y = 0);
		void hideCursor();
		void showCursor();
		void clearScreen();
		void clearScreenLower();
#ifdef WINDOWS
		void getWinCurCoord();
		void clearLine();
		void newLine();
		ushort attributes(const PIScreenTypes::Cell & c);
#else
		PIString formatString(const PIScreenTypes::Cell & c);
#endif
		PRIVATE_DECLARATION(PIP_CONSOLE_EXPORT)
		int width, height, pwidth, pheight;
		int mouse_x, mouse_y;
		PIVector<PIVector<PIScreenTypes::Cell> > cells, pcells;
	};

	void begin();
	void run();
	void end();
	void key_event(PIKbdListener::KeyEvent key);
	EVENT_HANDLER1(void, mouse_event, PIKbdListener::MouseEvent, me);
	EVENT_HANDLER1(void, wheel_event, PIKbdListener::WheelEvent, we);
	static void key_eventS(PIKbdListener::KeyEvent key, void * t) {((PIScreen*)t)->key_event(key);}
	PIVector<PIScreenTile*> tiles() {return root.children();}
	PIVector<PIScreenTile*> prepareMouse(PIKbdListener::MouseEvent * e);
	PIVector<PIScreenTile*> tilesUnderMouse(int x, int y);
	bool nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key = PIKbdListener::KeyEvent());
	void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e);
	void tileRemovedInternal(PIScreenTile * t);
	void tileSetFocusInternal(PIScreenTile * t);

	bool mouse_;
	SystemConsole console;
	PIScreenDrawer drawer_;
	PIKbdListener * listener;
	PIKbdListener::KBFunc ret_func;
	PIScreenTile root;
	PIScreenTile * tile_focus, * tile_dialog;

};


#endif // PISCREEN_H
