//
//	Copyright © 2006 Nemetschek North America 
//	All Rights Reserved.
//
// Created by Vladislav Stanev

#include "StdHeaders.h"

#include "CustomCtrlDrawing.h"

#include "VectorWorks/ISDK.h"

using namespace VectorWorks;
using namespace VectorWorks::VWUI;

// ----------------------------------------------------------------------------------------
namespace VectorWorks
{
	namespace VWUI
	{
		struct SVisualPoint {
			ViewPt		pt;
			bool		bVisible;
		};

		typedef std::vector<SVisualPoint>	TPointsArray;
	}
}

// ----------------------------------------------------------------------------------------
VWCustomCtrlDC::VWCustomCtrlDC(unsigned long devHandle, void* devDC, ViewCoord xOffset, ViewCoord yOffset) :
	fpDrawPad( VectorWorks::IID_DrawPad ),
	fXOffset( xOffset ),
	fYOffset( yOffset )
{
	farrPolyPts		= new TPointsArray;

	fDevHandle		= devHandle;
	fpDevDC			= devDC;

	if ( fpDrawPad == NULL || VCOM_FAILED( fpDrawPad->InitializeInDevice( devHandle, devDC ) ) ) {
		// error! release and use empty instance
		fpDrawPad	= TDrawPad();
	}
}

VWCustomCtrlDC::VWCustomCtrlDC(ViewCoord width, ViewCoord height) :
	fpDrawPad( VectorWorks::IID_DrawPad ),
	fXOffset( 0 ),
	fYOffset( 0 )
{
	farrPolyPts		= new TPointsArray;

	fDevHandle		= NULL;
	fpDevDC			= NULL;

	ViewRect	rect( 0, 0, width, height );
	if ( fpDrawPad == NULL || VCOM_FAILED( fpDrawPad->InitializeInMemory( rect ) ) ) {
		// error! release and use empty instance
		fpDrawPad	= TDrawPad();
	}
	else {
		fpDrawPad->SetClipRect( rect );
	}
}

VWCustomCtrlDC::VWCustomCtrlDC(const ViewRect& inViewRect) :
	fpDrawPad( VectorWorks::IID_DrawPad ),
	fXOffset( 0 ),
	fYOffset( 0 )
{
	farrPolyPts		= new TPointsArray;

	if ( fpDrawPad == NULL || VCOM_FAILED( fpDrawPad->InitializeInMemory( inViewRect ) ) ) {
		// error! release and use empty instance
		fpDrawPad	= TDrawPad();
	}
	else {
		fpDrawPad->SetClipRect( inViewRect );
	}
}

VWCustomCtrlDC::VWCustomCtrlDC(const VWCustomCtrlDC& scr)
{
}

VWCustomCtrlDC::~VWCustomCtrlDC()
{
	if ( farrPolyPts ) {
		delete (TPointsArray*) farrPolyPts;
		farrPolyPts		= NULL;
	}
}

VWCustomCtrlDC& VWCustomCtrlDC::operator=(const VWCustomCtrlDC& scr)
{
	return *this;
}

Uint32 VWCustomCtrlDC::GetOSDevice() const
{
	Uint32	dc	= 0;
	fpDrawPad->GetOSDeviceContext( dc );
	return dc;
}

ViewCoord VWCustomCtrlDC::GetXOffset() const
{
	return fXOffset;
}

ViewCoord VWCustomCtrlDC::GetYOffset() const
{
	return fYOffset;
}

void VWCustomCtrlDC::SelectPen(const VWCustomCtrlPen& pen)
{
	fCurrentPen		= pen;
}

void VWCustomCtrlDC::SelectBrush(const VWCustomCtrlBrush& brush)
{
	fCurrentBrush	= brush;
}

void VWCustomCtrlDC::SelectFont(const VWCustomCtrlFont& font)
{
	ASSERTN( kVStanev, fpDrawPad );
	if ( fpDrawPad ) {
		DPFont	textFont;
		font.GetFontName().CopyInto( textFont.nameStr/*, kMaxFontNameSize*/ );
		textFont.family		= kNoFamily;
		textFont.ptSize		= font.GetFontSize();
		textFont.bold		= font.GetBold();
		textFont.italic		= font.GetItalic();
		textFont.underline	= font.GetUnderlined();
		textFont.outline	= 0;		// Mac only.
		textFont.shadow		= 0;		// Mac only.
		textFont.condense	= 0;		// Mac only, text pasted from other apps.
		textFont.extend		= 0;		// Mac only, text pasted from other apps.
		textFont._pad		= 0;

		fpDrawPad->SetTextFont( textFont );
		fpDrawPad->SetTextAngle( font.GetRotation(), font.GetBaselineMirror() );
	}
}

VWCustomCtrlPen	VWCustomCtrlDC::GetSelectedPen() const
{
	return fCurrentPen;
}

VWCustomCtrlBrush VWCustomCtrlDC::GetSelectedBrush() const
{
	return fCurrentBrush;
}

VWCustomCtrlFont VWCustomCtrlDC::GetSelectedFont() const
{
	VWCustomCtrlFont	currFont;

	ASSERTN( kVStanev, fpDrawPad );
	if ( fpDrawPad ) {
		DPFont		textFont;
		double		dAngle;
		bool		bMirror;

		fpDrawPad->GetTextFont( textFont );
		fpDrawPad->GetTextAngle( dAngle, bMirror );

		currFont.SetFont( textFont.nameStr, textFont.ptSize );
		currFont.SetStyle( textFont.bold, textFont.italic, textFont.underline );
		currFont.SetRotation( dAngle );
		currFont.SetBaselineMirror( bMirror );
	}

	return currFont;
}

void VWCustomCtrlDC::SetClipRect(const ViewRect& rect)
{
	ASSERTN( kVStanev, fpDrawPad );
	if ( fpDrawPad ) {
		ViewRect	theRect	= rect;
		theRect.Offset( fXOffset, fYOffset );
		fpDrawPad->SetClipRect( theRect );
	}
}

void VWCustomCtrlDC::DrawLine(const ViewPt& fromPt, const ViewPt& toPt)
{
	ASSERTN( kVStanev, fpDrawPad );
	if ( fpDrawPad ) {
		fpDrawPad->SetPen( fCurrentPen.GetSize(), fCurrentPen.GetColor(), fCurrentBrush.GetColor(), 2 );
		fpDrawPad->DPMoveTo( fromPt.x + fXOffset, fromPt.y + fYOffset );
		fpDrawPad->DPLineTo( toPt.x + fXOffset, toPt.y + fYOffset );
	}
}

void VWCustomCtrlDC::DrawRect(const ViewRect& rect)
{
	ASSERTN( kVStanev, fpDrawPad );
	if ( fpDrawPad ) {
		ViewRect	theRect	= rect;
		theRect.Offset( fXOffset, fYOffset );
		fpDrawPad->SetPen( fCurrentPen.GetSize(), fCurrentPen.GetColor(), fCurrentBrush.GetColor(), 2 );
		fpDrawPad->FrameRect( theRect );
	}
}

void VWCustomCtrlDC::FillRect(const ViewRect& rect)
{
	ASSERTN( kVStanev, fpDrawPad );
	if ( fpDrawPad ) {
		ViewRect	theRect	= rect;
		theRect.Offset( fXOffset, fYOffset );

		fpDrawPad->SetPen( fCurrentPen.GetSize(), fCurrentBrush.GetColor(), fCurrentBrush.GetColor(), 2 );
		fpDrawPad->FillRect( theRect );
		fpDrawPad->SetPen( fCurrentPen.GetSize(), fCurrentPen.GetColor(), fCurrentBrush.GetColor(), 2 );
	}
}

Uint32 VWCustomCtrlDC::GetStringWidth(const TXString& string)
{
	Uint32		width	= 0;
	ASSERTN( kVStanev, fpDrawPad );
	if ( fpDrawPad ) {
		fpDrawPad->GetTextWidth( string, width );
	}
	return width;
}

void VWCustomCtrlDC::DrawString(const ViewPt& pt, const TXString& string)
{
	ASSERTN( kVStanev, fpDrawPad );
	if ( fpDrawPad ) {
		fpDrawPad->SetPen( fCurrentPen.GetSize(), fCurrentPen.GetColor(), fCurrentBrush.GetColor(), 2 );
		fpDrawPad->DPMoveTo( pt.x + fXOffset, pt.y + fYOffset );
		fpDrawPad->DrawTextString( string );
	}
}

void VWCustomCtrlDC::DrawString(const ViewPt& pt, const TXString& string, Uint8 red, Uint8 green, Uint8 blue)
{
	ASSERTN( kVStanev, fpDrawPad );
	if ( fpDrawPad ) {
		GSColor		color;
		color.Set8( red, green, blue );
		fpDrawPad->SetPen( fCurrentPen.GetSize(), color, fCurrentBrush.GetColor(), 1 );
		fpDrawPad->DPMoveTo( pt.x + fXOffset, pt.y + fYOffset );
		fpDrawPad->DrawTextString( string );
		fpDrawPad->SetPen( fCurrentPen.GetSize(), fCurrentPen.GetColor(), fCurrentBrush.GetColor(), 1 );
	}
}

void VWCustomCtrlDC::BitBlt(const ViewRect& destRect, const VWCustomCtrlDC& srcDC, const ViewPt& srcPt, EDrawPadTransferMode mode)
{
	ASSERTN( kVStanev, fpDrawPad && srcDC.fpDrawPad );
	if ( fpDrawPad && srcDC.fpDrawPad ) {
		GSRect32		gsSrcRect	( srcPt.x, srcPt.y, srcPt.x + destRect.Width(), srcPt.y + destRect.Height() );
		GSRect32		gsDestRect	( destRect.left + fXOffset, destRect.top + fYOffset, destRect.right + fXOffset, destRect.bottom + fYOffset );
		srcDC.fpDrawPad->CopyBitsOut( gsSrcRect, fpDrawPad, gsDestRect, mode );
	}
}

void VWCustomCtrlDC::BitBlt(const ViewRect& destRect, const VWCustomCtrlDC& srcDC, const ViewRect& srcRect, EDrawPadTransferMode mode)
{
	ASSERTN( kVStanev, fpDrawPad && srcDC.fpDrawPad );
	if ( fpDrawPad && srcDC.fpDrawPad ) {
		GSRect32		gsSrcRect	( srcRect.left, srcRect.top, srcRect.right, srcRect.bottom );
		GSRect32		gsDestRect	( destRect.left + fXOffset, destRect.top + fYOffset, destRect.right + fXOffset, destRect.bottom + fYOffset );
		srcDC.fpDrawPad->CopyBitsOut( gsSrcRect, fpDrawPad, gsDestRect, mode );
	}
}

void VWCustomCtrlDC::PathBegin()
{
	TPointsArray*	pPtsArray	= (TPointsArray*) farrPolyPts;
	if ( pPtsArray ) {
		pPtsArray->clear();
	}
}

void VWCustomCtrlDC::PathMoveTo(Sint16 x, Sint16 y)
{
	TPointsArray*	pPtsArray	= (TPointsArray*) farrPolyPts;
	if ( pPtsArray ) {
		SVisualPoint	pt;
		pt.bVisible			= false;
		pt.pt.x				= x;
		pt.pt.y				= y;

		pPtsArray->push_back( pt );
	}
}

void VWCustomCtrlDC::PathLineTo(Sint16 x, Sint16 y)
{
	TPointsArray*	pPtsArray	= (TPointsArray*) farrPolyPts;
	if ( pPtsArray ) {
		SVisualPoint	pt;
		pt.bVisible			= true;
		pt.pt.x				= x;
		pt.pt.y				= y;

		pPtsArray->push_back( pt );
	}
}

void VWCustomCtrlDC::PathEndDraw()
{
	TPointsArray*	pPtsArray	= (TPointsArray*) farrPolyPts;
	if ( pPtsArray ) {
		ViewPt	lastPt;
		size_t	ptsCnt	= pPtsArray->size();
		for(size_t i=0; i<ptsCnt; i++) {
			const SVisualPoint& pt	= (*pPtsArray)[ i ];

			if ( i != 0 && pt.bVisible ) {
				this->DrawLine( lastPt, pt.pt );
			}
			
			lastPt		= pt.pt;
		}
	}
}

void VWCustomCtrlDC::PathEndDrawAndFill()
{
	TPointsArray*	pPtsArray	= (TPointsArray*) farrPolyPts;
	if ( pPtsArray && fpDrawPad ) {
		GSPolyRef	polyRef;
		if ( VCOM_SUCCEEDED( fpDrawPad->CreatePoly( polyRef ) ) ) {
			ViewPt	lastPt;
			size_t	ptsCnt	= pPtsArray->size();
			for(size_t i=0; i<ptsCnt; i++) {
				const SVisualPoint& pt	= (*pPtsArray)[ i ];

				ViewPt				thePt;
				thePt.x					= pt.pt.x + fXOffset;
				thePt.y					= pt.pt.y + fYOffset;
				fpDrawPad->AddPolyPt( polyRef, thePt );

				if ( i != 0 && pt.bVisible ) {
					this->DrawLine( lastPt, pt.pt );
				}
				
				lastPt		= pt.pt;
			}

			fpDrawPad->SetPen( fCurrentPen.GetSize(), fCurrentBrush.GetColor(), fCurrentBrush.GetColor(), 2 );
			fpDrawPad->FillPoly( polyRef );
			fpDrawPad->ReleasePoly( polyRef );

			fpDrawPad->SetPen( fCurrentPen.GetSize(), fCurrentPen.GetColor(), fCurrentBrush.GetColor(), 2 );
		}
	}
}

void VWCustomCtrlDC::PathEndFill()
{
	TPointsArray*	pPtsArray	= (TPointsArray*) farrPolyPts;
	if ( pPtsArray && fpDrawPad ) {
		GSPolyRef	polyRef;
		if ( VCOM_SUCCEEDED( fpDrawPad->CreatePoly( polyRef ) ) ) {
			size_t	ptsCnt	= pPtsArray->size();
			for(size_t i=0; i<ptsCnt; i++) {
				const SVisualPoint& pt	= (*pPtsArray)[ i ];

				ViewPt				thePt;
				thePt.x					= pt.pt.x + fXOffset;
				thePt.y					= pt.pt.y + fYOffset;
				fpDrawPad->AddPolyPt( polyRef, thePt );
			}

			fpDrawPad->SetPen( fCurrentPen.GetSize(), fCurrentBrush.GetColor(), fCurrentBrush.GetColor(), 2 );
			fpDrawPad->FillPoly( polyRef );
			fpDrawPad->ReleasePoly( polyRef );

			fpDrawPad->SetPen( fCurrentPen.GetSize(), fCurrentPen.GetColor(), fCurrentBrush.GetColor(), 2 );
		}
	}
}

void VWCustomCtrlDC::PathEndFillAndDraw()
{
	TPointsArray*	pPtsArray	= (TPointsArray*) farrPolyPts;
	if ( pPtsArray && fpDrawPad ) {
		GSPolyRef	polyRef;
		if ( VCOM_SUCCEEDED( fpDrawPad->CreatePoly( polyRef ) ) ) {
			size_t	ptsCnt	= pPtsArray->size();
			for(size_t i=0; i<ptsCnt; i++) {
				const SVisualPoint& pt	= (*pPtsArray)[ i ];

				ViewPt				thePt;
				thePt.x					= pt.pt.x + fXOffset;
				thePt.y					= pt.pt.y + fYOffset;
				fpDrawPad->AddPolyPt( polyRef, thePt );
			}

			fpDrawPad->SetPen( fCurrentPen.GetSize(), fCurrentBrush.GetColor(), fCurrentBrush.GetColor(), 2 );
			fpDrawPad->FillPoly( polyRef );
			fpDrawPad->ReleasePoly( polyRef );

			fpDrawPad->SetPen( fCurrentPen.GetSize(), fCurrentPen.GetColor(), fCurrentBrush.GetColor(), 2 );

			ViewPt	lastPt;
			for(size_t i=0; i<ptsCnt; i++) {
				const SVisualPoint& pt	= (*pPtsArray)[ i ];
				
				if ( i != 0 && pt.bVisible ) {
					this->DrawLine( lastPt, pt.pt );
				}
				
				lastPt		= pt.pt;
			}
		}
	}
}

void VWCustomCtrlDC::DrawSymbolPreview(	InternalIndex resourceRefNum,
										const ViewRect& destRect,
										ECustomDCPreviewMode viewMode,
										ECustomDCRenderMode renderMode)
{
	gSDK->DrawSymbolPreview( fpDrawPad, resourceRefNum, destRect, (short) viewMode, (short) renderMode );
}






