XSIPLUGINCALLBACK CStatus Coat3DExport_Execute( CRef& in_ctxt )
{
	// Unpack the command argument values
	Context ctxt( in_ctxt );
	CValueArray args = ctxt.GetAttribute(L"Arguments");
	CString string;

	// A 3d object with a mesh geometry must be selected
	Selection selection(app.GetSelection());

	bool isPolymesh = true;
	for(int i =0; i< selection.GetCount(); i++)
	{
		X3DObject obj(selection[i]);
		//app.LogMessage(L"obj.IsA(siPolygonMeshID): " + CString(obj.GetType()));
		if(obj.GetType() != L"polymsh" )
		{
			isPolymesh = false;
			break;
		}
	}

	if (selection.GetCount() > 0 && isPolymesh)
	{
		gV = 0; gVn = 0; gVt = 0;
		gVprev = 0; gVnPrev = 0; gVtPrev = 0;
		// prepare the output text file
		CString strOut = Get3DCoatParam( L"tempLocation" ).GetValue();
		
		std::ofstream mfw;
		mfw.open(strOut.GetAsciiString(), std::ios_base::out | std::ios_base::trunc);
		if (mfw.is_open())
		{
			bar.PutMaximum( selection.GetCount() );
			bar.PutStep( 1 );
			bar.PutVisible( true );		

			OutputHeader( mfw);				
			// output the data
			for (int i=0; i < selection.GetCount(); i++)
			{
				gObjCnt = i;
				gVprev = gV;
				gVtPrev = gVt;
				gVnPrev = gVn;
				X3DObject xobj(selection.GetItem(i));

				bar.PutValue(i);
				bar.PutCaption( L"Exporting " + xobj.GetName());

				mfw << "\n";
				mfw << "# Hierarchy (from self to top father)\n";
				string = L"g " + xobj.GetName() + L"\n";
				mfw << string.GetAsciiString();
				mfw << "\n";

				// Get a geometry accessor from the selected object	
				Primitive prim = xobj.GetActivePrimitive();
				PolygonMesh mesh = prim.GetGeometry();
				if (!mesh.IsValid()) return CStatus::False;

				CGeometryAccessor ga = mesh.GetGeometryAccessor();

				OutputVertices( mfw, ga, xobj );
				if (bar.IsCancelPressed()) return CStatus::False;
				OutputPolygonComponents( mfw, ga );
				if (bar.IsCancelPressed()) return CStatus::False;
				//bar.Increment();		
			}
		}
		mfw.close();

		if(Get3DCoatParam(L"bExpMat").GetValue())
		{
			OutputMaterials(selection );
		}
		bar.PutStatusText( L"import.txt" );
		OutputImportTxt();
		bar.PutVisible(false);
                app.LogMessage(L"Export done!");
	}
	else
	{
		app.LogMessage(L"Please, select objects!", siWarningMsg);
		return CStatus::False;
	}

	return CStatus::OK;
}
/** Event handler for when the options dialog is interacted with */
CStatus OgreMeshExportOptions_PPGEvent( const CRef& io_Ctx )
{
	// This callback is called when events happen in the user interface
	// This is where you implement the "logic" code.

	Application app ;
	static bool hasSkel = false;

	PPGEventContext ctx( io_Ctx ) ;

	PPGEventContext::PPGEvent eventID = ctx.GetEventID() ;

	CustomProperty prop = ctx.GetSource() ;	
	Parameter objectNameParam = prop.GetParameters().GetItem( L"objectName" ) ;
    // On open dialog
    if ( eventID == PPGEventContext::siOnInit )
	{
		CString theObjectName;
        // Pre-populate object with currently selected item(s)
		Selection sel(app.GetSelection());
		if (sel.GetCount() > 0)
		{
			CString val;
			for (int i = 0; i < sel.GetCount(); ++i)
			{
				CString thisName = SIObject(sel[i]).GetName();
				val += thisName;
				theObjectName += thisName;
				if (i < sel.GetCount() - 1)
				{
					val += L", ";
					theObjectName += L"_";
				}
			}
			prop.PutParameterValue(L"objectName", val);
		}
		else
		{
			// no selection, assume entire scene
			prop.PutParameterValue(L"objectName", CString(L"[Entire Scene]"));
		}
        // Make the selection read-only
		objectNameParam.PutCapabilityFlag( siReadOnly, true );

		// Default mesh name
		if (prop.GetParameterValue(L"targetMeshFileName") == L"")
		{
			// default name
			prop.PutParameterValue(L"targetMeshFileName", theObjectName + L".mesh");
		}

		// Default material name
		if (prop.GetParameterValue(L"targetMaterialFileName") == L"")
		{
			// default name
			prop.PutParameterValue(L"targetMaterialFileName", theObjectName + L".material");
		}

		// default the frame rate to that selected in animation panel
		prop.PutParameterValue(L"fps", CTime().GetFrameRate());

		// enable / disable the skeleton export based on envelopes
		if (!hasSkeleton(sel, true))
		{
			prop.PutParameterValue(L"exportSkeleton", false);
			Parameter param = prop.GetParameters().GetItem(L"exportSkeleton");
			param.PutCapabilityFlag(siReadOnly, true);
			param = prop.GetParameters().GetItem(L"targetSkeletonFileName");
			param.PutCapabilityFlag(siReadOnly, true);
			hasSkel = false;
		}
		else
		{
			prop.PutParameterValue(L"exportSkeleton", true);
			Parameter param = prop.GetParameters().GetItem(L"exportSkeleton");
			param.PutCapabilityFlag(siReadOnly, false);
			param = prop.GetParameters().GetItem(L"targetSkeletonFileName");
			param.PutCapabilityFlag(siReadOnly, false);

			if (prop.GetParameterValue(L"targetSkeletonFileName") == L"")
			{
				// default name
				prop.PutParameterValue(L"targetSkeletonFileName", theObjectName + L".skeleton");
			}
			hasSkel = true;
		}
		// value of param is a griddata object
		// initialise it with all detected animations if it's empty
		Parameter param = prop.GetParameters().GetItem(L"animationList");
		GridData gd(param.GetValue());
		if (gd.GetRowCount() == 0 || gd.GetCell(0,0) == L"No data has been set")
		{
			populateAnimationsList(gd);
		}
			
	}
    // On clicking a button
	else if ( eventID == PPGEventContext::siButtonClicked )
	{
		CValue buttonPressed = ctx.GetAttribute( L"Button" );	
        // Clicked the refresh animation button
		if ( buttonPressed.GetAsText() == L"refreshAnimation" )
		{
			LONG btn;
			CStatus ret = app.GetUIToolkit().MsgBox(
				L"Are you sure you want to lose the current contents "
				L"of the animations list and to refresh it from mixers?",
				siMsgYesNo,
				L"Confirm",
				btn);
			if (btn == 6)
			{
				Parameter param = prop.GetParameters().GetItem(L"animationList");
				GridData gd(param.GetValue());
				populateAnimationsList(gd);
			}
			
		}
		else if( buttonPressed.GetAsText() == L"addAnimation" )
		{
			Parameter param = prop.GetParameters().GetItem(L"animationList");
			GridData gd(param.GetValue());

			gd.PutRowCount(gd.GetRowCount() + 1);
			// default export to true and sample rate
			gd.PutCell(ANIMATION_LIST_EXPORT_COL, gd.GetRowCount()-1, true);
			gd.PutCell(ANIMATION_LIST_IKFREQ_COL, gd.GetRowCount()-1, (LONG)5);
		}
		else if( buttonPressed.GetAsText() == L"removeAnimation" )
		{
			Parameter param = prop.GetParameters().GetItem(L"animationList");
			GridData gd(param.GetValue());
			GridWidget gw = gd.GetGridWidget();

			// cell-level selection, so have to search for selection in every cell
			long selRow = -1;
			for (long row = 0; row < gd.GetRowCount() && selRow == -1; ++row)
			{
				for (long col = 0; col < gd.GetColumnCount() && selRow == -1; ++col)
				{
					if (gw.IsCellSelected(col, row))
					{
						selRow = row;
					}
				}
			}

			if (selRow != -1)
			{
				LONG btn;
				CStatus ret = app.GetUIToolkit().MsgBox(
					L"Are you sure you want to remove this animation entry?",
					siMsgYesNo,
					L"Confirm",
					btn);
				if (btn == 6)
				{
					// Move all the contents up one
					for (long row = selRow; row < gd.GetRowCount(); ++row)
					{
						for (long col = 0; col < gd.GetColumnCount(); ++col)
						{
							gd.PutCell(col, row, gd.GetCell(col, row+1));
						}
					}
					// remove last row
					gd.PutRowCount(gd.GetRowCount() - 1);
				}

			}

		}
	}
    // Changed a parameter
	else if ( eventID == PPGEventContext::siParameterChange )
	{
		Parameter changed = ctx.GetSource() ;	
		CustomProperty prop = changed.GetParent() ;	
		CString   paramName = changed.GetScriptName() ; 

        // Check paramName against parameter names, perform custom onChanged event
		if (paramName == L"targetMeshFileName")
		{
			// Default skeleton & material name 
			Ogre::String meshName = XSItoOgre(XSI::CString(changed.GetValue()));
			if (hasSkel)
			{
				Ogre::String skelName = meshName;
				if (Ogre::StringUtil::endsWith(skelName, ".mesh"))
				{
					skelName = skelName.substr(0, skelName.size() - 5) + ".skeleton";
				}
				CString xsiSkelName = OgretoXSI(skelName);
				prop.PutParameterValue(L"targetSkeletonFileName", xsiSkelName);
			}
			// default material script name 
			Ogre::String matName = meshName;
			if (Ogre::StringUtil::endsWith(matName, ".mesh"))
			{
				matName = matName.substr(0, matName.size() - 5) + ".material";
			}
			CString xsiMatName = OgretoXSI(matName);
			prop.PutParameterValue(L"targetMaterialFileName", xsiMatName);

			
		}
	}


	return CStatus::OK;	

}