#include "stdafx.h"
#include "ui_conf.h"
#include "host.h"
#include "scintilla_conf.h"
#include "ui_goto.h"
#include "ui_find.h"
#include "ui_replace.h"


using namespace pfc::stringcvt;

//config_dialog_manager g_config_dlg_mgr;


LRESULT CDialogConf::OnInitDialog(HWND hwndFocus, LPARAM lParam)
{
	//g_config_dlg_mgr.add_window(m_hWnd);

	// Get caption text
	uGetWindowText(m_hWnd, m_caption);

	// Init resize
	DlgResize_Init();

	// Apply window placement
	if (m_parent->get_wndpl().length == 0)
	{
		m_parent->get_wndpl().length = sizeof(WINDOWPLACEMENT);

		if (!GetWindowPlacement(&m_parent->get_wndpl()))
			memset(&m_parent->get_wndpl(), 0, sizeof(WINDOWPLACEMENT));
	}
	else
	{
		SetWindowPlacement(&m_parent->get_wndpl());
	}

	// Script Engine
	HWND combo_script_engine = GetDlgItem(IDC_SCRIPT_ENGINE);

	ComboBox_AddString(combo_script_engine, _T("JScript"));
	ComboBox_AddString(combo_script_engine, _T("VBScript"));

	if (!uComboBox_SelectString(combo_script_engine, m_parent->get_script_name()))
		ComboBox_SetCurSel(combo_script_engine, 0);

	// Edge Style
	HWND combo_edge_style = GetDlgItem(IDC_EDGE_STYLE);

	ComboBox_AddString(combo_edge_style, _T("None"));    // NO_EDGE
	ComboBox_AddString(combo_edge_style, _T("Sunken"));  // SUNKEN_EDGE
	ComboBox_AddString(combo_edge_style, _T("Grey"));    // GREY_EDGE

	ComboBox_SetCurSel(combo_edge_style, m_parent->get_edge_style());

	// Edit box
	pfc::string8_fast text;
	HWND edit = GetDlgItem(IDC_EDIT);
	int cursel;

	// Subclassing scintilla
	SetWindowSubclass(edit, EditorSubclassFunc, 0, (DWORD_PTR)this);

	sci_init(edit);
	cursel = ComboBox_GetCurSel(combo_script_engine);

	if (uComboBox_GetText(combo_script_engine, cursel, text))
	{
		sci_set_lexer(edit, text);
	}

	// Checkboxs
	uButton_SetCheck(m_hWnd, IDC_CHECK_GRABFOCUS, m_parent->get_grab_focus());
	uButton_SetCheck(m_hWnd, IDC_CHECK_PSEUDO_TRANSPARENT, m_parent->get_pseudo_transparent());

	::EnableWindow(combo_edge_style, !m_parent->get_pseudo_transparent());

	// GUID Text
	pfc::string8 guid_text = "GUID: ";
	guid_text += pfc::print_guid(m_parent->get_config_guid());
	uSetWindowText(GetDlgItem(IDC_STATIC_GUID), guid_text);

	// Script
	sci_set_text(edit, m_parent->get_script_code(), true);

	// Set save point
	SendMessage(edit, SCI_SETSAVEPOINT, 0, 0);

	return TRUE; // set focus to default control
}

LRESULT CDialogConf::OnCloseCmd(WORD wNotifyCode, WORD wID, HWND hWndCtl)
{
	switch (wID)
	{
	case IDOK:
		Apply();
		EndDialog(IDOK);
		break;

	case IDAPPLY:
		Apply();
		break;

	case IDCANCEL:
		if (SendDlgItemMessage(IDC_EDIT, SCI_GETMODIFY, 0, 0))
		{
			// Prompt?
			int ret = uMessageBox(m_hWnd, "Save and apply changes?", m_caption, MB_ICONWARNING | MB_YESNOCANCEL);

			switch (ret)
			{
			case IDYES:
				Apply();
				EndDialog(IDOK);
				break;

			case IDCANCEL:
				return 0;
			}
		}

		EndDialog(IDCANCEL);
	}
	
	return 0;
}

LRESULT CDialogConf::OnScriptEngineCbnSelEndOk(WORD wNotifyCode, WORD wID, HWND hWndCtl)
{
	pfc::string8_fast text;
	HWND edit = GetDlgItem(IDC_EDIT);
	HWND combo = GetDlgItem(IDC_SCRIPT_ENGINE);
	int cursel = ComboBox_GetCurSel(combo);

	if (uComboBox_GetText(combo, cursel, text))
	{
		sci_set_lexer(edit, text);
	}

	return 0;
}

LRESULT CDialogConf::OnResetDefault(WORD wNotifyCode, WORD wID, HWND hWndCtl)
{
	pfc::string8 code;
	HWND edit = GetDlgItem(IDC_EDIT);
	HWND combo = GetDlgItem(IDC_SCRIPT_ENGINE);

	wsh_panel_vars::get_default_script_code(code);
	uComboBox_SelectString(combo, "JScript");
	sci_set_text(edit, code);
	return 0;
}

LRESULT CDialogConf::OnResetCurrent(WORD wNotifyCode, WORD wID, HWND hWndCtl)
{
	HWND edit = GetDlgItem(IDC_EDIT);
	HWND combo = GetDlgItem(IDC_SCRIPT_ENGINE);

	uComboBox_SelectString(combo, m_parent->get_script_name());			
	sci_set_text(edit, m_parent->get_script_code());
	return 0;
}

LRESULT CDialogConf::OnImport(WORD wNotifyCode, WORD wID, HWND hWndCtl)
{
	HWND edit = GetDlgItem(IDC_EDIT);
	pfc::string8 filename;

	if (uGetOpenFileName(m_hWnd, "Text files|*.txt;*.text|JScript files|*.js|All files|*.*", 0, "txt", "Import from", NULL, filename, FALSE))
	{
		// Open file
		file_ptr io;
		abort_callback_dummy abort;
		t_filesize filesize;
		pfc::string8 text;
		const unsigned char utf8_bom[] = {0xef, 0xbb, 0xbf};
		const unsigned char utf16_le[] = {0xff, 0xfe};
		unsigned char sig[3] = { 0 };

		try
		{
			filesystem::g_open(io, filename, filesystem::open_mode_read, abort);
			filesize = io->get_size(abort);
			io->seek(0, abort);

			if (filesize < 3) // 3 Bytes is enough to estimate
				return 0;

			io->read(sig, 3, abort);
		}
		catch (std::exception &)
		{
			return 0;
		}

		if (memcmp(utf8_bom, sig, 3) == 0) // utf8
		{
			try
			{
				io->read_string_raw(text, abort);
			}
			catch (std::exception &)
			{
				return 0;
			}
		}
		else if (memcmp(utf16_le, sig, 2) == 0)  // utf16 le
		{
			pfc::stringcvt::string_utf8_from_wide conv;
			t_size ac_size = (t_size)(filesize - 2) >> 1;
			pfc::array_t<WCHAR> buff;

			buff.set_size(ac_size + 1);
			buff[ac_size] = 0;

			try
			{
				io->seek(2, abort);
				io->read(buff.get_ptr(), ac_size << 1, abort);
			}
			catch (std::exception &)
			{
				return 0;
			}

			conv.convert(buff.get_ptr());
			text = conv;
		}
		else  // assume it's ansi
		{
			pfc::stringcvt::string_utf8_from_ansi conv;
			pfc::string8 str;

			try
			{
				io->seek(0, abort);
				io->read_string_raw(str, abort);
			}
			catch (std::exception &)
			{
				return 0;
			}

			conv.convert(str);
			text = conv;
		}

		sci_set_text(edit, text);
	}

	return 0;
}

LRESULT CDialogConf::OnExport(WORD wNotifyCode, WORD wID, HWND hWndCtl)
{
	pfc::string8 filename;

	if (uGetOpenFileName(m_hWnd, "Text files|*.txt|All files|*.*", 0, "txt", "Save as", NULL, filename, TRUE))
	{
		file_ptr io;
		abort_callback_dummy abort;
		const unsigned char utf8_bom[] = {0xef, 0xbb, 0xbf};
		HWND edit = GetDlgItem(IDC_EDIT);
		int len = SendMessage(edit, SCI_GETTEXTLENGTH, 0, 0);
		pfc::array_t<char> code;

		code.set_size(len + 1);
		SendMessage(edit, SCI_GETTEXT, (WPARAM)len + 1 , (LPARAM)code.get_ptr());

		try
		{
			filesystem::g_open_write_new(io, filename, abort);
			io->write(utf8_bom, sizeof(utf8_bom), abort);
			io->write_string_raw(code.get_ptr(), abort);
		}
		catch (std::exception &)
		{
			return 0;
		}
	}

	return 0;
}

void CDialogConf::Apply()
{
	pfc::string8 name;
	pfc::array_t<char> code;
	int len = 0;

	// Get engine name
	uGetWindowText(GetDlgItem(IDC_SCRIPT_ENGINE), name);
	// Get script text
	len = SendDlgItemMessage(IDC_EDIT, SCI_GETTEXTLENGTH, 0, 0);
	code.set_size(len + 1);
	SendDlgItemMessage(IDC_EDIT, SCI_GETTEXT, (WPARAM)len + 1, (LPARAM)code.get_ptr());

	m_parent->get_edge_style() = static_cast<t_edge_style>(ComboBox_GetCurSel(GetDlgItem(IDC_EDGE_STYLE)));
	m_parent->get_disabled() = false;
	m_parent->get_grab_focus() = uButton_GetCheck(m_hWnd, IDC_CHECK_GRABFOCUS);
	m_parent->get_pseudo_transparent() = uButton_GetCheck(m_hWnd, IDC_CHECK_PSEUDO_TRANSPARENT);
	m_parent->on_update_script(name, code.get_ptr());

	// Wndow position
	GetWindowPlacement(&m_parent->get_wndpl());

	// Save point
	SendDlgItemMessage(IDC_EDIT, SCI_SETSAVEPOINT, 0, 0);
}

LRESULT CDialogConf::OnNotify(int idCtrl, LPNMHDR pnmh)
{
	SCNotification * notification = (SCNotification *)pnmh;

	switch (pnmh->code)
	{
	case SCN_UPDATEUI:
		sci_match_brace(GetDlgItem(IDC_EDIT));
		break;

	case SCN_CHARADDED:
		sci_auto_indent(GetDlgItem(IDC_EDIT), notification->ch);
		break;

	case SCN_ZOOM:
		sci_auto_margin_width(GetDlgItem(IDC_EDIT));
		break;

		// dirty
	case SCN_SAVEPOINTLEFT:
		{
			pfc::string8 caption = m_caption;

			caption += " *";
			uSetWindowText(m_hWnd, caption);
		}
		break;

		// not dirty
	case SCN_SAVEPOINTREACHED:
		uSetWindowText(m_hWnd, m_caption);
		break;
	}

	return 0; 
}

void CDialogConf::OnFinalMessage(HWND hWnd)
{
	//g_config_dlg_mgr.remove_window(m_hWnd);
	// Remove subclass chain
	RemoveWindowSubclass(GetDlgItem(IDC_EDIT), EditorSubclassFunc, 0);
}

LRESULT CDialogConf::OnScenChange(WORD wNotifyCode, WORD wID, HWND hWndCtl)
{
	sci_auto_margin_width(GetDlgItem(IDC_EDIT));
	return 0;
}

LRESULT CDialogConf::OnUmDialogStyleReload(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	HWND edit = GetDlgItem(IDC_EDIT);

	// Reload styles
	sci_reload_style(edit);
	return 0;
}

void CDialogConf::MatchShortcuts(unsigned vk)
{
	int modifiers = 
		(IsKeyPressed(VK_SHIFT) ? SCMOD_SHIFT : 0) |
		(IsKeyPressed(VK_CONTROL) ? SCMOD_CTRL : 0) |
		(IsKeyPressed(VK_MENU) ? SCMOD_ALT : 0);

	// Hotkey
	if (modifiers == SCMOD_CTRL)
	{
		switch (vk)
		{
		case 'F':
			{
				if (!m_dlgfind)
				{
					// Create it on request.
					m_dlgfind = new CDialogFind(GetDlgItem(IDC_EDIT));
					
					if (!m_dlgfind || !m_dlgfind->Create(m_hWnd))
						break;
				}

				m_dlgfind->ShowWindow(SW_SHOW);
				m_dlgfind->SetFocus();
			}
			break;

		case 'H':
			{
				if (!m_dlgreplace)
				{
					m_dlgreplace = new CDialogReplace(GetDlgItem(IDC_EDIT));
					
					if (!m_dlgreplace || !m_dlgreplace->Create(m_hWnd))
						break;
				}

				m_dlgreplace->ShowWindow(SW_SHOW);
				m_dlgreplace->SetFocus();
			}
			break;

		case 'G':
			{
				CDialogGoto dlg(GetDlgItem(IDC_EDIT));
				dlg.DoModal(m_hWnd);
			}
			break;

		case 'S':
			Apply();
			break;
		}
	}
}

LRESULT CALLBACK CDialogConf::EditorSubclassFunc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
	CDialogConf * pDlg = reinterpret_cast<CDialogConf *>(dwRefData);
	// Must be first
	LRESULT ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);

	if (uMsg == WM_KEYDOWN)
	{
		pDlg->MatchShortcuts(wParam);
	}

	return ret;
}

LRESULT CDialogConf::OnCheckPseudoTransparentBnClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl)
{
	::EnableWindow(GetDlgItem(IDC_EDGE_STYLE), !uButton_GetCheck(m_hWnd, IDC_CHECK_PSEUDO_TRANSPARENT));
	return 0;
}
