//! \~\file piscreentypes.h
//! \~\ingroup Console
//! \brief
//! \~english Types for PIScreen
//! \~russian Типы для PIScreen
//! \details
//! \~english Provides common types used by screen tiles and drawer.
//! \~russian Обеспечивает общие типы, используемые тайлами и отрисовщиком экрана.
/*
    PIP - Platform Independent Primitives
    Types for PIScreen
    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 PISCREENTYPES_H
#define PISCREENTYPES_H

#include "pip_console_export.h"
#include "pivariant.h"
#include "pivariantsimple.h"

class PIScreenTile;

//! \relatesalso PIScreenTile
//! \~english Namespace with shared screen cells, layout flags, and tile event types.
//! \~russian Пространство имен с общими типами экранных ячеек, флагами компоновки и событиями тайлов.
namespace PIScreenTypes {

//! \~english Color for a character or its background.
//! \~russian Цвет символа или его фона.
enum Color {
	Default /** \~english Terminal default color \~russian Цвет терминала по умолчанию */,
	Black /** \~english Black \~russian Черный */,
	Red /** \~english Red \~russian Красный */,
	Green /** \~english Green \~russian Зеленый */,
	Blue /** \~english Blue \~russian Синий */,
	Cyan /** \~english Cyan \~russian Голубой */,
	Magenta /** \~english Magenta \~russian Пурпурный */,
	Yellow /** \~english Yellow \~russian Желтый */,
	White /** \~english White \~russian Белый */,
	Transparent /** \~english Preserve the background already stored in the target cell \~russian Сохранить фон, уже записанный в целевой
				   ячейке */
};

//! \~english Character formatting flags.
//! \~russian Флаги оформления символа.
enum CharFlag {
	Bold      = 0x1 /** \~english Bold or bright text \~russian Жирный или яркий текст */,
	Blink     = 0x2 /** \~english Blinking text \~russian Мигание текста */,
	Underline = 0x4 /** \~english Underlined text \~russian Подчеркнутый текст */,
	Inverse   = 0x08 /** \~english Inverted foreground and background \~russian Инвертированные цвета текста и фона */
};

//! \~english Horizontal text alignment inside a tile.
//! \~russian Горизонтальное выравнивание текста внутри тайла.
enum Alignment {
	Left /** \~english Left alignment \~russian Выравнивание влево */,
	Center /** \~english Center alignment \~russian Выравнивание по центру */,
	Right /** \~english Right alignment \~russian Выравнивание вправо */
};

//! \~english Layout policy used by parent tiles.
//! \~russian Политика размера, используемая родительскими тайлами при компоновке.
enum SizePolicy {
	Fixed /** \~english Keep the requested size \~russian Сохранять запрошенный размер */,
	Preferred /** \~english Use preferred size first and share extra space after fixed tiles \~russian Сначала использовать предпочтительный
				 размер и затем делить свободное место после фиксированных тайлов */
		,
	Expanding /** \~english Take extra space before preferred tiles when the parent can grow children \~russian Получать дополнительное
				 пространство раньше тайлов с предпочтительным размером, если родитель может расширять дочерние элементы */
		,
	Ignore /** \~english Skip automatic layout; geometry must be managed manually \~russian Не участвовать в автоматической компоновке;
			  геометрию нужно задавать вручную */
};

//! \~english Child layout direction.
//! \~russian Направление раскладки дочерних тайлов.
enum Direction {
	Horizontal /** \~english Horizontal layout \~russian Горизонтальная раскладка */,
	Vertical /** \~english Vertical layout \~russian Вертикальная раскладка */
};

//! \~english Focus and navigation flags for tiles.
//! \~russian Флаги фокуса и навигации для тайлов.
enum FocusFlag {
	CanHasFocus            = 0x1 /** \~english Tile can receive focus \~russian Тайл может получать фокус */,
	NextByTab              = 0x2 /** \~english Tab moves focus to the next tile \~russian Клавиша Tab переводит фокус к следующему тайлу */,
	NextByArrowsHorizontal = 0x4 /** \~english Left and right arrows move focus \~russian Стрелки влево и вправо переводят фокус */,
	NextByArrowsVertical   = 0x8 /** \~english Up and down arrows move focus \~russian Стрелки вверх и вниз переводят фокус */,
	NextByArrowsAll /** \~english Any arrow key moves focus \~russian Любая стрелка переводит фокус */ =
		NextByArrowsHorizontal | NextByArrowsVertical,
	FocusOnMouse = 0x10 /** \~english Mouse press gives focus to the tile \~russian Нажатие мышью переводит фокус на тайл */,
	FocusOnWheel = 0x20 /** \~english Mouse wheel gives focus to the tile \~russian Колесо мыши переводит фокус на тайл */,
	FocusOnMouseOrWheel /** \~english Mouse press or wheel gives focus to the tile \~russian Нажатие мышью или колесо переводят фокус на
						   тайл */
		= FocusOnMouse | FocusOnWheel
};

//! \~english Combination of \a CharFlag values.
//! \~russian Комбинация значений \a CharFlag.
typedef PIFlags<CharFlag> CharFlags;

//! \~english Combination of \a FocusFlag values.
//! \~russian Комбинация значений \a FocusFlag.
typedef PIFlags<FocusFlag> FocusFlags;

//! \~\brief
//! \~english Packed character formatting used by screen cells.
//! \~russian Упакованное описание оформления символа, используемое экранными ячейками.
union PIP_CONSOLE_EXPORT CellFormat {
	//! \~english Constructs a format from the raw packed value.
	//! \~russian Создает формат из упакованного сырого значения.
	CellFormat(ushort f = 0) { raw_format = f; }

	//! \~english Constructs a format from foreground color, background color, and character flags.
	//! \~russian Создает формат из цвета символа, цвета фона и флагов оформления.
	CellFormat(Color col_char, Color col_back = Default, CharFlags flags_ = 0) {
		color_char = col_char;
		color_back = col_back;
		flags      = flags_;
	}

	//! \~english Raw packed representation of the format.
	//! \~russian Сырое упакованное представление формата.
	ushort raw_format;
	struct {
		//! \~english Foreground color from \a Color.
		//! \~russian Цвет символа из \a Color.
		ushort color_char: 4;

		//! \~english Background color from \a Color.
		//! \~russian Цвет фона из \a Color.
		ushort color_back: 4;

		//! \~english Combination of \a CharFlag values.
		//! \~russian Комбинация значений \a CharFlag.
		ushort flags: 8;
	};

	//! \~english Returns \b true when two formats are identical.
	//! \~russian Возвращает \b true, если два формата совпадают.
	bool operator==(const CellFormat & c) const { return raw_format == c.raw_format; }

	//! \~english Returns \b true when two formats differ.
	//! \~russian Возвращает \b true, если форматы различаются.
	bool operator!=(const CellFormat & c) const { return raw_format != c.raw_format; }
};

//! \~\brief
//! \~english One character cell of the console screen.
//! \~russian Одна символьная ячейка консольного экрана.
struct PIP_CONSOLE_EXPORT Cell {
	//! \~english Constructs a cell from a symbol and its format.
	//! \~russian Создает ячейку из символа и его формата.
	Cell(PIChar c = PIChar(' '), CellFormat f = CellFormat()) {
		symbol = c;
		format = f;
	}

	//! \~english Cell formatting.
	//! \~russian Формат ячейки.
	CellFormat format;

	//! \~english Character stored in the cell.
	//! \~russian Символ, хранимый в ячейке.
	PIChar symbol;

	//! \~english Returns \b true when symbol and format match.
	//! \~russian Возвращает \b true, если совпадают символ и формат.
	bool operator==(const Cell & c) const { return format == c.format && symbol == c.symbol; }

	//! \~english Returns \b true when symbol or format differs.
	//! \~russian Возвращает \b true, если символ или формат различаются.
	bool operator!=(const Cell & c) const { return format != c.format || symbol != c.symbol; }

	//! \~english Assigns a cell, preserving the current background when source background is \a Transparent.
	//! \~russian Присваивает ячейку, сохраняя текущий фон, если у источника фон равен \a Transparent.
	Cell & operator=(const Cell & c) {
		symbol = c.symbol;
		if (c.format.color_back == Transparent) {
			format.color_char = c.format.color_char;
			format.flags      = c.format.flags;
		} else
			format = c.format;
		return *this;
	}
};

//! \~\brief
//! \~english User-defined event raised by a tile.
//! \~russian Пользовательское событие, поднимаемое тайлом.
struct PIP_CONSOLE_EXPORT TileEvent {
	//! \~english Constructs an event with numeric type and optional payload.
	//! \~russian Создает событие с числовым типом и необязательными данными.
	TileEvent(int t = -1, const PIVariant & d = PIVariant()): type(t), data(d) {}

	//! \~english Event type chosen by the tile implementation.
	//! \~russian Тип события, выбираемый реализацией тайла.
	int type;

	//! \~english Optional event payload.
	//! \~russian Необязательные данные события.
	PIVariant data;
};

//! \~\brief
//! \~english Base interface used by tiles to notify the owning screen about focus, removal, and custom events.
//! \~russian Базовый интерфейс, через который тайлы уведомляют владеющий экран о фокусе, удалении и пользовательских событиях.
class PIP_CONSOLE_EXPORT PIScreenBase {
public:
	//! \~english Constructs an empty screen bridge.
	//! \~russian Создает пустой мост к экрану.
	PIScreenBase() {}

	//! \~english Destroys the screen bridge.
	//! \~russian Уничтожает мост к экрану.
	virtual ~PIScreenBase() {}

	//! \~english Called when a tile raises a custom event.
	//! \~russian Вызывается, когда тайл поднимает пользовательское событие.
	virtual void tileEventInternal(PIScreenTile *, TileEvent) {}

	//! \~english Called when a tile is removed from the screen tree.
	//! \~russian Вызывается при удалении тайла из дерева экрана.
	virtual void tileRemovedInternal(PIScreenTile *) {}

	//! \~english Called when a tile requests focus.
	//! \~russian Вызывается, когда тайл запрашивает фокус.
	virtual void tileSetFocusInternal(PIScreenTile *) {}
};

} // namespace PIScreenTypes


// inline PIByteArray & operator <<(PIByteArray & s, const PIScreenTypes::Cell & v) {s << v.format.raw_format << v.symbol; return s;}
// inline PIByteArray & operator >>(PIByteArray & s, PIScreenTypes::Cell & v) {s >> v.format.raw_format >> v.symbol; return s;}

//! \relatesalso PIBinaryStream
//! \~english Store operator
//! \~russian Оператор сохранения
BINARY_STREAM_WRITE(PIScreenTypes::Cell) {
	s << v.format.raw_format << v.symbol;
	return s;
}

//! \relatesalso PIBinaryStream
//! \~english Restore operator
//! \~russian Оператор извлечения
BINARY_STREAM_READ(PIScreenTypes::Cell) {
	s >> v.format.raw_format >> v.symbol;
	return s;
}


//! \relatesalso PIBinaryStream
//! \~english Store operator
//! \~russian Оператор сохранения
BINARY_STREAM_WRITE(PIScreenTypes::TileEvent) {
	s << v.type << v.data;
	return s;
}

//! \relatesalso PIBinaryStream
//! \~english Restore operator
//! \~russian Оператор извлечения
BINARY_STREAM_READ(PIScreenTypes::TileEvent) {
	s >> v.type >> v.data;
	return s;
}


REGISTER_PIVARIANTSIMPLE(PIScreenTypes::TileEvent)

#endif // PISCREENTYPES_H
