/*
this file is part of notepad++
Copyright (C)2003 Don HO < donho@altern.org >

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either
version 2 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "WordStyleDlg.h"
#include "ScintillaEditView.h"
#include "SysMsg.h"

BOOL CALLBACK ColourStaticTextHooker::colourStaticProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	switch(Message)
    {
        case WM_PAINT:
        {

	        RECT rect;
            ::GetClientRect(hwnd, &rect);

            PAINTSTRUCT ps;
            HDC hdc = ::BeginPaint(hwnd, &ps);
    		
            ::SetTextColor(hdc, _colour);
            ::SetBkColor(hdc, ::GetSysColor(COLOR_3DFACE));
    		// Create a font 
		    if(_hFont == 0)
		    {
			    // Get the default GUI font
			    LOGFONT lf;
                HFONT hf = (HFONT)::GetStockObject(DEFAULT_GUI_FONT);

			    // Add UNDERLINE attribute
				//lf.lfUnderline = TRUE;

				::GetObject(hf, sizeof lf, &lf);
    			
			    // Create a new font
                _hFont = ::CreateFontIndirect(&lf);
		    }

			HANDLE hOld = SelectObject(hdc, _hFont);

		    // Draw the text!
            char text[MAX_PATH];
            ::GetWindowText(hwnd, text, sizeof(text));
            ::DrawText(hdc, text, -1, &rect, DT_LEFT);
    		
            ::SelectObject(hdc, hOld);

            ::EndPaint(hwnd, &ps);

		    return 0;
        }
    }
    return ::CallWindowProc(_oldProc, hwnd, Message, wParam, lParam);
}


BOOL CALLBACK WordStyleDlg::run_dlgProc(UINT Message, WPARAM wParam, LPARAM lParam)
{
	switch (Message)
	{
		case WM_INITDIALOG :
		{
			_lsArray = (NppParameters::getInstance())->getLStylerArray();
            _globalStyles = (NppParameters::getInstance())->getGlobalStylers();

			
			::SendDlgItemMessage(_hSelf, IDC_LANGUAGES_LIST, LB_ADDSTRING, 0, (LPARAM)"Global Styles");
			// All the lexers
            for (int i = 0 ; i < _lsArray.getNbLexer() ; i++)
            {
				::SendDlgItemMessage(_hSelf, IDC_LANGUAGES_LIST, LB_ADDSTRING, 0, (LPARAM)_lsArray.getLexerDescFromIndex(i));
            }

            _hStyleList = ::GetDlgItem(_hSelf, IDC_STYLES_LIST);
            _hCheckBold = ::GetDlgItem(_hSelf, IDC_BOLD_CHECK);
            _hCheckItalic = ::GetDlgItem(_hSelf, IDC_ITALIC_CHECK);
			_hCheckUnderline = ::GetDlgItem(_hSelf, IDC_UNDERLINE_CHECK);
			_hFontNameCombo = ::GetDlgItem(_hSelf, IDC_FONT_COMBO);
			_hFontSizeCombo = ::GetDlgItem(_hSelf, IDC_FONTSIZE_COMBO);

			_hFgColourStaticText = ::GetDlgItem(_hSelf, IDC_FG_STATIC);
			_hBgColourStaticText = ::GetDlgItem(_hSelf, IDC_BG_STATIC);
			_hFontNameStaticText = ::GetDlgItem(_hSelf, IDC_FONTNAME_STATIC);
			_hFontSizeStaticText = ::GetDlgItem(_hSelf, IDC_FONTSIZE_STATIC);
			_hStyleInfoStaticText = ::GetDlgItem(_hSelf, IDC_STYLEDEFAULT_WARNING_STATIC);

			colourHooker.setColour(RGB(0xFF, 0x00, 0x00));
			colourHooker.hookOn(_hStyleInfoStaticText);

			for(int i = 0 ; i < sizeof(fontSizeStrs)/3 ; i++)
				::SendMessage(_hFontSizeCombo, CB_ADDSTRING, 0, (LPARAM)fontSizeStrs[i]);

			const std::vector<std::string> & fontlist = (NppParameters::getInstance())->getFontList();
			for (size_t i = 0 ; i < fontlist.size() ; i++)
			{
				int j = ::SendMessage(_hFontNameCombo, CB_ADDSTRING, 0, (LPARAM)fontlist[i].c_str());
				::SendMessage(_hFontNameCombo, CB_SETITEMDATA, j, (LPARAM)fontlist[i].c_str());
			}

			_pFgColour = new ColourPicker;
			_pBgColour = new ColourPicker;
			_pFgColour->init(_hInst, _hSelf);
			_pBgColour->init(_hInst, _hSelf);

            POINT p1, p2;

            alignWith(_hFgColourStaticText, _pFgColour->getHSelf(), ALIGNPOS_RIGHT, p1);
            alignWith(_hBgColourStaticText, _pBgColour->getHSelf(), ALIGNPOS_RIGHT, p2);

            p1.x = p2.x = ((p1.x > p2.x)?p1.x:p2.x) + 10;
            p1.y -= 4; p2.y -= 4;

            ::MoveWindow((HWND)_pFgColour->getHSelf(), p1.x, p1.y, 25, 25, TRUE);
            ::MoveWindow((HWND)_pBgColour->getHSelf(), p2.x, p2.y, 25, 25, TRUE);
			_pFgColour->display();
			_pBgColour->display();

			const int index2Begin = 0;
			::SendDlgItemMessage(_hSelf, IDC_LANGUAGES_LIST, LB_SETCURSEL, 0, index2Begin);
			setStyleListFromLexer(index2Begin);
			::EnableWindow(::GetDlgItem(_hSelf, IDOK), _isDirty);
			::EnableWindow(::GetDlgItem(_hSelf, IDC_SAVECLOSE_BUTTON), !_isSync);

			goToCenter();
			return TRUE;
		}

		case WM_DESTROY:
		{
			_pFgColour->destroy();
			_pBgColour->destroy();
			delete _pFgColour;
			delete _pBgColour;
			return TRUE;
		}
		case WM_COMMAND : 
		{
			if (HIWORD(wParam) == EN_CHANGE)
            {
				int editID = LOWORD(wParam);
				if (editID == IDC_USER_KEYWORDS_EDIT)
				{
					updateUserKeywords();
					notifyDataModified();
				}
				else if (editID == IDC_USER_EXT_EDIT)
				{
					updateExtension();
					notifyDataModified();
				}
			}
			else
			{
				switch (wParam)
				{
					case IDC_BOLD_CHECK :
						updateFontStyleStatus(BOLD_STATUS);
						notifyDataModified();
						break;

					case IDC_ITALIC_CHECK :
						updateFontStyleStatus(ITALIC_STATUS);
						notifyDataModified();
						break;

					case IDC_UNDERLINE_CHECK :
						updateFontStyleStatus(UNDERLINE_STATUS);
						notifyDataModified();
						break;

					case IDCANCEL :
					if (_isDirty)
					{
						_lsArray = (NppParameters::getInstance())->getLStylerArray();
						_globalStyles = (NppParameters::getInstance())->getGlobalStylers();
						_isDirty = false;
                        setVisualFromStyleList();
					}
					::EnableWindow(::GetDlgItem(_hSelf, IDOK), FALSE);
			        ::EnableWindow(::GetDlgItem(_hSelf, IDC_SAVECLOSE_BUTTON), !_isSync);
					display(false);
					return TRUE;

					case IDOK : //_isDirty == true;
					{
						LexerStylerArray & lsa = (NppParameters::getInstance())->getLStylerArray();
						StyleArray & globalStyles = (NppParameters::getInstance())->getGlobalStylers();

						lsa = _lsArray;
						globalStyles = _globalStyles;

						::EnableWindow(::GetDlgItem(_hSelf, IDOK), FALSE);
						_isDirty = false;
						_isSync = false;
						::SendMessage(_hParent, WM_UPDATESCINTILLAS, 0, 0);
						return TRUE;
					}

					case IDC_SAVECLOSE_BUTTON :
					{
						if (_isDirty)
						{
							LexerStylerArray & lsa = (NppParameters::getInstance())->getLStylerArray();
							StyleArray & globalStyles = (NppParameters::getInstance())->getGlobalStylers();

							lsa = _lsArray;
							globalStyles = _globalStyles;

							::EnableWindow(::GetDlgItem(_hSelf, IDOK), FALSE);
							_isDirty = false;
						}
						(NppParameters::getInstance())->writeStyles(_lsArray, _globalStyles);
						::EnableWindow(::GetDlgItem(_hSelf, IDC_SAVECLOSE_BUTTON), FALSE);
						_isSync = true;
						display(false);
						::SendMessage(_hParent, WM_UPDATESCINTILLAS, 0, 0);
						return TRUE;
					}
					
					case IDC_SC_TRANSPARENT_CHECK :
					{
						bool isChecked = (BST_CHECKED == ::SendDlgItemMessage(_hSelf, IDC_SC_TRANSPARENT_CHECK, BM_GETCHECK, 0, 0));
						if (isChecked)
						{
							int percent = ::SendDlgItemMessage(_hSelf, IDC_SC_PERCENTAGE_SLIDER, TBM_GETPOS, 0, 0);
							(NppParameters::getInstance())->SetTransparent(_hSelf, percent);
						}
						else
							(NppParameters::getInstance())->removeTransparent(_hSelf);

						::EnableWindow(::GetDlgItem(_hSelf, IDC_SC_PERCENTAGE_SLIDER), isChecked);
						return TRUE;
					}

					default:
						switch (HIWORD(wParam))
						{
							case CBN_SELCHANGE : // == case LBN_SELCHANGE :
							{
								switch (LOWORD(wParam))
								{
									case IDC_FONT_COMBO :
										updateFontName();
										notifyDataModified();
										break;
									case IDC_FONTSIZE_COMBO :
										updateFontSize();
										notifyDataModified();
										break;
									case IDC_LANGUAGES_LIST :
									{
										int i = ::SendDlgItemMessage(_hSelf, LOWORD(wParam), LB_GETCURSEL, 0, 0);
										if (i != LB_ERR)
											setStyleListFromLexer(i);
										break;
									}
									case IDC_STYLES_LIST :
										setVisualFromStyleList();
										break;
								}
								return TRUE;
							}

							case CPN_COLOURPICKED:	
							{
								if ((HWND)lParam == _pFgColour->getHSelf())
								{
									updateColour(C_FOREGROUND);
									notifyDataModified();
									return TRUE;
								}
								else if ((HWND)lParam == _pBgColour->getHSelf())
								{
									updateColour(C_BACKGROUND);
									notifyDataModified();
									return TRUE;
								}
								else
									return FALSE;
							}

							default :
							{
								return FALSE;
							}
						}
						return TRUE;
				}
			}

		}
		default :
			return FALSE;
	}
	return FALSE;
}

void WordStyleDlg::updateColour(bool which)
{
	Style & style = getCurrentStyler();
	if (which == C_FOREGROUND)
	{
		style._fgColor = _pFgColour->getColour();
	}
	else //(which == C_BACKGROUND)
	{
		style._bgColor = _pBgColour->getColour();
	}
}

void WordStyleDlg::updateFontSize()
{
	Style & style = getCurrentStyler();
	int iFontSizeSel = ::SendMessage(_hFontSizeCombo, CB_GETCURSEL, 0, 0);

	char intStr[5];
	if (iFontSizeSel != 0)
	{
		::SendMessage(_hFontSizeCombo, CB_GETLBTEXT, iFontSizeSel, (LPARAM)intStr);
		if ((!intStr) || (!intStr[0])) 
			style._fontSize = -1;
		else
		{
			char *finStr;
			style._fontSize = strtol(intStr, &finStr, 10);
			if (*finStr != '\0')
				style._fontSize = -1;
		}
	}
	else
		style._fontSize = 0;
}

void WordStyleDlg::updateExtension()
{
	const int NB_MAX = 256;
	char ext[NB_MAX];
	::SendDlgItemMessage(_hSelf, IDC_USER_EXT_EDIT, WM_GETTEXT, NB_MAX, (LPARAM)ext);
	_lsArray.getLexerFromIndex(_currentLexerIndex - 1).setLexerUserExt(ext);
}

void WordStyleDlg::updateUserKeywords()
{
	Style & style = getCurrentStyler();
	//const int NB_MAX = 2048;
	//char kw[NB_MAX];
	int len = ::SendDlgItemMessage(_hSelf, IDC_USER_KEYWORDS_EDIT, WM_GETTEXTLENGTH, 0, 0);

	char *kw = new char[len];
	::SendDlgItemMessage(_hSelf, IDC_USER_KEYWORDS_EDIT, WM_GETTEXT, len, (LPARAM)kw);
	style.setKeywords(kw);

	delete [] kw;
}

void WordStyleDlg::updateFontName()
{
    Style & style = getCurrentStyler();
	int iFontSel = ::SendMessage(_hFontNameCombo, CB_GETCURSEL, 0, 0);
	char *fnStr = (char *)::SendMessage(_hFontNameCombo, CB_GETITEMDATA, iFontSel, 0);
	style._fontName = fnStr;
}

void WordStyleDlg::updateFontStyleStatus(fontStyleType whitchStyle)
{
    Style & style = getCurrentStyler();
	if (style._fontStyle == -1)
		style._fontStyle = 0;

	int fontStyle = FONTSTYLE_UNDERLINE;
	HWND hWnd = _hCheckUnderline;

	if (whitchStyle == BOLD_STATUS)
	{
		fontStyle = FONTSTYLE_BOLD;
		hWnd = _hCheckBold;
	}
	if (whitchStyle == ITALIC_STATUS)
	{
		fontStyle = FONTSTYLE_ITALIC;
		hWnd = _hCheckItalic;
	}

	int isChecked = ::SendMessage(hWnd, BM_GETCHECK, 0, 0);
	if (isChecked != BST_INDETERMINATE)
	{
		if (isChecked == BST_CHECKED)
			style._fontStyle |= fontStyle;
		else
			style._fontStyle &= ~fontStyle;
	}
}

void WordStyleDlg::setStyleListFromLexer(int index)
{
    _currentLexerIndex = index;

    // Fill out Styles listbox
    // Before filling out, we clean it
    ::SendMessage(_hStyleList, LB_RESETCONTENT, 0, 0);

	if (index)
	{
		const char *langName = _lsArray.getLexerNameFromIndex(index - 1);
		const char *ext = NppParameters::getInstance()->getLangExtFromName(langName);
		const char *userExt = (_lsArray.getLexerStylerByName(langName))->getLexerUserExt();
		::SendDlgItemMessage(_hSelf, IDC_DEF_EXT_EDIT, WM_SETTEXT, 0, (LPARAM)(ext));
		::SendDlgItemMessage(_hSelf, IDC_USER_EXT_EDIT, WM_SETTEXT, 0, (LPARAM)(userExt));
		//::SetWindowText(::GetDlgItem(_hSelf, IDC_USER_EXT_EDIT), userExt);
	}
	::ShowWindow(::GetDlgItem(_hSelf, IDC_DEF_EXT_EDIT), index?SW_SHOW:SW_HIDE);
    ::ShowWindow(::GetDlgItem(_hSelf, IDC_DEF_EXT_STATIC), index?SW_SHOW:SW_HIDE);
	::ShowWindow(::GetDlgItem(_hSelf, IDC_USER_EXT_EDIT), index?SW_SHOW:SW_HIDE);
    ::ShowWindow(::GetDlgItem(_hSelf, IDC_USER_EXT_STATIC), index?SW_SHOW:SW_HIDE);
	::ShowWindow(::GetDlgItem(_hSelf, IDC_PLUSSYMBOL2_STATIC), index?SW_SHOW:SW_HIDE);

	StyleArray & lexerStyler = index?_lsArray.getLexerFromIndex(index-1):_globalStyles;

    for (int i = 0 ; i < lexerStyler.getNbStyler() ; i++)
    {
        Style & style = lexerStyler.getStyler(i);
        ::SendMessage(_hStyleList, LB_ADDSTRING, 0, (LPARAM)style._styleDesc);	
    }
    ::SendMessage(_hStyleList, LB_SETCURSEL, 0, 0);
    setVisualFromStyleList();
}

void WordStyleDlg::setVisualFromStyleList() 
{

    Style & style = getCurrentStyler();

    //--Warning text
    bool showWarning = ((_currentLexerIndex == 0) && (style._styleID == STYLE_DEFAULT));//?SW_SHOW:SW_HIDE;

	COLORREF c = RGB(0xFF, 0x00, 0x00);
	char str[256];
	strcpy(str, _originalWarning);
    if (!showWarning)
	{
		if (!_originalWarning[0])
			// Get the original text for the usage afterward
			::GetWindowText(_hStyleInfoStaticText, _originalWarning, sizeof(_originalWarning));

		str[0] = '\0';
		c = RGB(0x00, 0x00, 0xFF);
		int i = ::SendDlgItemMessage(_hSelf, IDC_LANGUAGES_LIST, LB_GETCURSEL, 0, 0);
		if (i == LB_ERR)
			return;
		::SendDlgItemMessage(_hSelf, IDC_LANGUAGES_LIST, LB_GETTEXT, i, (LPARAM)str);

		i = ::SendDlgItemMessage(_hSelf, IDC_STYLES_LIST, LB_GETCURSEL, 0, 0);
		if (i == LB_ERR)
			return;
		char styleName[64];
		::SendDlgItemMessage(_hSelf, IDC_STYLES_LIST, LB_GETTEXT, i, (LPARAM)styleName);

		strcat(strcat(str, " : "), styleName);
	}
	else
	{
		if (!str[0])
		{
			::GetWindowText(_hStyleInfoStaticText, _originalWarning, sizeof(_originalWarning));
			strcpy(str, _originalWarning);
		}
	}
	colourHooker.setColour(c);
	::SetWindowText(_hStyleInfoStaticText, str);
	//::InvalidateRect(hColourTextStatic, NULL, TRUE);
	//::UpdateWindow(hColourTextStatic);

	//::ShowWindow(_hStyleInfoStaticText, showWarning);

	//-- 2 couleurs : fg et bg
	bool isEnable = false;
	if (HIBYTE(HIWORD(style._fgColor)) != 0xFF)
	{
		_pFgColour->setColour(style._fgColor);
		isEnable = true;
	}
	enableFg(isEnable);

	isEnable = false;
	if (HIBYTE(HIWORD(style._bgColor)) != 0xFF)
	{
		_pBgColour->setColour(style._bgColor);
		isEnable = true;
	}
	enableBg(isEnable);

	//-- font name
	isEnable = false;
	int iFontName;
	if (style._fontName != NULL)
	{
		iFontName = ::SendMessage(_hFontNameCombo, CB_FINDSTRING, 1, (LPARAM)style._fontName);
		if (iFontName == CB_ERR)
			iFontName = 0;
		isEnable = true;
	}
	else
	{
		iFontName = 0;
	}
	::SendMessage(_hFontNameCombo, CB_SETCURSEL, iFontName, 0);
	enableFontName(isEnable);

	//-- font size
	isEnable = false;
	char intStr[5] = "";
	int iFontSize = 0;
	if (style._fontSize != -1)
	{
		sprintf(intStr, "%d", style._fontSize);
		iFontSize = ::SendMessage(_hFontSizeCombo, CB_FINDSTRING, 1, (LPARAM)intStr);
		isEnable = true;
	}
	::SendMessage(_hFontSizeCombo, CB_SETCURSEL, iFontSize, 0);
	enableFontSize(isEnable);

	//-- font style : bold et italic
	isEnable = false;
	int isBold, isItalic, isUnderline;
	if (style._fontStyle != -1)
	{
		isBold = (style._fontStyle & FONTSTYLE_BOLD)?BST_CHECKED:BST_UNCHECKED;
		isItalic = (style._fontStyle & FONTSTYLE_ITALIC)?BST_CHECKED:BST_UNCHECKED;
		isUnderline = (style._fontStyle & FONTSTYLE_UNDERLINE)?BST_CHECKED:BST_UNCHECKED;
		::SendMessage(_hCheckBold, BM_SETCHECK, isBold, 0);
		::SendMessage(_hCheckItalic, BM_SETCHECK, isItalic, 0);
		::SendMessage(_hCheckUnderline, BM_SETCHECK, isUnderline, 0);
		isEnable = true;
	}
	else // -1 est comme 0
	{
		::SendMessage(_hCheckBold, BM_SETCHECK, BST_UNCHECKED, 0);
		::SendMessage(_hCheckItalic, BM_SETCHECK, BST_UNCHECKED, 0);
		::SendMessage(_hCheckUnderline, BM_SETCHECK, BST_UNCHECKED, 0);
	}

    enableFontStyle(isEnable);


	//-- Default Keywords
	bool shouldBeDisplayed = style._keywordClass != -1;
	if (shouldBeDisplayed)
	{
		LexerStyler & lexerStyler = _lsArray.getLexerFromIndex(_currentLexerIndex - 1);

		NppParameters *pNppParams = NppParameters::getInstance();
		LangType lType = pNppParams->getLangIDFromStr(lexerStyler.getLexerName());
		if (lType == L_TXT)
		{
			string str = lexerStyler.getLexerName();
			str += " is not defined in NppParameters::getLangIDFromStr()";
				printStr(str.c_str());
		}
		const char *kws = pNppParams->getWordList(lType, style._keywordClass);
		if (!kws)
			kws = "";
		::SendDlgItemMessage(_hSelf, IDC_DEF_KEYWORDS_EDIT, WM_SETTEXT, 0, (LPARAM)(kws));

		const char *ckwStr = (style._keywords)?style._keywords->c_str():"";
		::SendDlgItemMessage(_hSelf, IDC_USER_KEYWORDS_EDIT, WM_SETTEXT, 0, (LPARAM)(ckwStr));
	}
	int showOption = shouldBeDisplayed?SW_SHOW:SW_HIDE;
	::ShowWindow(::GetDlgItem(_hSelf, IDC_DEF_KEYWORDS_EDIT), showOption);
	::ShowWindow(::GetDlgItem(_hSelf, IDC_USER_KEYWORDS_EDIT),showOption);
	::ShowWindow(::GetDlgItem(_hSelf, IDC_DEF_KEYWORDS_STATIC), showOption);
	::ShowWindow(::GetDlgItem(_hSelf, IDC_USER_KEYWORDS_STATIC),showOption);
	::ShowWindow(::GetDlgItem(_hSelf, IDC_PLUSSYMBOL_STATIC),showOption);

    redraw();
}

void WordStyleDlg::create(int dialogID, bool isRTL)
{
	StaticDialog::create(dialogID, isRTL);

	if ((NppParameters::getInstance())->isTransparentAvailable())
	{
		::ShowWindow(::GetDlgItem(_hSelf, IDC_SC_TRANSPARENT_CHECK), SW_SHOW);
		::ShowWindow(::GetDlgItem(_hSelf, IDC_SC_PERCENTAGE_SLIDER), SW_SHOW);
		
		::SendDlgItemMessage(_hSelf, IDC_SC_PERCENTAGE_SLIDER, TBM_SETRANGE, FALSE, MAKELONG(20, 200));
		::SendDlgItemMessage(_hSelf, IDC_SC_PERCENTAGE_SLIDER, TBM_SETPOS, TRUE, 150);
		if (!(BST_CHECKED == ::SendDlgItemMessage(_hSelf, IDC_SC_PERCENTAGE_SLIDER, BM_GETCHECK, 0, 0)))
			::EnableWindow(::GetDlgItem(_hSelf, IDC_SC_PERCENTAGE_SLIDER), FALSE);
	}
}

