//
//	ObjectInsertionToolApp.cpp
//
//	Main entry point for VectorWorks Plug-in Object code.
//
//	Copyright © Nemetschek North America, Inc  2008.
//	All Rights Reserved.
//
//

#include "StdAfx.h"



#include "ObjectInsertionToolApp.h"

// ----------------------------------------------------------------------------------------------------
CPersistentData::CPersistentData()
{
	fToolData				= 0;
	fCount					= 0;
	fdCurrentPreviewHeight	= 0;
	for(size_t i=0; i<10; i++) {
		fBarState[i]	= 0;
	}
}

CPersistentData::~CPersistentData()
{
}

long& CPersistentData::GetToolData()
{
	return fToolData;
}

short CPersistentData::GetBarState(size_t groupID) const
{
	return fBarState[ groupID ];
}

void CPersistentData::SetBarState(size_t groupID, short state)
{
	fBarState[ groupID ]	= state;
}

SDefaultToolInfo CPersistentData::SetupBar(bool bInitOnly)
{
	SDefaultToolInfo	defToolSettings;
#if 0
	if ( this->GetBarState( 1 ) == 0 )	this->SetBarState( 1, 1 );
	if ( this->GetBarState( 2 ) == 0 )	this->SetBarState( 2, 1 );
	if ( this->GetBarState( 3 ) == 0 )	this->SetBarState( 3, 4 );

	if ( ! bInitOnly ) {
		// if not initializing then build the mode bar
		gSDK->AddRadioMode( this->GetBarState( 1 ), 2, 11001, 11002 );
		gSDK->AddRadioMode( this->GetBarState( 2 ), 5, 2489, 2490, 11003, 11004, 11005, 0 );
		gSDK->AddRadioMode( this->GetBarState( 3 ), 4, 2500, 2501, 2502, 2503, 0, 0 );
		gSDK->AddButtonMode( 11006 );
		gSDK->AddButtonMode( 11007 );
	}

	defToolSettings.fModeGroup				= 2;	// mode change group ID
	defToolSettings.fAlignmentGroup			= 3;	// alignment change group ID
	defToolSettings.fRegularInsChoiceIndex	= 1;	// fModeGroup indices
	defToolSettings.fOffsetInsChoiceIndex	= 2;		//
	defToolSettings.fLeftChoiceIndex		= 1;	// fAlignmentGroup indices
	defToolSettings.fCenterChoiceIndex		= 2;		//
	defToolSettings.fRightChoiceIndex		= 3;		//
	defToolSettings.fNaturalChoiceIndex		= 4;		//
#else
	if ( this->GetBarState( 1 ) == 0 )	this->SetBarState( 1, 1 );
	if ( this->GetBarState( 2 ) == 0 )	this->SetBarState( 2, 1 );

	if ( ! bInitOnly ) {
		// if not initializing then build the mode bar
		gSDK->AddRadioMode( this->GetBarState( 1 ), 2, 11001, 11002 );
		gSDK->AddRadioMode( this->GetBarState( 2 ), 5, 2489, 2490, 11003, 11004, 11005, 0 );
		gSDK->AddButtonMode( 11006 );
		gSDK->AddButtonMode( 11007 );
	}

	defToolSettings.fModeGroup				= 2;	// mode change group ID
	defToolSettings.fRegularInsChoiceIndex	= 1;	// fModeGroup indices
	defToolSettings.fOffsetInsChoiceIndex	= 2;		//
#endif

	return defToolSettings;
}

bool CPersistentData::IsOffsetMode() const
{
	return this->GetBarState( 2 ) == 2;
}

TXString CPersistentData::GetObjectName() const
{
	return "#Simple Test";
}

void CPersistentData::SetDefaultPreviewHeight()
{
	fdCurrentPreviewHeight	= 100;
}

double CPersistentData::GetCurrentPreviewHeight() const
{
	return fdCurrentPreviewHeight;
}

void CPersistentData::UpdateTempPreview(double dHeight)
{
	gSDK->SupportUndoAndRemove();

	gSDK->SetUndoMethod( kUndoSwapObjects );
	InternalName	objName;
	this->GetObjectName().CopyInto( objName );

	// default default format
	MCObjectHandle	hDefFormat	= gSDK->DefineCustomObject( objName, kCustomObjectPrefNever );
	if ( hDefFormat ) {
		// set-up default properties
		TFormatHandler	defFormat( hDefFormat );
		short		itemIndex	= defFormat.GetFieldIndex( TXString("height") );
		TRecordItem valueItem( defFormat.GetFieldStyle( itemIndex ) );
		if ( defFormat.GetFieldDefault( itemIndex, valueItem ) ) {
			if ( valueItem.SetFieldValue( dHeight ) ) {
				defFormat.SetFieldDefault( itemIndex, valueItem );
			}
		}

		fdCurrentPreviewHeight		= dHeight;
	}

	// add a demo record outside undo so it will be preserved
	Str63	demoRecName;
	TXString("demo_record").CopyInto( demoRecName );
	MCObjectHandle	hFormat	= gSDK->GetNamedObject( demoRecName );
	if ( hFormat == NULL ) {
		TFormatHandler	fh( demoRecName );
		gSDK->AddAfterSwapObject( gSDK->GetNamedObject( demoRecName ) );
	
		Str20			fieldName;
		TXString("test").CopyInto( fieldName );
		TRecordItem		defaultValue( kFieldBoolean );
		defaultValue.SetFieldValue( (Boolean) false );
		fh.AddField( fieldName, defaultValue, false );

		hFormat		= gSDK->GetNamedObject( demoRecName );
	}

	// create custom object for preview
	MCObjectHandle	hObj			= gSDK->CreateCustomObject( objName, WorldPt(0,0), 0, false );

	MCObjectHandle	hDefaultRecord	= ::GS_FindAuxObject( gCBP, hFormat, kRecordNode );
	if ( hDefaultRecord ) {
		for(long i=0; i<fCount; i++) {
			MCObjectHandle	hRecord			= ::GS_DuplicateObject( gCBP, hDefaultRecord );
			::GS_AttachAuxObject( gCBP, hRecord, hObj );
		}
	}

	gSDK->ResetObject( hObj );

	gSDK->CallDefaultTool( kDefaultTool_UpdatePreviewObject, (long) hObj, 0, this->GetToolData() );

	gSDK->UndoAndRemove();;
}

void CPersistentData::OnBarEvent(short groupID, short buttonID, short oldButtonID)
{
	if ( groupID == 3 ) {
		fCount	++;
		this->UpdateTempPreview( fdCurrentPreviewHeight );
	}
	else if ( groupID == 4 ) {
		if ( fCount > 0 ) {
			fCount	--;
		}
		this->UpdateTempPreview( fdCurrentPreviewHeight );
	}
}

// ----------------------------------------------------------------------------------------------------
long ToolMain(long action, long message1, long message2, long &userData)
{
	GSExternalSetup(gCBP);

	long returnVal = 0L;


	CPersistentData*	pInfo	= (CPersistentData*) userData;

	switch (action) {

		case kToolInitGlobals : {
			void* pRawMem	= gSDK->NewPtr( sizeof(CPersistentData) );
			pInfo			= new ( pRawMem ) CPersistentData();
			if ( pInfo ) {
				InternalName	objName;
				pInfo->GetObjectName().CopyInto( objName );

				SDefaultToolInfo settings	= pInfo->SetupBar( true );

				gSDK->CallDefaultTool( kToolInitGlobals, (long) & objName, (long) & settings, pInfo->GetToolData() );
			}

			break;
		}
		case kToolDisposeGlobals : {
			if ( pInfo ) {
				gSDK->CallDefaultTool( kToolDisposeGlobals, 0, 0, pInfo->GetToolData() );

				pInfo->~CPersistentData();
				gSDK->DisposePtr( pInfo );
			}

			break;
		}
		case kToolDoSetup : {
			SDefaultToolInfo settings	= pInfo->SetupBar( false );

			gSDK->CallDefaultTool( kToolDoSetup, message1, (long) & settings, pInfo->GetToolData() );
			if ( message1 == 0 ) {
				pInfo->SetDefaultPreviewHeight();
				pInfo->UpdateTempPreview( pInfo->GetCurrentPreviewHeight() );
			}

			break;
		}
		case kToolDoSetDown : {
			gSDK->CallDefaultTool( kToolDoSetDown, message1, message2, pInfo->GetToolData() );
			break;
		}
		case kToolDoModeEvent : {
			short		groupID		= DemoteTo<short>( kVStanev, (message1 > 0 ? message1 : 0) );
			short		buttonID	= DemoteTo<short>( kVStanev, ((message2 > 0 ? message2 : 0) & 0x0000FFFF) );
			short		oldButtonID	= DemoteTo<short>( kVStanev, (((message2 > 0 ? (size_t)(message2) : 0) & 0xFFFF0000) >> 24) );

			pInfo->SetBarState( groupID, buttonID );

			returnVal	= gSDK->CallDefaultTool( kToolDoModeEvent, message1, message2, pInfo->GetToolData() );

			pInfo->OnBarEvent( groupID, buttonID, oldButtonID );
			break;
		}
		case kToolDraw: {
			size_t	ptsCnt		= gSDK->GetNumToolPts();
			bool	bOffsetMode	= pInfo->IsOffsetMode();
			if ( (bOffsetMode && ptsCnt < 2) || (! bOffsetMode && ptsCnt < 1) ) {
				// dont recognize wall when determining the orientation
				double	dWallWidth	= 0;
				WorldPt pt;
				if ( gSDK->GetToolPtCurrent2D( pt ) ) {
					double	dCurrHeight	= pInfo->GetCurrentPreviewHeight();

					MCObjectHandle	hPickObject		= gSDK->ObjectNearCoordPt( pt );
					short			pickObjType		= gSDK->GetObjectType( hPickObject );
					if ( pickObjType == kWallNode || pickObjType == kRoundWallNode ) {
						gSDK->WrapGetWallWidth( hPickObject, dWallWidth );
						if ( Abs(dWallWidth - dCurrHeight) > 0.001 ) {
							pInfo->UpdateTempPreview( dWallWidth );
						}
					}
					else {
						pInfo->SetDefaultPreviewHeight();
						double	defHeight	= pInfo->GetCurrentPreviewHeight();
						if ( Abs(defHeight - dCurrHeight) > 0.001 ) {
							pInfo->UpdateTempPreview( defHeight );
						}
					}
				}
			}

			returnVal	= gSDK->CallDefaultTool( kToolDraw, message1, message2, pInfo->GetToolData() );
			break;
		}
		case kToolHandleComplete: {
			MCObjectHandle	hResult	= NULL;
			returnVal	= gSDK->CallDefaultTool( kToolHandleComplete, 0, (long) & hResult, pInfo->GetToolData() );
			
			TXString str;
			str.Format( "kToolHandleComplete: hResult=0x%X", hResult );
			gSDK->AlertInform( str );
			break;
		}
		default:
			returnVal	= gSDK->CallDefaultTool( action, message1, message2, pInfo->GetToolData() );
			break;

	}

	userData	= (long) pInfo;

	GSExternalSetdown (0L);

	return returnVal;
}
