//
//
//	SampleObject.cpp
//	
//	
//	Copyright © 2000 Nemetschek North America 
//	All Rights Reserved.
//
//

#if _WINDOWS
#include <Windows.h>
#include "GSWinSDK.h"	// Graphsoft Required.
#else
#include "StdHeaders.h"
#endif

#include <MiniCadCallBacks.h>
#include <MiniCadExternals.h>
#include "CustomObjects.h"

#include <GSString.h>
#include <RecordHandler.h>



//===========================================
#include <MiniCadHookIntf.h>
#include <MCCoordTypes.h>
#include <MCVector.h>
#include <MCMatrix.h>



//-------------------------------------------
//	Forward declarations:
static Boolean GetMyParameterValues(MCObjectHandle, Str255&, size_t&, Boolean&, char*&, size_t&);
//-------------------------------------------


#define USE_TAGGED_DATA_API_DIRECTLY 0
OSType kDataContainerID = 'MY_C'; // uppercase and registered with NNA as with UserDataNodes.



static bool SetColor(MCObjectHandle owner, int dataTag, ColorRef inColor)
//
//	This function stores a single ColorRef which is mapped to the caller specified Tag.  The caller specifies the Tag 
//	so that a call to GetColor below can retrieve it.  The application can change the ColorRef when this object moves to another document
//	and the Tag will remain the same. 
//
{
	
	bool success = false;
	
	#if !USE_TAGGED_DATA_API_DIRECTLY
	
	success = GS_SetCustomObjectColor(gCBP, owner, dataTag, inColor);
	
	#else
	
	//	Here is code to store the data in an object using a different data Container
	//	GS_SetCustomObjectColor stores it inside a dedicated CustomObject TaggedData Container.
	//	This code is left as an example using Tagged Data APIs
	if (! GS_TaggedDataSet(gCBP, owner,kDataContainerID, kTaggedDataColorRefArrayTypeID, dataTag, 0, &inColor)) {
		if (GS_TaggedDataCreate(gCBP, owner, kDataContainerID, kTaggedDataColorRefArrayTypeID, dataTag, 0)) {
			
			success = GS_TaggedDataSet(gCBP, owner, kDataContainerID, kTaggedDataColorRefArrayTypeID, dataTag, 0, &inColor);
		}
	}
	#endif
	
	return success;
}

static bool GetColor(MCObjectHandle owner, int dataTag, ColorRef& outColor)
//
//	Retreives the ColorRef has been previously stored with the TAG == dataTag
{
	#if !USE_TAGGED_DATA_API_DIRECTLY
	return GS_GetCustomObjectColor(gCBP, owner, dataTag, outColor);
	#else
	return GS_TaggedDataGet(gCBP, owner, kDataContainerID, kTaggedDataColorRefArrayTypeID, dataTag, 0, &outColor);
	#endif
}





//-------------------------------------------
long ParametricMain(long action, MCObjectHandle objHand, long /*message*/, long &userData)
//
//	Main entry point for plug-in object.
//	See MiniCadHookIntf.h for constants.
//
{
	long	reply = kParametricNoErr;


	switch (action) {

		case kParametricInitGlobals : {
				//
				//	This action is called when an workspace is activated and serves the 
				//	primary purpose of allowing the plug-in to define any 
				//	defaults and global information and to initialize data space that 
				//	may be stored in userData.
				//

				// Construct explicitly with 'placement new'. Get memory from the app because
				// memory allocated with normal 'new' disappears when the dll unloads.

			/* Example:

				void* pRawMemory = GS_NewPtr(gCBP, sizeof(FooClass));
				if (pRawMemory) {
					FooClass* pConstructedMemory = (FooClass*) new(pRawMemory) FooClass();	
					userData = (long) pConstructedMemory;
				}
				else {
					userData = nil;
				}
	
			*/

				break;
			}

		case kParametricDisposeGlobals : {
				//
				//	This action is called when a workspace is deactivated and serves the 
				//	primary purpose of allowing the external function to dispose data 
				//	space that may be stored in userData.
				//

				// Destruct explicitly when using 'placement new'

			/* Example:

				if (userData) {
					FooClass* pData = (FooClass*) userData;
					pData->~FooClass();
					GS_DisposePtr(gCBP, pData);
					userData = nil;
				}
	
			*/
				
				break;
			}

		case kParametricRecalculate : {
			//
			//	This action is called to regenerate the look of a plug-in object in response to a change 
			//	in one of the parameter values on the object info palette, or a rotate, move, attribute change.
			//
			//	For this action, the message argument contains a handle to a wall, if we are inserted in a wall directly.
			//  
				

			// If this is a "Path" Plug-in Object, then it would get its path and/or profile objects now.
			// MCObjectHandle pathH         = GS_GetCustomObjectPath(gCBP, objHand);
			// MCObjectHandle profileGroupH = GS_GetCustomObjectProfileGroup(gCBP, objHand);
			
			Str255 outText;
			size_t outTextLength;
			Boolean outUseFontStyle;
			char*	text;
			size_t	textSize;
			if (GetMyParameterValues(objHand, outText, outTextLength, outUseFontStyle, text, textSize)) {
			
				////////////////////////////////////////////////////
				//
				//	Example showing the storage of colorRef data attached to this object.  Developers can now store color
				//	as a ColorRef.  These ColorRefs will be maintained by the application  during document transfer and 
				//	during Purge Unused COlors
				//
				ColorRef colorRef = 0;
				
				ObjectColorType colors;
				GS_GetDefaultColors(gCBP,  colors);
				
				const int kMyColorIndexTag = 0;
				if (!GetColor(objHand, kMyColorIndexTag, colorRef)) {
				
					RGBColor rgb;
					rgb.red   = 0;
					rgb.green = kGSMaxUint16;
					rgb.blue  = 0;
					GS_RGBToColorIndex(gCBP, rgb, colorRef);
					(void) SetColor(objHand, kMyColorIndexTag, colorRef);
					colors.fillFore = colorRef;
					colors.fillBack = colorRef;
					GS_SetDefaultColors(gCBP, colors);
				}
				else {
					colors.penFore = colorRef;
					colors.penBack = colorRef;
					GS_SetDefaultColors(gCBP, colors);
				}

				(void) GS_CreateTextBlock(gCBP, outText, WorldPt(0, 0), false, 0);
				
				TVariableBlock varBlock(outUseFontStyle);
				(void) GS_SetObjectVariable(gCBP, objHand, ovPluginHasFontStyle, varBlock);
			}
			break;
		}

		case kParametricPreference : {
			//
			//	This action gives the object an opportunity to pose a custom dialog for parameter value editting.
			//	If this object handles the request and poses its own dialog, then it returns kParametricPrefOK or kParametricPrefCancel.
			//	If this object does not have a custom dialog, it returns kParametricNotImplemented.
			// 	Most parametrics will choose not to implement this optional action, and simply set reply to kParametricNotImplemented 
			//  and let VectorWorks application pose the standard dialog. 
			           
			reply = kParametricNotImplemented;
			break;
		}
	}

	return reply;
}

// 	Index into Parameter list inside the record node is 1-based.
// 	must match Universal 'Prm#' resource or 'PARM' resource 
const short kTextParamIndex = 1;	
const short kUseFontStyleParamIndex = 2;
const short kPopup = 3;

//-------------------------------------------
static Boolean GetMyParameterValues(MCObjectHandle objHand, 
								Str255& outText, 
								size_t& outTextLength,
								Boolean& outUseFontStyle,
								char*& outChoiceStr,
								size_t& outChoiceStrSize)
{
	Boolean retVal = true;

	// read record node on aux list of given object
	RecordHandle parmRecordHand = NULL;
	FormatHandle parmFormatHand = NULL;
	if (	(GetCustomObjectDefinition(gCBP, objHand, parmRecordHand, parmFormatHand) == (Boolean) true)
		&& 	parmRecordHand 
		&& 	parmFormatHand) 
{
		TRecordHandler rh(parmRecordHand);
		TFormatHandler fh(parmFormatHand);	

		// Parameter 1 - 'p1'
		char* textPtr = nil;
		
		TRecordItem textItem(fh.GetFieldStyle(kTextParamIndex));	// must initialize with correct type for this field
		if (rh.GetFieldObject(kTextParamIndex, textItem)) {
			textItem.GetFieldValue(textPtr, outTextLength);
			TXString recordText = textPtr;
			recordText.CopyInto(outText);
		}
		else {
			retVal = false;
			DSTOP((kSteve, "Failed to get a plug-in parameter value for parameter p1."));
		}
		
		// Parameter 2 - 'p2'
		TRecordItem useFontStyleItem(fh.GetFieldStyle(kUseFontStyleParamIndex));
		if (rh.GetFieldObject(kUseFontStyleParamIndex, useFontStyleItem)) {
			useFontStyleItem.GetFieldValue(outUseFontStyle);
		}
		else {
			retVal = false;
			DSTOP((kSteve, "Failed to get a plug-in parameter value for parameter p2."));
		}

		// Parameter 3 - 'p3'
		TRecordItem popup(fh.GetFieldStyle(kPopup));
		char*	text;
		size_t	textSize;

		if (rh.GetFieldObject(kPopup, popup)) {
			popup.GetFieldValue(text, textSize);
			outChoiceStr = text;
			outChoiceStrSize = textSize;
		}
		else {
			retVal = false;
			DSTOP((kSteve, "Failed to get a plug-in parameter value for parameter p3."));
		}
	}
	return retVal;
}
