#include <common/richedit.hpp>
#include <common/font.hpp>
#include <common/charform.hpp>
#include <common/purehdc.hpp>
#include <common/gdipoint.hpp>
#include <common/chrrange.hpp>

RichEditControl::RichEditControl(void)
: mhLibInst(0)
{
  loadLibrary();
	getLogPixelsy();
}

RichEditControl::RichEditControl(HWND hControlWnd,BOOL destroyWindow)
: Control(hControlWnd,destroyWindow), mhLibInst(0)
{
  loadLibrary();
	getLogPixelsy();
}

RichEditControl::~RichEditControl()
{
  freeLibrary();
}

BOOL RichEditControl::createControl(GUIWindow &parentWnd,const Rect &initRect,UINT controlID,UINT styles)
{
  Control::createControl(WS_EX_CLIENTEDGE,"RICHEDIT","",WS_VISIBLE|WS_CLIPCHILDREN|WS_CLIPSIBLINGS|ES_MULTILINE|ES_SUNKEN|ES_SAVESEL|ES_AUTOHSCROLL|ES_AUTOVSCROLL|styles,initRect,parentWnd,controlID);
	if(!isValid())return FALSE;
	return isValid();
}

void RichEditControl::loadLibrary(void)
{
  freeLibrary();
	mhLibInst=::LoadLibrary("RICHED32.DLL");
}

void RichEditControl::freeLibrary(void)
{
  if(!mhLibInst)return;
	::FreeLibrary(mhLibInst);
}

BOOL RichEditControl::setBkGndColor(const RGBColor &bkGndColor)const
{
  if(!isValid())return FALSE;
	sendMessage(EM_SETBKGNDCOLOR,0,(COLORREF)bkGndColor);
  return TRUE;  
}

BOOL RichEditControl::limitText(DWORD cchMax)const
{
  if(!isValid())return FALSE;
	sendMessage(EM_EXLIMITTEXT,0,(LPARAM)cchMax?cchMax:MaxText);
	return TRUE;
}

BOOL RichEditControl::findText(FindTextEx &findTextEx,BOOL matchCase,BOOL wholeWord)
{
  if(!isValid())return FALSE;
	if(-1==sendMessage(EM_FINDTEXTEX,0,(LPARAM)&(findTextEx.findTextEx())))return FALSE;
	sendMessage(EM_SETSEL,0,0);
	setFocus();
	scrollLine(lineFromCharPos(findTextEx.foundRange().posMin()));  // getCaretPosition()
	sendMessage(EM_SETSEL,findTextEx.foundRange().posMin(),findTextEx.foundRange().posMax());
  return TRUE;
}

BOOL RichEditControl::setReadOnly(BOOL isReadOnly)const
{
  if(!isValid())return FALSE;
	return sendMessage(EM_SETREADONLY,(WPARAM)isReadOnly,0L);
}

String RichEditControl::getLine(int lineNumber)const
{
  String strControl;

	if(!isValid())return strControl;
	strControl.reserve(MaxLine);
  *((int*)(char*)strControl)=MaxLine;
	sendMessage(EM_GETLINE,(WPARAM)lineNumber,(LPARAM)(LPSTR)strControl);
	return strControl;
}

BOOL RichEditControl::getSelectedText(String &strText)const
{
  LONG charCount;
  if(!isValid())return FALSE;
	strText.reserve(MaxText);
	charCount=sendMessage(EM_GETSELTEXT,(WPARAM)0,(LPARAM)(LPSTR)strText);
	return charCount?TRUE:FALSE;
}

BOOL RichEditControl::pasteSpecial(UINT cbFormat)const
{
  if(!isValid())return FALSE;
	sendMessage(EM_PASTESPECIAL,(WPARAM)cbFormat,0);
	return TRUE;
}

BOOL RichEditControl::cutSelection(BOOL canUndo)const
{
  return replaceSelection(String(),canUndo);
}

BOOL RichEditControl::replaceSelection(const String &strReplacementText,BOOL canUndo)const
{
  if(!isValid())return FALSE;
	sendMessage(EM_REPLACESEL,(WPARAM)canUndo,strReplacementText.isNull()?(LPARAM)0:(LPARAM)(LPSTR)(String&)strReplacementText);
	return TRUE;
}

int RichEditControl::lineFromCharPos(int charPos)
{
  if(!isValid())return 0;
	return sendMessage(EM_LINEFROMCHAR,(WPARAM)charPos,0);
}

BOOL RichEditControl::getLines(Block<String> &strLines)
{
  int lines(lineCount());

	for(int lineIndex=0;lineIndex<lines;lineIndex++)strLines.insert(&getLine(lineIndex));
	return (strLines.size()?TRUE:FALSE);
}

String RichEditControl::getCurrentLine(void)const
{
  String strControl;
  if(!isValid())return strControl; 
	strControl=getLine(currentLine());
	return strControl;
}

int RichEditControl::firstVisibleLine(void)const
{
  if(!isValid())return 0;
	return sendMessage(EM_GETFIRSTVISIBLELINE,0,0L);
}

int RichEditControl::lineCount(void)const
{
  if(!isValid())return 0;
	return sendMessage(EM_GETLINECOUNT,0,0L);
}

int RichEditControl::lineIndex(int lineIndex)const
{
  if(!isValid())return -1;
	return sendMessage(EM_LINEINDEX,(WPARAM)lineIndex,0L);
}

int RichEditControl::currentLine(void)const
{
  if(!isValid())return 0;
	return sendMessage(EM_LINEFROMCHAR,(WPARAM)-1,0L);
}

BOOL RichEditControl::wantReturn(BOOL wantReturn)const
{
  if(!isValid())return FALSE;
	sendMessage(EM_SETOPTIONS,ECOOP_OR,ECO_WANTRETURN);
	return TRUE;
}

BOOL RichEditControl::scrollCaret(void)const
{
  if(!isValid())return FALSE;
	return sendMessage(EM_SCROLLCARET,0,0L);
}

BOOL RichEditControl::scroll(ScrollAction scrollAction)const
{
  if(!isValid())return FALSE;
	sendMessage(EM_SCROLL,(WPARAM)scrollAction,0L);
	return TRUE;
}

BOOL RichEditControl::scrollLine(int cyScroll)const
{
  if(!isValid())return FALSE;
	return sendMessage(EM_LINESCROLL,0,cyScroll);
}

void RichEditControl::getLogPixelsy(void)
{
  PureDevice screenDevice;
	screenDevice.screenDevice();
	mLogPixelsy=::GetDeviceCaps(screenDevice,LOGPIXELSY);
}

void RichEditControl::copyClipboard(void)
{
  if(!isValid())return;
	sendMessage(WM_COPY,0,0L);
}

BOOL RichEditControl::setTextColor(const RGBColor &textColor)const
{
  if(!isValid())return FALSE;
  CharFormat charFormat;
  sendMessage(EM_GETCHARFORMAT,0,(LPARAM)(LPSTR)&((CHARFORMAT&)charFormat));
	charFormat.mask(CharFormat::MaskColor);
	charFormat.effects(0);
	charFormat.textColor(textColor);
	sendMessage(EM_SETCHARFORMAT,SCF_ALL,(LPARAM)(LPSTR)&((CHARFORMAT&)charFormat));
	return TRUE;
}

BOOL RichEditControl::setFont(const Font &someFont)const
{
  if(!isValid())return FALSE;
	CharFormat charFormat;
  sendMessage(EM_GETCHARFORMAT,0,(LPARAM)(LPSTR)&((CHARFORMAT&)charFormat));
	charFormat.mask(CharFormat::MaskCharSet|CharFormat::MaskFace|CharFormat::MaskSize);
	charFormat.effects(0);
	charFormat.charSet(someFont.charSet());
	charFormat.yHeight(-(((int)someFont.sizeFont()*mLogPixelsy)/72));
	charFormat.pitchAndFamily(someFont.pitchAndFamily());
	charFormat.faceName(someFont.fontStyle());
	sendMessage(EM_SETCHARFORMAT,SCF_ALL,(LPARAM)(LPSTR)&((CHARFORMAT&)charFormat));
	return TRUE;
}

BOOL RichEditControl::setCharFormat(const String faceName,int charHeight)const
{
  if(!isValid())return FALSE;
	CharFormat charFormat;
	charFormat.mask(CharFormat::MaskCharSet|CharFormat::MaskFace|CharFormat::MaskSize);
	charFormat.effects(0);
	charFormat.charSet(0);
	charFormat.yHeight(charHeight);
	charFormat.faceName(faceName);
	sendMessage(EM_SETCHARFORMAT,SCF_ALL,(LPARAM)(LPSTR)&((CHARFORMAT&)charFormat));
	return TRUE;
}

BOOL RichEditControl::isDirty(void)const
{
  if(!isValid())return FALSE;
	return sendMessage(EM_GETMODIFY,0,0L);
}

void RichEditControl::isDirty(BOOL isDirty)const
{
  if(!isValid())return;
	sendMessage(EM_SETMODIFY,(UINT)isDirty,0L);
}

void RichEditControl::setLimitRect(const Rect &limitRect)const
{
  if(!isValid())return;
	sendMessage(EM_SETRECT,0,(LPARAM)(RECT*)((Rect&)limitRect));
}

int RichEditControl::charFromPos(const GDIPoint &cursorPoint)
{
  if(!isValid())return 0;
	GDIPoint copyPoint(cursorPoint);
	return sendMessage(EM_CHARFROMPOS,0,(LPARAM)&((POINT&)copyPoint));
}

int RichEditControl::getCaretPosition(void)const
{
  CHARRANGE charRange;
	int row;
	int col;

  if(!isValid())return 0;
  sendMessage(EM_EXGETSEL,0,(LPARAM)&charRange);
	charRange.cpMax++;
	row=sendMessage(EM_LINEFROMCHAR,(WPARAM)charRange.cpMax,0L)+1;
	col=(charRange.cpMax-lineIndex())+1;
	return MAKELPARAM(row,col);
}

BOOL RichEditControl::setLine(int line,const String &strLine)const
{
  if(!selectLine(line))return FALSE;
	replaceSelection(strLine);
	return TRUE;
}

BOOL RichEditControl::selectLine(int line)const
{
  int currLineIndex;

	if(!isValid())return FALSE;
	if(-1==(currLineIndex=lineIndex(line)))return FALSE;
	return sendMessage(EM_SETSEL,(WPARAM)currLineIndex,(LPARAM)lineIndex(line+1));
}

void RichEditControl::getLimitRect(Rect &limitRect)const
{
  if(!isValid())return;
	sendMessage(EM_GETRECT,0,(LPARAM)(RECT*)limitRect);
}

void RichEditControl::setCaption(const String &strCaption)const
{
  if(strCaption.isNull())return;
	Control::setCaption(strCaption);
}

void RichEditControl::setCaption(Block<String> &codeLines)const
{
	if(!codeLines.size())return;
	String strLine;
	for(int lineIndex=0;lineIndex<codeLines.size();lineIndex++)strLine+=codeLines[lineIndex]+String("\n");
  Control::setCaption(strLine);
}

