//***************************************************************************************
//
// File supervisor: Softimage Rendering & Pipeline team
//
// (c) Copyright 2001-2005 Avid Technology, Inc. . All rights reserved.
//
//***************************************************************************************

/**************************************************************************************
THIS CODE IS PUBLISHED AS A SAMPLE ONLY AND IS PROVIDED "AS IS".
IN NO EVENT SHALL SOFTIMAGE, AVID TECHNOLOGY, INC. AND/OR THEIR RESPECTIVE
SUPPLIERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS CODE .

COPYRIGHT NOTICE. Copyright © 1999-2005 Avid Technology Inc. . All rights reserved. 

SOFTIMAGE is a registered trademark of Avid Technology Inc. or its subsidiaries 
or divisions. Windows NT is a registered trademark of Microsoft Corp. All other
trademarks contained herein are the property of their respective owners. 
****************************************************************************************/
/*! \file cnv_custompset.cpp
/*!
	implementation file for custom pset classes
*/

#include "stdafx.h"
#include "cnv_custompset.h"
#include "FTKUtil.h"
#include <xsi_sceneitem.h>
#include <xsi_customproperty.h>
#include <xsi_property.h>
#include <xsi_parameter.h>
#include <xsi_material.h>
#include <xsi_shader.h>
#include <Template.h>
#include <VariantParameter.h>
#include <CustomPSet.h> 
#include <CustomParamInfo.h> 
#include <xsi_ppglayout.h>

/**************************************************************************************
CCustomPSetFromXSI
**************************************************************************************/
CCustomPSetFromXSI::CCustomPSetFromXSI(short in_CryFiletype) : CHierarchyTraverserCallback(in_CryFiletype) {};

CCustomPSetFromXSI::~CCustomPSetFromXSI() {};

CStatus CCustomPSetFromXSI::Execute(CdotXSIConverter *in_pContext, CRef in_XSIParent, CSLTemplate *in_pFTKParent, CHierarchyElementInfo* in_pInfo, CRef *io_pXSIModel, CSLTemplate **io_pFTKModel)
{
	CStatus status = CStatus::OK;
	SceneItem l_sceneItem = (SceneItem) *io_pXSIModel;
	Material l_Material = (Material) *io_pXSIModel;
	Shader l_Shader = (Shader) *io_pXSIModel;

	if((l_sceneItem.IsValid() || l_Material.IsValid() || l_Shader.IsValid()) && (*io_pFTKModel != NULL) && (*io_pFTKModel != in_pFTKParent))
	{
		// Get all the properties for this SceneItem
		CRefArray l_properties;
		int loop;

		if(l_sceneItem.IsValid())
		{
			l_properties = l_sceneItem.GetProperties();
		}

		if(l_Material.IsValid())
		{
			l_properties = l_Material.GetProperties();
		}

		if(l_Shader.IsValid())
		{
			l_properties = l_Shader.GetProperties();
		}

		// Enumerate all properties
		for(loop = 0; loop < l_properties.GetCount(); loop++)
		{

			CustomProperty l_property = l_properties.GetItem(loop);

			// If the property is a custom property we process is
			// note: we don't want to export the "ImportFTKOptions" custom property set
			if(l_property.IsValid() && (in_pContext->exportproperty() != l_property)
				&& (l_property.GetName() != L"ImportFTKOptions"))
			{

				CSLTemplate *l_pTemplate = *io_pFTKModel;
				CSLCustomPSet *l_pNewPSet = l_pTemplate->AddCustomPSet();

				if(in_pContext->ftkscene()->Parser()->GetdotXSIFileVersionMajor() >= 5 || in_pContext->ftkscene()->Parser()->GetdotXSIFormat() == FORMAT_COLLADA)
				{
					CString l_CustomPSetType = l_property.GetType();
					l_pNewPSet->SetType((char *)l_CustomPSetType.GetAsciiString());
				}

				l_pNewPSet->SetName((char*)l_property.GetName().GetAsciiString());
				l_pNewPSet->AttachUserData("CREF", in_pContext->AddCRef(l_property));

				// Now we enumerate all the parameters
				
				CRefArray l_parameters = l_property.GetParameters();
				int loop2;

				for(loop2 = 0; loop2 < l_parameters.GetCount(); loop2 ++)
				{
					Parameter		l_parameter = l_parameters.GetItem(loop2);

					// Get the custom parameter value according to the type
					switch(l_parameter.GetValueType())
					{
						case CValue::siInt1 :
						case CValue::siInt2 :
						case CValue::siUInt2 :
						case CValue::siUInt4 :
						case CValue::siInt4 :
						case CValue::siFloat :
						case CValue::siDouble :
						case CValue::siString :
						case CValue::siBool :
						case CValue::siUInt1 :
							// break for all of these acceptable cases
						break;
						default: 
						{
							// skip this parameter; i.e. don't bother exporting it
							logmessage(L"Unable to export this parameter : %s", l_parameter.GetFullName().GetWideString());
							continue;
						}
						break;
					}

					SI_TinyVariant	l_FTKValue;

					CSLVariantParameter		*l_pNewParam = l_pNewPSet->AddParameter();
					
					l_pNewParam->SetName((char*)l_parameter.GetScriptName().GetAsciiString());
					CValue	l_XSIValue = l_parameter.GetValue();

					// Get the custom parameter value according to the type
					switch(l_parameter.GetValueType())
					{
						case CValue::siInt1 :
						{
							l_FTKValue.variantType = SI_VT_BYTE;
							l_FTKValue.bVal = (char) ((LONG)l_XSIValue);
							l_pNewParam->SetValue(&l_FTKValue);

							// Create additional information for this pset
							CSLXSICustomParamInfo	*l_pParamInfo = l_pNewPSet->CreateCustomParamInfo(l_pNewParam);
							l_pParamInfo->SetCapabilities(l_parameter.GetCapabilities());
							l_FTKValue.bVal = (char) ((LONG)l_parameter.GetMin());
							l_pParamInfo->SetMinValue(l_FTKValue);
							l_FTKValue.bVal = (char) ((LONG)l_parameter.GetMax());
							l_pParamInfo->SetMaxValue(l_FTKValue);
						}
						break;
						case CValue::siInt2 :
						{
							l_FTKValue.variantType = SI_VT_SHORT;
							l_FTKValue.sVal = (short) ((LONG)l_XSIValue);
							l_pNewParam->SetValue(&l_FTKValue);

							// Create additional information for this pset
							CSLXSICustomParamInfo	*l_pParamInfo = l_pNewPSet->CreateCustomParamInfo(l_pNewParam);
							l_pParamInfo->SetCapabilities(l_parameter.GetCapabilities());
							l_FTKValue.sVal = (short) ((LONG)l_parameter.GetMin());
							l_pParamInfo->SetMinValue(l_FTKValue);
							l_FTKValue.sVal = (short) ((LONG)l_parameter.GetMax());
							l_pParamInfo->SetMaxValue(l_FTKValue);
						}
						break;
						case CValue::siUInt2 :
						case CValue::siUInt4 :
						case CValue::siInt4 :
						{
							l_FTKValue.variantType = SI_VT_INT;
							l_FTKValue.nVal = (int) ((LONG)l_XSIValue);
							l_pNewParam->SetValue(&l_FTKValue);

							// Create additional information for this pset
							CSLXSICustomParamInfo	*l_pParamInfo = l_pNewPSet->CreateCustomParamInfo(l_pNewParam);
							l_pParamInfo->SetCapabilities(l_parameter.GetCapabilities());
							l_FTKValue.nVal = (int) ((LONG)l_parameter.GetMin());
							l_pParamInfo->SetMinValue(l_FTKValue);
							l_FTKValue.nVal = (int) ((LONG)l_parameter.GetMax());
							l_pParamInfo->SetMaxValue(l_FTKValue);
						}
						break;
						case CValue::siFloat :
						{
							l_FTKValue.variantType = SI_VT_FLOAT;
							l_FTKValue.fVal = (float)l_XSIValue;
							l_pNewParam->SetValue(&l_FTKValue);

							// Create additional information for this pset
							CSLXSICustomParamInfo	*l_pParamInfo = l_pNewPSet->CreateCustomParamInfo(l_pNewParam);
							l_pParamInfo->SetCapabilities(l_parameter.GetCapabilities());

							l_FTKValue.fVal = (float) l_parameter.GetMin();
							l_pParamInfo->SetMinValue(l_FTKValue);

							l_FTKValue.fVal = (float) l_parameter.GetMax();
							l_pParamInfo->SetMaxValue(l_FTKValue);
						}
						break;
						case CValue::siDouble :
						{
							l_FTKValue.variantType = SI_VT_DOUBLE;
							l_FTKValue.dVal = (double)l_XSIValue;
							l_pNewParam->SetValue(&l_FTKValue);

							// Create additional information for this pset
							CSLXSICustomParamInfo	*l_pParamInfo = l_pNewPSet->CreateCustomParamInfo(l_pNewParam);
							l_pParamInfo->SetCapabilities(l_parameter.GetCapabilities());
							l_FTKValue.dVal = (double) l_parameter.GetMin();
							if(l_FTKValue.dVal < -FLT_MAX)
								l_FTKValue.dVal = -FLT_MAX;
							l_pParamInfo->SetMinValue(l_FTKValue);

							l_FTKValue.dVal = (double) l_parameter.GetMax();
							if(l_FTKValue.dVal > FLT_MAX)
								l_FTKValue.dVal = FLT_MAX;
							l_pParamInfo->SetMaxValue(l_FTKValue);
						}
						break;
						case CValue::siString :
						{
							l_FTKValue.variantType = SI_VT_PCHAR;
							CString l_XSIString = l_XSIValue;
							char *l_pAnsiString = (char *) calloc(sizeof(char), wcslen(l_XSIString.GetWideString()) + 1);
							wcstombs(l_pAnsiString, l_XSIString.GetWideString(), wcslen(l_XSIString.GetWideString()));
							l_FTKValue.p_cVal = l_pAnsiString;
							l_pNewParam->SetValue(&l_FTKValue);


							// TODO: capabilities are not supported on strings
						}
						break;
						case CValue::siBool :
						{
							l_FTKValue.variantType = SI_VT_BOOL;
							l_FTKValue.boolVal = ((LONG)l_XSIValue) ? true : false;
							l_pNewParam->SetValue(&l_FTKValue);

							// Create additional information for this pset
							CSLXSICustomParamInfo	*l_pParamInfo = l_pNewPSet->CreateCustomParamInfo(l_pNewParam);
							l_pParamInfo->SetCapabilities(l_parameter.GetCapabilities());
						}
						break;
						case CValue::siUInt1 :
						{
							l_FTKValue.variantType = SI_VT_UBYTE;
							l_FTKValue.ubVal = (unsigned char) ((LONG)l_XSIValue);
							l_pNewParam->SetValue(&l_FTKValue);

							// Create additional information for this pset
							CSLXSICustomParamInfo	*l_pParamInfo = l_pNewPSet->CreateCustomParamInfo(l_pNewParam);
							l_pParamInfo->SetCapabilities(l_parameter.GetCapabilities());
							l_FTKValue.ubVal = (unsigned char) ((LONG)l_parameter.GetMin());
							l_pParamInfo->SetMinValue(l_FTKValue);
							l_FTKValue.ubVal = (unsigned char) ((LONG)l_parameter.GetMax());
							l_pParamInfo->SetMaxValue(l_FTKValue);
						}
						break;
						default: 
						{
							// this should be caught by the above switch statement; ending up in here means
							// that there is a missed case above for skipping the param completely
							logmessage(L"Error exporting this parameter : %s", l_parameter.GetFullName().GetWideString());
							assert(false);
						}
						break;
					}
				}
			}
		}
	}

	return status;
}

wchar_t *CCustomPSetFromXSI::GetClassID(){return L"CCustomPSetFromXSI";}

/**************************************************************************************
CCustomPSetToXSI
**************************************************************************************/
CCustomPSetToXSI::CCustomPSetToXSI(short in_CryFiletype) : CHierarchyTraverserCallback(in_CryFiletype) {};

CCustomPSetToXSI::~CCustomPSetToXSI() {};

CStatus CCustomPSetToXSI::Execute(CdotXSIConverter *in_pContext, CRef in_XSIParent, CSLTemplate *in_pFTKParent, CHierarchyElementInfo* in_pInfo, CRef *io_pXSIModel, CSLTemplate **io_pFTKModel)
{
	CStatus status = CStatus::OK;

	SceneItem l_sceneItem = (SceneItem) *io_pXSIModel;
	Material l_Material = (Material) *io_pXSIModel;
	Shader l_Shader = (Shader) *io_pXSIModel;

	if((l_sceneItem.IsValid() || l_Material.IsValid() || l_Shader.IsValid()) && (*io_pFTKModel != NULL))
	{
		// we go through all the custom psets of the template
		int loop;				

		CSLTemplate *l_pTemplate = *io_pFTKModel;

		for(loop = 0; loop < l_pTemplate->GetCustomPSetCount(); loop ++)
		{
			CSLCustomPSet	*l_pCustomPSet = l_pTemplate->GetCustomPSetList()[loop];
			CustomProperty	l_XSICustomPSet;

			// create the custom pset in XSI
			CString l_PsetName;
			CString l_PsetType(L"CustomProperty");
			bool	l_bCreateParam = true;

			l_PsetName.PutAsciiString(l_pCustomPSet->GetName());

			
			// but first, check if we must create the pset using a defined custom pset type
			// we only handle color here for 3.6 and lower

			int loop2;
			
			if( in_pContext->ftkscene()->Parser()->GetdotXSIFileVersionMajor() < 5)
			{
				if(	(l_pCustomPSet->GetParameterCount() == 4) && 
					(strcmp(l_pCustomPSet->GetParameterList()[0]->GetName(), "Color_R") == 0) && 
					(strcmp(l_pCustomPSet->GetParameterList()[1]->GetName(), "Color_G") == 0) && 
					(strcmp(l_pCustomPSet->GetParameterList()[2]->GetName(), "Color_B") == 0) && 
					(strcmp(l_pCustomPSet->GetParameterList()[3]->GetName(), "Color_A") == 0))
				{
					l_PsetType = CString(L"CustomColor");
					l_bCreateParam = false;
				}
			}
			else
			{
				if((l_pCustomPSet->GetType() != NULL) && (strcmp(l_pCustomPSet->GetType(), "customparamset") != 0))
				{
					l_PsetType.PutAsciiString(l_pCustomPSet->GetType());
					l_bCreateParam = false;
				}

			}

			if(l_sceneItem.IsValid())
			{
				l_XSICustomPSet = l_sceneItem.AddProperty(l_PsetType,false, l_PsetName);
				if((l_XSICustomPSet.IsValid() == false) && (l_PsetType != CString(L"CustomProperty")))
				{
					l_XSICustomPSet = l_sceneItem.AddProperty(CString(L"CustomProperty"),false, l_PsetName);
					l_bCreateParam = true;
				}
			}

			if(l_Material.IsValid())
			{
				l_XSICustomPSet = l_Material.AddProperty(l_PsetType,false, l_PsetName);
				if((l_XSICustomPSet.IsValid() == false) && (l_PsetType != CString(L"CustomProperty")))
				{
					l_XSICustomPSet = l_Material.AddProperty(CString(L"CustomProperty"),false, l_PsetName);
					l_bCreateParam = true;
				}
			}

			if(l_Shader.IsValid())
			{
				l_XSICustomPSet = l_Shader.GetProperties().GetItem(l_PsetName);

				if(l_XSICustomPSet.IsValid() == false)
				{
					l_XSICustomPSet = l_Shader.AddProperty(l_PsetType, false, l_PsetName);

					if((l_XSICustomPSet.IsValid() == false) && (l_PsetType != CString(L"CustomProperty")))
					{
						l_XSICustomPSet = l_Shader.AddProperty(CString(L"CustomProperty"),false, l_PsetName);
						l_bCreateParam = true;
					}
				}
			}

			l_pCustomPSet->AttachUserData("CREF", in_pContext->AddCRef(l_XSICustomPSet));

			// now process the parameters

			for(loop2 = 0; loop2 < l_pCustomPSet->GetParameterCount(); loop2++)
			{
				CSLVariantParameter *l_pParameter = l_pCustomPSet->GetParameterList()[loop2];
				Parameter l_XSIParameter;
				
				CString				l_scriptname;
				CValue::DataType	l_type;
				int					l_capabilities = siAnimatable|siPersistable;
				CString				l_name;
				CString				l_description;
				CValue				l_default_value;
				CValue				l_min_value;
				CValue				l_max_value;
				bool				l_bExtraInfo = false;

				l_scriptname.PutAsciiString(l_pParameter->GetName());
				l_name.PutAsciiString(l_pParameter->GetName());
				SI_TinyVariant *l_pValue = l_pParameter->GetValue();
				CSLXSICustomParamInfo	*l_pParamInfo = l_pParameter->CustomParamInfo();
				if(l_pParamInfo)
				{
					l_bExtraInfo = true;
					l_capabilities = l_pParamInfo->GetCapabilities();
				}


				switch(l_pValue->variantType)
				{
					case SI_VT_BYTE : 
					{
						l_type = CValue::siInt1;
						l_default_value = CValue((LONG)l_pValue->bVal);
						if(l_pParamInfo)
						{
							SI_TinyVariant min, max;
							l_pParamInfo->GetMinValue(min);
							l_pParamInfo->GetMaxValue(max);

							l_min_value = CValue((LONG)min.bVal);
							l_max_value = CValue((LONG)max.bVal);
						}
					}
					break;
					case SI_VT_UBYTE : 
					{
						l_type = CValue::siUInt1;
						l_default_value = CValue((LONG)l_pValue->ubVal);
						if(l_pParamInfo)
						{
							SI_TinyVariant min, max;
							l_pParamInfo->GetMinValue(min);
							l_pParamInfo->GetMaxValue(max);

							l_min_value = CValue((LONG)min.ubVal);
							l_max_value = CValue((LONG)max.ubVal);
						}
					}
					break;

					case SI_VT_SHORT : 
					{
						l_type = CValue::siInt2;
						l_default_value = CValue((short)l_pValue->sVal);
						if(l_pParamInfo)
						{
							SI_TinyVariant min, max;
							l_pParamInfo->GetMinValue(min);
							l_pParamInfo->GetMaxValue(max);

							l_min_value = CValue((short)min.sVal);
							l_max_value = CValue((short)max.sVal);
						}
					}
					break;
					case SI_VT_USHORT : 
					{
						l_type = CValue::siUInt2;
						l_default_value = CValue((short)l_pValue->usVal);
						if(l_pParamInfo)
						{
							SI_TinyVariant min, max;
							l_pParamInfo->GetMinValue(min);
							l_pParamInfo->GetMaxValue(max);

							l_min_value = CValue((short)min.usVal);
							l_max_value = CValue((short)max.usVal);
						}
					}
					break;

					case SI_VT_INT : 
					case SI_VT_LONG : 
					{
						l_type = CValue::siInt4;
						l_default_value = CValue((LONG)l_pValue->nVal);
						if(l_pParamInfo)
						{
							SI_TinyVariant min, max;
							l_pParamInfo->GetMinValue(min);
							l_pParamInfo->GetMaxValue(max);

							l_min_value = CValue((LONG)min.nVal);
							l_max_value = CValue((LONG)max.nVal);
						}
					}
					break;
					case SI_VT_ULONG : 
					case SI_VT_UINT : 
					{
						l_type = CValue::siUInt4;
						l_default_value = CValue((LONG)l_pValue->unVal);
						if(l_pParamInfo)
						{
							SI_TinyVariant min, max;
							l_pParamInfo->GetMinValue(min);
							l_pParamInfo->GetMaxValue(max);

							l_min_value = CValue((LONG)min.unVal);
							l_max_value = CValue((LONG)max.unVal);
						}
					}
					break;

					case SI_VT_FLOAT : 
					{
						l_type = CValue::siFloat;
						l_default_value = CValue((float)l_pValue->fVal);
						if(l_pParamInfo)
						{
							SI_TinyVariant min, max;
							l_pParamInfo->GetMinValue(min);
							l_pParamInfo->GetMaxValue(max);

							l_min_value = CValue((float)min.fVal);
							l_max_value = CValue((float)max.fVal);
							if  ( fabs( (float)max.fVal - (float)min.fVal ) < 0.00001f)
							{
								l_max_value = l_max_value = CValue((float)max.fVal+1);
							}
						}
					}
					break;

					case SI_VT_DOUBLE : 
					{
						l_type = CValue::siDouble;
						l_default_value = CValue((float)l_pValue->dVal);
						if(l_pParamInfo)
						{
							SI_TinyVariant min, max;
							l_pParamInfo->GetMinValue(min);
							l_pParamInfo->GetMaxValue(max);

							if (min.dVal < -FLT_MAX)
								l_min_value = CValue(-FLT_MAX);
							else
								l_min_value = CValue((float)min.dVal);

							if (max.dVal > FLT_MAX)
								l_max_value = CValue(FLT_MAX);
							else
								l_max_value = CValue((float)max.dVal);
						}
					}
					break;

					case SI_VT_BOOL : 
					{
						l_type = CValue::siBool;
						l_default_value = CValue((LONG)l_pValue->boolVal);
					}
					break;

					case SI_VT_PCHAR : 
					{
						l_type = CValue::siString;
						wchar_t *l_pUniString = (wchar_t*) calloc(sizeof(wchar_t), strlen(l_pValue->p_cVal)+1);
						mbstowcs(l_pUniString,l_pValue->p_cVal, strlen(l_pValue->p_cVal)+1); 
						l_default_value = CString(l_pUniString);
						free(l_pUniString);
					}
					break;

					default: logmessage(L"Unable to import this parameter : %s", l_pParameter->GetName());
						continue;
						break;

				}


				if(l_bCreateParam)
				{
					if(l_bExtraInfo)
					{
						l_XSICustomPSet.AddParameter
						(
							l_scriptname,
							l_type,
							l_capabilities,
							l_name,
							l_description,
							l_default_value,
							l_min_value,
							l_max_value,
							l_min_value,
							l_max_value,
							l_XSIParameter
						);



					}
					else
					{
						l_XSICustomPSet.AddParameter
						(
							l_scriptname,
							l_type,
							l_capabilities,
							l_name,
							l_description,
							l_default_value,
							l_XSIParameter
						);
					}
				}
				else
				{
					l_XSIParameter = l_XSICustomPSet.GetParameter(l_scriptname);
					if(l_XSIParameter.IsValid())
					{
						l_XSIParameter.PutValue(l_default_value);
					}
				}

				if ( ( l_pValue->variantType == SI_VT_PCHAR ) && l_pValue->p_cVal && strstr ( l_pValue->p_cVal,"\n"))
				{
					XSI::PPGLayout layout = l_XSICustomPSet.GetPPGLayout();
					layout.AddString (l_name,l_name,true);
				} else {
					XSI::PPGLayout layout = l_XSICustomPSet.GetPPGLayout();
					layout.AddItem (l_name);
				}

			}
		}
	}

	return status;
}

wchar_t *CCustomPSetToXSI::GetClassID(){return L"CCustomPSetToXSI";}

