//====================================================================================================
//
// CustomObjects.cpp
//
// Copyright © Nemetschek North America 1997-2002.
// All Rights Reserved.
//
// Utility functions for SDK Plug-in Objects.
//
// Created 8/25/97 by Jeff Koppi
// Modified 9/28/99 JAK
// Modified 8/22/02 JAK - Look for new resource type available in VW 10.0.0.
//====================================================================================================

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

#include "CustomObjects.h"

#include <GSESetup.h>
#include <GSString.h>
#include <MCCoordTypes.h>


//====================================================================================================
//	STRUCTS
//
//====================================================================================================


// Plug-in Object Definition Resource
// This resource is used to define the name of an SDK Plug-in Object. 
// It contains two names: a universal name and a localizable name. 
// The universal name is set by the developer of the plug-in, and should never be changed. 
// The localizable name can be changed by distributors who are localizing the product for 
// a different language.  It can be translated.  
// VectorWorks will always display the localizable name in the user interface.
// (If the localizable name is empty then the universal name is displayed.)
// This resource was added for VectorWorks 10.0.0.  
//
// New for VW 10.0.0.
#define OST_PDEf						'PDEf'	
const short kPluginObjDefResID			= 128;
//--------------------------------------------------------------------
#pragma pack(push, 2) // BEGIN 2 BYTE STRUCTURE ALIGNMENT (RESOURCES)

struct PluginObjDef {
	PStr63 universalName;	// universal name should NOT be changed when translating plug-ins.
	PStr63 displayName; 	// localizable name should be translated to appropriate language.
	short version;
};
#pragma pack(pop) // END 2 BYTE STRUCTURE ALIGNMENT (RESOURCES)
//--------------------------------------------------------------------

typedef struct PluginObjDef *PluginObjDefPtr, **PluginObjDefHand;


// Old Plug-in Object Definition Resource
// This is the original resource that defines Plug-in Objects. 
// It only contains one name, which was localized during the tranlation process. 
// This resource is still supported for compatiblity, but plug-ins should use the new resource instead.
//
#define OST_PDef        'PDef'
const short kPDefResID		= 128;

//--------------------------------------------------------------------
#pragma pack(push, 2) // BEGIN 2 BYTE STRUCTURE ALIGNMENT (RESOURCES)
struct PDefSpec {
	PStr20	name;	// 22 bytes
	short 	version;
};
#pragma pack(pop) // END 2 BYTE STRUCTURE ALIGNMENT (RESOURCES)
//--------------------------------------------------------------------

typedef struct PDefSpec *PDefSpecPtr, **PDefSpecHandle;


//====================================================================================================
//	FUNCTIONS
//
//	Utility Functions for Plug-ins.
//
//====================================================================================================


//----------------------------------------------------------------------------
static Boolean GetCustomObjectDefResource(PluginObjDefHand& objNames)
//
//	Looks for a Plug-in Object definition resource within this plug-in, allocates a structure to hold the data,
//	and returns a handle to the structure.  This will first look for the latest resource type 'PDEf' which is 
// 	new for VW 10.0.0 and if not found it will look for the older version 'Pdef' resource.  
//	Returns true if one of these is found.
//
{
	Boolean result = false;
	
	// Attempt to read new version of Plug-in Object Definition resource first.
	PluginObjDefHand defHand = NULL;
	defHand = PluginObjDefHand(GS_GetResource(gCBP, OST_PDEf, kPluginObjDefResID));		
	if (defHand == NULL) {
		// Did not find the new resource type, so look for the old one.
		PDefSpecHandle pDefHandle = NULL;
		pDefHandle = PDefSpecHandle(GS_GetResource(gCBP, OST_PDef, kPDefResID));	// old resource
		if (pDefHandle != NULL) {
			// Found the old one, so copy its string into new structure and dispose of old structure.
			defHand = (PluginObjDefHand)GS_NewHandle(gCBP, sizeof(PluginObjDef));
			StringCopy((*pDefHandle)->name, (*defHand)->universalName, sizeof(Str63));
			StringCopy((*pDefHandle)->name, (*defHand)->displayName, sizeof(Str63));;
			(*defHand)->version = (*pDefHandle)->version;
			GS_ReleaseResource(gCBP, Handle(pDefHandle));	// callback works cross-platform
			result = true;
		}
	}
	else
		result = true;
		
	objNames = defHand;
	return result;
}


//----------------------------------------------------------------------------
Boolean GetCustomObjectName(Str20 parmName, short &version)
//
//	*** This is an obsolete function that is here for compatibility.  ***
//
//	Read name from resources of this file.
//	Assumes the resource file is open and active.
// 	
//	If the plug-in has the new resource (VW 10.0.0) then this old routine will return the "Universal Name" of the object. 
//	If the plug-in only has the old resource, then this function will return the only name in that resource.
//
{
	Boolean result = false;
	
	PluginObjDefHand objDef = NULL;
	if (GetCustomObjectDefResource(objDef) && (objDef != NULL)) {
		StringCopy((*objDef)->universalName, parmName, sizeof(Str20));
		version = (*objDef)->version;	
		GS_ReleaseResource(gCBP, Handle(objDef));
		result = true;
	}	
		
	return result;
}


//----------------------------------------------------------------------------
Boolean GetCustomObjectName(Str63 universalName, Str63 displayName, short &version)
//
//	New function to return contents of new Plug-in Definition Resource including
//	universal name, display name (localized), and version.  
//
{
	Boolean result = false;
	
	PluginObjDefHand objDef = NULL;
	if (GetCustomObjectDefResource(objDef) && (objDef != NULL)) {
		StringCopy((*objDef)->universalName, universalName, sizeof(Str63));
		StringCopy((*objDef)->displayName, displayName, sizeof(Str63));
		version = (*objDef)->version;
		GS_ReleaseResource(gCBP, Handle(objDef));
		result = true;
	}

	return result;
}



//----------------------------------------------------------------------------
Boolean GetCustomObjectDefinition(CallBackPtr cbp, MCObjectHandle parmHand, RecordHandle& recordHand, FormatHandle& formatHand)
//
//	Should only be called from Regeneration code, not from Tool code.
//	Given handle to object instance, retrieve its record node and format node.
//	Returns true if successful.
//
{
	Boolean found = false;

	// Loop to find record among all record nodes on aux list.
	RecordHandle record = (RecordHandle) GS_FindAuxObject( cbp, MCObjectHandle(parmHand), recordNode);
	FormatHandle format = NULL;
	while( record && !found){
		format = (FormatHandle) GS_GetDefinition(cbp, (MCObjectHandle) record);
		if (format) {
			TFormatHandler currFormatHandler(format);
			if (currFormatHandler.IsParametric()) {
				// If we find a recordNode on the aux list of the kParametricNode, and its formatNode has the parametric bit set,
				// then we can assume it is "the one".  No name checking is necessary.  JAK 9/27/99 Fix for VW 8.5.0.
				found = true;
			}
		}

		if (found == false)
			record = GS_NextAuxObject(cbp, GS_NextObject(cbp, record), recordNode);	// loop increment			
	}
	
	if (found) {
		recordHand = MCObjectHandle(record);
		formatHand = MCObjectHandle(format);
		return true;
	}
	else {
		DSTOP((kJeff, "Regenerate function failed to find a record or format for this parametric.\n"));
		return false;
	}
}


//----------------------------------------------------------------------------
Boolean GetParameterChoice(short parameterIndex, short choiceIndex, Str255 univChoiceStr, Str255 localChoiceStr)
//
//	This function will return the universal name and localized name for a popup or radio button choice.
//	This function returns one choice.  If you need all choices, it may be more efficient to write your own routine
// 	rather than calling this one in a loop.  
//
//	The "parameterIndex" argument is a 1-based index.
//	The "choiceIndex" argument is a 1-based index.
//
{
	Boolean status = false;
	
	// Read the parameter resource ('Prm#').
	UnivParmTabHandle parameterResHand = (UnivParmTabHandle)GS_GetResource(gCBP, OST_Prm, kUnivParmResID);
	if (parameterResHand) {
		if ((parameterIndex > 0) && (parameterIndex <= (*parameterResHand)->numParms)) {
			short choiceID = (*parameterResHand)->parms[parameterIndex-1].fChoices;
			if (choiceID > 0) {		
				// Read the choices resource ('Chc#').
				ParmChoiceTabHandle choiceTable = (ParmChoiceTabHandle)GS_GetResource(gCBP, OST_Chc, choiceID);
				if (choiceTable && (choiceIndex > 0) && (choiceIndex <= (*choiceTable)->numChoices)) {
					StringCopy((*choiceTable)->choices[choiceIndex-1].fUniversalChoiceName, univChoiceStr, sizeof(Str255));
					StringCopy((*choiceTable)->choices[choiceIndex-1].fLocalizedChoiceName, localChoiceStr, sizeof(Str255));
					status = true;
				}
				GS_ReleaseResource(gCBP, (Handle)choiceTable);
			}
		}
		GS_ReleaseResource(gCBP, (Handle)parameterResHand);
	}
	else {
		// Current parameter resource not found.  Look for old resource type ('PARM').
		// ***
	}	

	return status;
}


//----------------------------------------------------------------------------
Boolean GetNumParameterChoices(short parameterIndex, short &numChoices)
//
//	This function returns the number of choices for a particular popup or radio button parameter.
//	The "parameterIndex" argument is a 1-based index.
//
{
	Boolean status = false;
	
	// Read the parameter resource ('Prm#').
	UnivParmTabHandle parameterResHand = (UnivParmTabHandle)GS_GetResource(gCBP, OST_Prm, kUnivParmResID);
	if (parameterResHand) {
		if ((parameterIndex > 0) && (parameterIndex <= (*parameterResHand)->numParms)) {
			short choiceID = (*parameterResHand)->parms[parameterIndex-1].fChoices;
			if (choiceID > 0) {		
				// Read the choices resource ('Chc#').
				ParmChoiceTabHandle choiceTable = (ParmChoiceTabHandle)GS_GetResource(gCBP, OST_Chc, choiceID);
				if (choiceTable) {
					numChoices = (*choiceTable)->numChoices;
					status = true;
				}
				GS_ReleaseResource(gCBP, (Handle)choiceTable);
			}
		}
		GS_ReleaseResource(gCBP, (Handle)parameterResHand);
	}
	else {
		// Current parameter resource not found.  Look for old resource type ('PARM').
		// ***
	}
	
	return status;
}


//----------------------------------------------------------------------------
Boolean GetLocalParameterName(short parameterIndex, Str255 localParameterName)
//
//	Read the new parameter resource 'Prm#' and return one localized parameter name.
//	Only to be called from a plug-in object. 
//
//	The "parameterIndex" argument is a 1-based index.
//
{
	Boolean status = false;
	
	// Read the parameter resource ('Prm#').
	UnivParmTabHandle parameterResHand = (UnivParmTabHandle)GS_GetResource(gCBP, OST_Prm, kUnivParmResID);
	if (parameterResHand) {
		if ((parameterIndex > 0) && (parameterIndex <= (*parameterResHand)->numParms)) {
			StringCopy((*parameterResHand)->parms[parameterIndex-1].fLocalizedName, localParameterName, sizeof(Str255));
			status = true;
		}
		GS_ReleaseResource(gCBP, (Handle)parameterResHand);
	}
	else {
		// Current parameter resource not found.  Look for old resource type ('PARM').
		// ***
	}

	return status;
}




