#pragma once

#include <easyx.h>
#include <time.h>
#include <string>

// 编辑框
class Edit
{
private:

	// 字符
	struct Char
	{
		RECT rct = {};
		TCHAR tch = 0;

		COLORREF text_color = BLACK;

		Char* prev = nullptr;
		Char* next = nullptr;
	};

	// 单个光标
	struct Cursor
	{
		Char* pos = nullptr;	// 光标对应字符的位置
	};

	// 光标组
	struct CursorGroup
	{
		int show_duration = 500;			// 光标闪烁时间
		int hide_duration = 500;			// 光标隐藏时间
		clock_t timer;						// 光标闪烁计时

		bool show = true;					// 是否显示光标（闪烁中）
		int width = 1;						// 光标宽度

		int x_pos = 0;						// 光标 x 位置（像素位置）

		bool selecting = false;				// 是否选区

		Cursor begin, end;					// 选区的开始和结束光标，其中活动光标总是 end（未选区时使用 end）

		Cursor* pBehind = &end;	// 选区时，用于标记更靠近头结点的光标（称为近光标，未选区时使用 end 代替）
		Cursor* pFront = &end;	// 选区时，用于标记更远离头结点的光标（称为远光标，未选区时使用 end 代替）

		// 由于光标绘制在字符的右侧，所以操作选区时，从近光标的下一个字符开始操作，一直操作到远光标（包含远光标）
	};

	int m_standard_char_height = textheight(_T(' '));	// 标准字符高
	int m_standard_char_width = textwidth(_T(' '));		// 标准字符宽
	Char m_head;										// 文字头结点（不储存信息）
	CursorGroup m_cursors;								// 光标
	bool m_shift = false;								// 标识 shift 是否按下
	bool m_lbtn = false;								// 标识鼠标左键是否按下

	// 在某字符后创建一个新的字符
	Char* NewChar(Char* pc);

	// 删除某个字符
	void DeleteChar(Char* pc);

	// 获取字符大小
	SIZE GetCharSize(TCHAR tch);

	// 获取新输入字符所在行的 y 位置（返回是否需要新开一行）
	bool GetLinePos(Char* pc, int* line_pos);

	// 获取左侧的一个可聚焦的字符（没有则返回自身）
	Char* GetValidLeftChar(Char* pc);

	// 获取右侧的一个可聚焦的字符（没有则返回自身）
	Char* GetValidRightChar(Char* pc);

	// 获取上一行或下一行的一个可聚焦的字符（没有则返回自身）
	// up 是否向上搜索，否则向下
	Char* GetValidUpOrDownChar(Char* pc, int x_pos, bool up);

	// 移动某字符及其后续所有字符的位置
	// x, y			相对位移或绝对位置（y 指定行高度）
	// is_inline	是否只移动同行字符
	// absolute		是否使用绝对位置（整体移动）
	// 返回最后一个被移动的字符
	Char* MoveFollowCharPos(Char* pc, int x, int y, bool is_inline, bool absolute);

	// 连接某字符后续的所有字符（将后续字符贴上来，清除断层，调整字符位置）
	void ConnectFollowChar(Char* pc);

	// 删除选区或前一个字符
	void Delete();

	// 添加一个字符
	void Insert(TCHAR tch);

	// 重置光标选择状态
	void ResetCursorSelState(CursorGroup* pcg);

	// 选区时，对两个光标进行排序
	void SortCursors(CursorGroup* pcg);

	// 更新光标 x 位置记录
	void UpdateCursorXPos(CursorGroup* pcg);

	// 获取鼠标位置对应的字符
	Char* GetMouseChar(int x, int y);

	// 判断字符是否为单词分隔符
	bool IsSeparation(Char* pc);

	// 根据一个字符选取它附近的一个单词
	// 返回该单词的起始和结束字符
	void GetWordFromChar(Char* pc, Char*& word_begin, Char*& word_end);

	// 高亮处理
	void HighLight();

	// 渲染图像
	void Render();

public:

	Edit();

	// 更新消息
	void UpdateMessage(bool isNewMsg, ExMessage msg);

	// 获取文本
	std::wstring GetText(Char* begin = nullptr, Char* end = nullptr);

};

