#include <common/infowin.hpp>
#include <common/purehdc.hpp>

char InfoWindow::smszClassName[]={"InfoWin"};

InfoWindow::InfoWindow(Window &parentWindow,WORD windowWidth,WORD windowHeight)
: mCreateHandler(this,&InfoWindow::createHandler),
	mPaintHandler(this,&InfoWindow::paintHandler),
	mDestroyHandler(this,&InfoWindow::destroyHandler),
	mCloseHandler(this,&InfoWindow::closeHandler),
	mIsDestroyed(FALSE), mParentWindow(parentWindow),
	mhInfoFont(0), mCharHeight(0), mWindowWidth(windowWidth), 
	mWindowHeight(windowHeight)
{
	createInfoFont();
#ifdef __FLAT__
	mhInstance=(HINSTANCE)::GetWindowLong(mParentWindow,GWL_HINSTANCE);
#else
	mhInstance=(HINSTANCE)::GetWindowWord(mParentWindow,GWW_HINSTANCE);
#endif
	insertHandler(VectorHandler::CreateHandler,&mCreateHandler);
	insertHandler(VectorHandler::PaintHandler,&mPaintHandler);
	insertHandler(VectorHandler::DestroyHandler,&mDestroyHandler);
	insertHandler(VectorHandler::CloseHandler,&mCloseHandler);
	registerClass();
	createInfoWindow();
}

void InfoWindow::setCaption(String captionString)
{
	if(!captionString.isNull())::SetWindowText(*this,captionString);
}

void InfoWindow::createInfoFont()
{
	TEXTMETRIC tm;
	HFONT hOldFont;
	int fontHeight;
	HDC hDC(::GetDC(0));

	fontHeight=::MulDiv(-10,::GetDeviceCaps(hDC,LOGPIXELSY),72);
	mhInfoFont=::CreateFont(fontHeight,0,0,0,FW_BOLD,0,0,0,
		ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
		DEFAULT_QUALITY,VARIABLE_PITCH|FF_SWISS,"Helv");
	hOldFont=(HFONT)::SelectObject(hDC,mhInfoFont);
  ::GetTextMetrics(hDC,&tm);
	::SelectObject(hDC,hOldFont);
	::ReleaseDC(NULL,hDC);
	mCharHeight=tm.tmHeight+tm.tmExternalLeading;
}

void InfoWindow::createInfoWindow(void)
{
	RECT windowRect;

	::SetRect(&windowRect,mTopLeftPoint.x(),mTopLeftPoint.y(),mWindowWidth,mWindowHeight);
	::CreateWindow((LPSTR)smszClassName,(LPSTR)smszClassName,WS_CAPTION|WS_CHILD,
		windowRect.left,windowRect.top,windowRect.right,windowRect.bottom,
		mParentWindow,0x00,mhInstance,(LPSTR)(Window*)this);
	return;
}

void InfoWindow::show(int showWindow)
{
	if(showWindow){Window::show(SW_SHOW);update();}
  else Window::show(SW_HIDE);
}

InfoWindow::~InfoWindow()
{
	if(::IsWindow(*this))::DestroyWindow(*this);
	if(mhInfoFont)::DeleteObject(mhInfoFont);
	removeHandlers();
}

void InfoWindow::removeHandlers(void)
{
	removeHandler(VectorHandler::CreateHandler,&mCreateHandler);
	removeHandler(VectorHandler::PaintHandler,&mPaintHandler);
	removeHandler(VectorHandler::DestroyHandler,&mDestroyHandler);
	removeHandler(VectorHandler::CloseHandler,&mCloseHandler);
}

void InfoWindow::registerClass(void)
{
	WNDCLASS wndClass;

	if(::GetClassInfo(mhInstance,smszClassName,(WNDCLASS FAR *)&wndClass))return;
	wndClass.style	       =CS_HREDRAW|CS_VREDRAW;
	wndClass.lpfnWndProc	 =(WNDPROC)Window::WndProc;
	wndClass.cbClsExtra	   =0;
	wndClass.cbWndExtra	   =sizeof(InfoWindow*);
	wndClass.hInstance	   =mhInstance;
	wndClass.hIcon	       =0;
	wndClass.hCursor	     =(HCURSOR)::LoadCursor(NULL,IDC_ARROW);
	wndClass.hbrBackground =(HBRUSH)::GetStockObject(LTGRAY_BRUSH);
	wndClass.lpszMenuName	 =0;
	wndClass.lpszClassName =smszClassName;
	::RegisterClass(&wndClass);
}

CallbackData::ReturnType InfoWindow::createHandler(CallbackData &/*someCallbackData*/)
{
	::SendMessage(*this,WM_NCACTIVATE,TRUE,0L);
	return (CallbackData::ReturnType)TRUE;
}

CallbackData::ReturnType InfoWindow::paintHandler(CallbackData &someCallbackData)
{
	PaintInformation *lpPaintInformation=(PaintInformation*)someCallbackData.lParam();

	paint((PureDevice)*(lpPaintInformation));
	return (CallbackData::ReturnType)FALSE;
}

CallbackData::ReturnType InfoWindow::destroyHandler(CallbackData &/*someCallbackData*/)
{
	mIsDestroyed=TRUE;
	return (CallbackData::ReturnType)FALSE;
}

CallbackData::ReturnType InfoWindow::closeHandler(CallbackData &/*someCallbackData*/)
{
	::DestroyWindow(*this);
	mIsDestroyed=TRUE;
	return (CallbackData::ReturnType)FALSE;
}

void InfoWindow::paint(PureDevice &windowDevice)
{
	RECT clientRect;
	RECT tempRect;
	HBRUSH hTempBrush;

	::GetClientRect(*this,(RECT FAR *)&clientRect);
	hTempBrush=::CreateSolidBrush(::GetSysColor(COLOR_BTNFACE));
	::FillRect((HDC)windowDevice,(RECT FAR*)&clientRect,hTempBrush);
	::DeleteObject(hTempBrush);

	hTempBrush=::CreateSolidBrush(::GetSysColor(COLOR_BTNSHADOW));
	tempRect=clientRect;
	tempRect.top+=HeightBorderValue;
	tempRect.left+=WidthBorderValue;
	tempRect.right-=WidthBorderValue;
	tempRect.bottom=tempRect.top+1;
	::FillRect((HDC)windowDevice,(RECT FAR*)&tempRect,hTempBrush);

	tempRect=clientRect;
	tempRect.left+=WidthBorderValue;
	tempRect.right=tempRect.left+1;
	tempRect.top+=HeightBorderValue;
	tempRect.bottom-=HeightBorderValue;
	::FillRect((HDC)windowDevice,(RECT FAR*)&tempRect,hTempBrush);
	::DeleteObject(hTempBrush);

	hTempBrush=::CreateSolidBrush(::GetSysColor(COLOR_BTNHIGHLIGHT));
	tempRect=clientRect;
	tempRect.bottom-=HeightBorderValue;
	tempRect.top=tempRect.bottom-1;
	tempRect.left+=WidthBorderValue;
	tempRect.right-=WidthBorderValue;
	::FillRect((HDC)windowDevice,(RECT FAR*)&tempRect,hTempBrush);

	tempRect=clientRect;
	tempRect.bottom-=HeightBorderValue;
	tempRect.top+=HeightBorderValue;
	tempRect.right-=WidthBorderValue;
	tempRect.left=tempRect.right-1;
	::FillRect((HDC)windowDevice,(RECT FAR*)&tempRect,hTempBrush);
	::DeleteObject(hTempBrush);
	combineLabelText();
}

void InfoWindow::makeBorderOffsetRect(RECT &borderRect,RECT &clientRect)const
{
	borderRect=clientRect;
	borderRect.top+=(HeightBorderValue+TextVertBorderOffset);
	borderRect.bottom-=(HeightBorderValue+TextVertBorderOffset);
	borderRect.left+=(WidthBorderValue+TextHorzBorderOffset);
	borderRect.right-=(WidthBorderValue+TextHorzBorderOffset);
}

void InfoWindow::setLineText(WORD lineNumber,String lineText)
{
	String tempString;

	if(lineText.isNull()||!lineNumber)return;
	--lineNumber;
	if(lineNumber>=mLineText.size())return;
	mLineText[lineNumber]=lineText;
	if(lineNumber<mLabelText.size())tempString=mLabelText[lineNumber];
	tempString+=lineText;
	drawText(++lineNumber,tempString);
}

void InfoWindow::setLineText(Block<String> &lineText,WORD refreshDisplay)
{
	size_t numLines((size_t)lineText.size());

	mLineText.remove();
	if(!numLines)return;
	for(int itemIndex=0;itemIndex<numLines;itemIndex++)
		if(!lineText[itemIndex].isNull())mLineText.insert(&lineText[itemIndex]);
	if(refreshDisplay)combineLabelText();
}

void InfoWindow::setLabelText(Block<String> &labelText,WORD refreshDisplay)
{
	size_t numLabels((size_t)labelText.size());

	mLabelText.remove();
	if(!numLabels)return;
	for(int itemIndex=0;itemIndex<numLabels;itemIndex++)
		if(!labelText[itemIndex].isNull())mLabelText.insert(&labelText[itemIndex]);
	if(refreshDisplay)combineLabelText();
}

void InfoWindow::combineLabelText(void)
{
	size_t numLines((size_t)mLineText.size());
	size_t numLabels((size_t)mLabelText.size());
	size_t numThings(numLines>numLabels?numLines:numLabels);

	for(int itemIndex=0;itemIndex<numThings;itemIndex++)
	{
		String displayString;
		if(itemIndex<numLabels)displayString+=mLabelText[itemIndex];
		if(itemIndex<numLines)displayString+=mLineText[itemIndex];
		if(!displayString.isNull())drawText(itemIndex+1,displayString);
	}
}

void InfoWindow::drawText(WORD lineNumber,String lineText)
{
	RECT clientRect;
	RECT borderRect;
	HFONT hOldFont;
	PureDevice windowDevice;

	if(!lineNumber)return;
	windowDevice=*this;
	::GetClientRect(*this,(RECT FAR *)&clientRect);
	makeBorderOffsetRect(borderRect,clientRect);
	hOldFont=(HFONT)::SelectObject(windowDevice,mhInfoFont);
	::SetTextColor(windowDevice,::GetSysColor(COLOR_BTNTEXT));
	::SetBkColor(windowDevice,::GetSysColor(COLOR_BTNFACE));
	clientRect.top=(lineNumber*TextVertBorderOffset)+(mCharHeight*(lineNumber-1))+HeightBorderValue+1;
	clientRect.left+=WidthBorderValue+TextHorzBorderOffset;
	clientRect.bottom=clientRect.top+mCharHeight;
	clientRect.right-=(WidthBorderValue+TextHorzBorderOffset);
	if(clientRect.bottom<=borderRect.bottom+OffsetCaption)
	  ::ExtTextOut(windowDevice,clientRect.left,clientRect.top,
			ETO_OPAQUE|ETO_CLIPPED,&clientRect,(LPSTR)lineText,lineText.length(),0);
	::SelectObject(windowDevice,hOldFont);
}

void InfoWindow::setLocation(const Point &topLeftPoint)
{
	Point mTopLeftPoint;

	mTopLeftPoint=topLeftPoint;
  move(mTopLeftPoint);
}

