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

#include "StdAfx.h"

#include "ObjectWithWidgetsData.h"
#include "ObjectWithWidgetsApp.h"
#include "ChoicesDlg.h"

#define		kTextWidgetID			100
#define		kStateCheckWidgetID		101
#define		kValuesPopupWidgetID	102
#define		kButtonWidgetID			103
#define		kNormalPopupWidgetID	104

static bool EditChoicesList(CObjectWithWidgetsObjectData& objData, const TXString& oldValue)
{
	SObjectWithWidgetsData&		data			= objData.GetData();
	
	const TVWMemoryStringArray&	arrPopupList	= data.GetPopupList();

	bool	handled	= false;
	int		index	= oldValue.atoi();

	// edit the list, handling 'cancel' properly
	CChoicesDlg	dlg( arrPopupList, index > 0 ? size_t(index-1) : size_t(-1) );
	if ( dlg.RunDialogLayout() == kDialogButton_Ok ) {
		// OK button, change the data
		TVWMemoryStringArray&	arrPopupListEdit	= data.GetPopupListForEdit();
		
		dlg.GetCoices( arrPopupListEdit );
		size_t			listSel	= dlg.GetSelection();

		TXString		strSel;
		strSel.Format( "%d", (listSel!=size_t(-1) ? (listSel+1) : 1) );
		objData.SetPopupText( strSel );

		handled		= true;
	}

	return handled;
}

long ParametricMain(long action, MCObjectHandle hParametricObj, long message, long &userData)
//
//	Main entry point for parametric object regeneration external code resource.
//	See MiniCadHookIntf.h for constants.
//
{
    // initialize VCOM mechanizm
    ::GS_InitializeVCOM( gCBP );

	long	reply = kParametricNoErr;

	CObjectWithWidgetsObjectData	objData( userData );

	switch (action) {
		case kParametricInitGlobals : {
				/*
					This action is called when an overlay is activated and serves the
					primary purpose of allowing the external function to define any
					defaults and global information and to initialize data space that
					may be stored in userData.
				*/
				objData.InitUserdata( true );
				break;
			}



		case kParametricDisposeGlobals : {
				/*
					This action is called when an overlay is deactivated and serves the
					primary purpose of allowing the external function to dispose data
					space that may be stored in userData.
				*/
				objData.InitUserdata( false );
				break;
			}

		case kObjOnInitXProperties: {
				CodeRefID objectID	= (CodeRefID) message;

				// obtain the interfact for accessing the extended properties
				using namespace VectorWorks::PluginSupport;
				VCOMPtr<IExtendedProps>	pExtProps( IID_ExtendedProps );

				// enable custom UI for that plug-in parametric type
				// all instances of that parametric will have the custom UI defined here
				pExtProps->SetObjectProperty( objectID, kObjXPropHasUIOverride, true );

				// define custom UI for that parametric type
				IWidgetsEditProvider*	pWidgetsProvider	= NULL;
				if ( VCOM_SUCCEEDED( pExtProps->GetObjComponentTypeWidgets( objectID, kObjectRootComponentTypeID, pWidgetsProvider ) ) ) {
					pWidgetsProvider->AddWidget( kTextWidgetID, "p1", "My Value" );
					pWidgetsProvider->AddWidget( kStateCheckWidgetID, "p2" );
					pWidgetsProvider->AddWidget( kValuesPopupWidgetID, "p3" );
					pWidgetsProvider->AddWidget( kButtonWidgetID, kWidgetButton, "Edit List..." );
					pWidgetsProvider->AddWidget( kNormalPopupWidgetID, "p4" );
				}

				// enable notification for updating widget visibility and enable state
				pExtProps->SetObjectProperty( objectID, kObjXHasCustomWidgetVisibilities, true );

				// prepare flags for the state event that is to be received
				short		stateEventFlags	= kParametricStateEvent_ResetStatesEvent;
				::GS_SetProgramVariable( gCBP, varParametricEnableStateEventing, & stateEventFlags );
				pExtProps->SetObjectProperty( objectID, kObjXPropAcceptStates, true );

				break;
			}

		case kObjOnWidgetPrep: {
				OnObjectWidgetPrepCall* pThisCall		= (OnObjectWidgetPrepCall*) message;
				IWidgetsProvider*		pWidgetProvider	= pThisCall ? (IWidgetsProvider*) pThisCall->fpWidgetProvider : NULL;
				if ( pWidgetProvider && objData.SetObject( hParametricObj ) ) {
					SWidgetDefinition*	pTextWidget		= pWidgetProvider->GetWidgetByID( kTextWidgetID );
					SWidgetDefinition*	pPopupWidget	= pWidgetProvider->GetWidgetByID( kValuesPopupWidgetID );
					SWidgetDefinition*	pButtonWidget	= pWidgetProvider->GetWidgetByID( kButtonWidgetID );
					if ( pTextWidget && pPopupWidget && pButtonWidget ) {
						pTextWidget->fWidgedVisible		= objData.GetUseCustomText();
						pPopupWidget->fWidgetEnabled	= objData.GetUseCustomText();
						pButtonWidget->fWidgetEnabled	= objData.GetUseCustomText();

						SObjectWithWidgetsData&	data	= objData.GetData();

						IWidgetDataPopup*	pPopupData	= dynamic_cast<IWidgetDataPopup*>( pPopupWidget->fpWidgetData );
						if ( pPopupData && (pPopupData->GetCount() == 0 || data.IsPopupListDirty() ) ) {
							pPopupData->Clear();

							TVWMemoryStringArray&	arrPopupList	= data.GetPopupListForEdit();
							size_t					popupListCnt	= arrPopupList.size();
							for(size_t i=0; i<popupListCnt; i++) {
								const TXString&	value	= arrPopupList[ i ];
								TXString		id;
								id.Format( "%d", (i+1) );
								pPopupData->Add( id, value );
							}

							pPopupData->Add( "div", "-" );
							pPopupData->Add( "edit", TXString( (short)11000, (short)2 ) );

							data.ClearPopupListDirty();
						}
					}
				}

				// important to return that this event is handled
				// so VW will respect the changes made in this event
				reply	= kObjectEventHandled;

				break;
			}

		case kObjOnObjectUIButtonHit: {
				if ( message == kButtonWidgetID && objData.SetObject( hParametricObj ) ) {
					if ( ::EditChoicesList( objData, objData.GetPopupText() ) ) {
						// reset the parametric to reflect changes
						::GS_ResetObject( gCBP, hParametricObj );
					}
				}

				break;
			}

		case kObjOnAddState: {
				// obtain the interfact for accessing the extended properties
				using namespace VectorWorks::PluginSupport;
				VCOMPtr<IExtendedProps>	pExtProps( IID_ExtendedProps );

				ObjectState*	pObjState	= (ObjectState*) message;
				if ( pObjState && objData.SetObject( hParametricObj ) ) {
					ObjectState::EStateType		objState	= (ObjectState::EStateType) pObjState->fSpecifier;
					if ( objState == ObjectState::kParameterChangedReset ) {
						const ObjectStateData_ParamChanged*	pParamChangedData	= (const ObjectStateData_ParamChanged*) pObjState->fData;

						if ( pParamChangedData->fWidgetID == kValuesPopupWidgetID ) {
							TXString	choiceSel	= objData.GetPopupText();
							if ( choiceSel == "div" || choiceSel == "edit" ) {
								Str255		oldValue;
								if ( pParamChangedData->fParameterValidOldValue &&
									 pParamChangedData->fParameterOldValue.GetStr255( oldValue ) )
								{
									if ( ! ::EditChoicesList( objData, oldValue ) ) {
										// if not handled restore prev
										objData.SetPopupText( oldValue );
									}
								}
							}
						}
					}
				}

				break;
			}

		case kParametricRecalculate : {
			//
			//	This action is called to regenerate the look of a parametric object in response to a change
			//	in one of the parameter values on the object info palette, or a rotate, move, attribute change.
			//
			//	I would like to use a super class TParmRegen in this file and then have it overridden in specific
			//	files, but the userData scheme will not allow virtual functions. JAK
			//
			//	The message argument contains a handle to a wall, if we are inserted in a wall directly. Only for this action.
			//

			// 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);
			
			objData.SetObject( hParametricObj );

			::GS_CreateTextBlock( gCBP, TXString("Object with widgets:"), WorldPt(0, 0), false, 0);
			::GS_CreateTextBlock (gCBP, TXString("Normal popup value=") + objData.GetNormalPopupText(), WorldPt(5, -10), false, 0 );
			if ( objData.GetUseCustomText() ) {
				::GS_CreateTextBlock( gCBP, TXString("Test=") + objData.GetText(), WorldPt(5, -20), false, 0);
				::GS_CreateTextBlock( gCBP, TXString("Popup value=") + objData.GetPopupText(), WorldPt(5, -30), false, 0);
			}
			else {
				::GS_CreateTextBlock (gCBP, TXString("No text!"), WorldPt(5, -20), false, 0 );
			}

			break;
		}

		case kParametricPreference : {
			//	This action gives the parametric an opportunity to pose a custom dialog for parameter value editting.
			//	If this parametric handles the request and poses its own dialog, then it returns kParametricNoErr regardless of
			//	whether chose ok or cancel.  If this parametric does not have a custom dialog, it returns kParametricNotImplemented.
			// 	Most parametrics will simply set reply to kParametricNotImplemented and let MiniCAD pose the standard dialog.

			reply = kParametricNotImplemented;


			break;
		}
	}

	userData	= objData.GetUserData();
	return reply;
}
