/*
	Copyright (c) 2024 PTC Inc. and/or Its Subsidiary Companies. All Rights Reserved.
*/

#include <ProToolkit.h>
#include <ProWorkspace.h>
#include <ProWTUtils.h>
#include <ProBrowser.h>
#include <ProUtil.h>
#include <ProMenuBar.h>
#include <ProMode.h>
#include <ProParameter.h>
#include <ProFamtable.h>
#include <ProFaminstance.h>
#include <ProWstring.h>

#include <PTWCServer.h>

#define LOCATION_PARAM_NAME L"PTC_WM_LOCATION"
#define INSTANCE_PARAM_NAME L"PROTK_INSTANCE_PARAM"
#define VERSION_PARAM_NAME L"PTC_WM_VERSION"

/*====================================================================*\
  FUNCTION: PTWCAddInstance
  PURPOSE:  Add a new instance to the current object, save it, and 
			check it in
\*====================================================================*/
int PTWCAddInstance ()
{
	ProMdl model;
	ProBoolean can_modify;
	ProModelitem item;
	wchar_t* server;
	int length;
	ProPath target_folder;
	ProParamvalue value;
	ProParameter param, ver_param;
	ProFamtable f_table;
	ProFamtableItem ft_item;
	ProFaminstance ft_instance;
	ProMdlName inst_name;
	int i, root_length, ver_length;
	ProSolid instance;
	ProServerCheckinConflicts conflicts;
	ProUnititem unit_item;

/*--------------------------------------------------------------------*\
	Check if the current object is modifiable.  If not, by using the UI
	option = PRO_B_TRUE, the user will be presented with an option to
	check out the object to allow the modification. If they deny this
	request, skip the operation.
\*--------------------------------------------------------------------*/
	status = ProMdlCurrentGet (&model);
	PT_TEST_LOG_SUCC ("ProMdlCurrentGet()");

	status = ProMdlToModelitem (model, &item);
	PT_TEST_LOG_SUCC ("ProMdlToModelitem()");

	status = ProParameterInit (&item, LOCATION_PARAM_NAME, &param);
	PT_TEST_LOG_SUCC ("ProParameterInit()");

	ProStringToWstring (target_folder, "");

	if (status == PRO_TK_NO_ERROR)
	{
		status = ProParameterValueWithUnitsGet (&param, &value, &unit_item);
		PT_TEST_LOG_SUCC ("ProParameterValueWithUnitsGet()");

		ProWstringLengthGet (value.value.s_val, &length);

		if (length > 0)
		{
			status = ProServerActiveGet (&server);
			PT_TEST_LOG_SUCC ("ProServerActiveGet()");
	
			PTWCUtilBuildServerFolder (server, value.value.s_val, 
									target_folder);
		}
	}
	
	status = ProMdlIsModifiable (model, PRO_B_TRUE, &can_modify);
	PT_TEST_LOG_SUCC ("ProMdlIsModifiable()");

	if (can_modify)
	{	
/*--------------------------------------------------------------------*\
		Look for a parameter used by this example.  If its not in the
		model, create it.
\*--------------------------------------------------------------------*/
	
		status = ProParameterInit (&item, INSTANCE_PARAM_NAME, &param);
		PT_TEST_LOG_SUCC ("ProParameterInit()");

		if (status != PRO_TK_NO_ERROR)
		{
			value.type = PRO_PARAM_STRING;
			ProStringToWstring (value.value.s_val, "Generic");

			status = ProParameterWithUnitsCreate (&item, INSTANCE_PARAM_NAME, &value, NULL, &param);
			PT_TEST_LOG_SUCC ("ProParameterWithUnitsCreate()");
		}

/*--------------------------------------------------------------------*\
		Add the parameter to the family table.  If the parameter is
		already in the family table, the ProFamtableItemAdd() call
		has no effect.
\*--------------------------------------------------------------------*/
		status = ProFamtableInit (model, &f_table);
		PT_TEST_LOG_SUCC ("ProFamtableInit()");

		status = ProParameterToFamtableItem (&param, &ft_item);
		PT_TEST_LOG_SUCC ("ProParameterToFamtableItem()");
	
		status = ProFamtableItemAdd (&f_table, &ft_item);
		PT_TEST_LOG_SUCC ("ProFamtableItemAdd()");

/*--------------------------------------------------------------------*\
		Use the version of the model to construct a unique new instance
		name for this example.
\*--------------------------------------------------------------------*/
		status = ProParameterInit (&item, VERSION_PARAM_NAME, &ver_param);
		PT_TEST_LOG_SUCC ("ProParameterInit()");

		status = ProParameterValueWithUnitsGet (&ver_param, &value, &unit_item);
		PT_TEST_LOG_SUCC ("ProParameterValueWithUnitsGet()");

		status = ProMdlMdlnameGet (model, inst_name);
		PT_TEST_LOG_SUCC ("ProMdlMdlnameGet()");

		ProWstringLengthGet (inst_name, &root_length);
		ProWstringLengthGet (value.value.s_val, &ver_length);
		
		for (i = 0; i < ver_length; i++)
		{
			if (value.value.s_val[i] == L'.')
				value.value.s_val[i] = L'_';
		}

		if (root_length + ver_length + 1 > PRO_MDLNAME_SIZE - 1)
		{
			ProWstringCopy (value.value.s_val, inst_name, PRO_VALUE_UNUSED);
		}
		else
		{
			ProWstringConcatenate (L"_", inst_name, PRO_VALUE_UNUSED);
			ProWstringConcatenate (value.value.s_val, inst_name, PRO_VALUE_UNUSED);
		}

/*--------------------------------------------------------------------*\
		Add the new instance and set the value of the example parameter
		for this instance.
\*--------------------------------------------------------------------*/
		status = ProFaminstanceInit (inst_name, &f_table, &ft_instance);
		PT_TEST_LOG_SUCC ("ProFaminstanceInit()");

		status = ProFaminstanceAdd (&ft_instance);
		PT_TEST_LOG_SUCC ("ProFaminstanceAdd()");

		ProStringToWstring (value.value.s_val, "Instance ");
		ProWstringConcatenate (inst_name, value.value.s_val, PRO_VALUE_UNUSED);

		status = ProFaminstanceValueSet (&ft_instance, &ft_item, &value);
		PT_TEST_LOG_SUCC ("ProFaminstanceValueSet()");

/*--------------------------------------------------------------------*\
		Instantiate the instance.  This also serves to verify the
		instance, allowing it to be checked in.
\*--------------------------------------------------------------------*/
		status = ProFaminstanceRetrieve (&ft_instance, (ProMdl*)&instance);
		PT_TEST_LOG_SUCC ("ProFaminstanceRetrieve()");

		status = ProMdlErase (instance);
		PT_TEST_LOG_SUCC ("ProMdlErase()");

/*--------------------------------------------------------------------*\
		Save and checkin the changed model.
\*--------------------------------------------------------------------*/
		status = ProMdlSave (model);
		PT_TEST_LOG_SUCC ("ProMdlSave()");

		status = ProServerObjectsCheckin (model, NULL, &conflicts);
		PT_TEST_LOG_SUCC ("ProServerObjectsCheckin()");

		if (status == PRO_TK_CHECKOUT_CONFLICT)
		{
			PTWCUtilConflictReport (conflicts);
			ProServerconflictsFree (conflicts);
		}
	}

	return  PRO_TK_NO_ERROR;
}

/*====================================================================*\
  FUNCTION: PTWCAccessAddInstance
  PURPOSE:  Access function for the Add Instance example.
\*====================================================================*/
uiCmdAccessState PTWCAccessAddInstance (uiCmdAccessMode m)
{
	ProMode mode;
	wchar_t* server;
	wchar_t* server_class;
	int result;

	status = ProModeCurrentGet (&mode);
	
	if (mode != PRO_MODE_PART && mode != PRO_MODE_ASSEMBLY)
		return ACCESS_REMOVE;

/*--------------------------------------------------------------------*\
	Ensure that there is an active Windchill server
\*--------------------------------------------------------------------*/
	return (PTWCUtilAccessIfWCServer ());
}