//-
// ==========================================================================
// Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors.  All 
// rights reserved.
//
// The coded instructions, statements, computer programs, and/or related 
// material (collectively the "Data") in these files contain unpublished 
// information proprietary to Autodesk, Inc. ("Autodesk") and/or its 
// licensors, which is protected by U.S. and Canadian federal copyright 
// law and by international treaties.
//
// The Data is provided for use exclusively by You. You have the right 
// to use, modify, and incorporate this Data into other products for 
// purposes authorized by the Autodesk software license agreement, 
// without fee.
//
// The copyright notices in the Software and this entire statement, 
// including the above license grant, this restriction and the 
// following disclaimer, must be included in all copies of the 
// Software, in whole or in part, and all derivative works of 
// the Software, unless such copies or derivative works are solely 
// in the form of machine-executable object code generated by a 
// source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. 
// AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED 
// WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF 
// NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 
// PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR 
// TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS 
// BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, 
// DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK 
// AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY 
// OR PROBABILITY OF SUCH DAMAGES.
//
// ==========================================================================
//+

//
// testExCameraSetCmd.cpp
//
// Description:
//     Sample plug-in that exercises the exCameraSet class
//
//	   testExCameraSet -help will list the options.
//
// Example usages:
// testExCameraSet -c;
// testExCameraSet -ac persp cameraSet1;
// testExCameraSet -ac top cameraSet1;
// testExCameraSet -d 0 cameraSet1;
// testExCameraSet -q -camera -layer 0 cameraSet1;
// testExCameraSet -e -camera side -layer 0 cameraSet1;
// testExCameraSet -e -set defaultObjectSet -layer 0 cameraSet1;
// testExCameraSet -q -set -layer 0 cameraSet1;
// testExCameraSet -e -set "" -layer 0 cameraSet1;
// testExCameraSet -e -layerType Left -layer 0 cameraSet1;
// testExCameraSet -q -layerType -layer 0 cameraSet1;
// testExCameraSet -e -active true -layer 0 cameraSet1;
// testExCameraSet -q -active -layer 0 cameraSet1;
// testExCameraSet -q -numLayers cameraSet1;
//
//
#include <maya/MArgList.h>
#include <maya/MIntArray.h>
#include <maya/MGlobal.h>
#include <maya/MPlug.h>
#include <maya/MDagMessage.h>
#include <maya/MDGMessage.h>
#include <maya/MModelMessage.h>
#include <maya/MDagPath.h>
#include <maya/MFnDagNode.h>
#include <maya/MFnCameraSet.h>
#include <maya/MCallbackIdArray.h>
#include <maya/MObjectArray.h>
#include "exCameraSet.h"
#include "testExCameraSetCmd.h"

#define kEditFlag 					"-e"
#define kEditFlagLong				"-edit"
#define kQueryFlag 					"-q"
#define kQueryFlagLong				"-query"
#define kActiveFlag 				"-a"
#define kActiveFlagLong				"-active"
#define kCameraFlag 				"-cam"
#define kCameraFlagLong				"-camera"
#define kCreateFlag 				"-c"
#define kCreateFlagLong				"-create"
#define kAppendCameraFlag 			"-ac"
#define kAppendCameraFlagLong		"-appendCamera"
#define kAppendCameraAndSetFlag 	"-acs"
#define kAppendCameraAndSetFlagLong	"-appendCameraAndSet"
#define kDeleteLayerFlag 			"-d"
#define kDeleteLayerFlagLong		"-deleteLayer"
#define kNumLayersFlag 				"-nl"
#define kNumLayersFlagLong			"-numLayers"
#define kLayerFlag 					"-l"
#define kLayerFlagLong				"-layer"
#define kLayerTypeFlag 				"-lt"
#define kLayerTypeFlagLong			"-layerType"
#define kSetFlag 					"-s"
#define kSetFlagLong				"-set"

#define kHelpFlag					"-h"
#define kHelpFlagLong				"-help"

#define CheckErrorContinue(stat, msg)	\
	if (MS::kSuccess != stat) {			\
		displayError(msg);				\
		continue;						\
	}							

#define CheckErrorReturn(stat, msg)		\
	if (MS::kSuccess != stat) {			\
		displayError(msg);				\
		return;							\
	}

//////////////////////////////////////////////////////////////////////////
//
// Command class implementation
//
//////////////////////////////////////////////////////////////////////////

testExCameraSetCmd::~testExCameraSetCmd() {}

void* testExCameraSetCmd::creator()
{
	return new testExCameraSetCmd();
}

MStatus testExCameraSetCmd::doIt( const MArgList& args)
//
// Parses the given command line arguments and executes them.
//
{
	MStatus status = parseArgs(args);
	if (status != MS::kSuccess)
	{
		MGlobal::displayError("Error parsing argument list");
		return status;
	}

	bool nothingSet = (	!createUsed && !appendCameraUsed && !appendCameraAndSetUsed && !deleteLayerUsed && !cameraUsed && 
						!layerUsed && !helpUsed && !setUsed && !layerTypeUsed && !numLayersUsed);

	if (nothingSet)
	{
		MGlobal::displayError("A flag must be used. testCameraSet -help for availible flags.");
		return MS::kFailure;
	}

	if (helpUsed) {
		MGlobal::displayInfo("testExCameraSet -help");
		MGlobal::displayInfo("\ttestExCameraSet tests the functionality of the exCameraSet node.");
		MGlobal::displayInfo("");
		MGlobal::displayInfo("\t-h -help : This message is printed");
		MGlobal::displayInfo("\t-a -active [true/false]: Set/get whether a particular layer is active");
		MGlobal::displayInfo("\t-ac -appendCamera <cameraName>: Append a new camera layer to the cameraSet using the specified camera");
		MGlobal::displayInfo("\t-acs -appendCameraAndSet <cameraName> <setName>: Append a new camera layer to the cameraSet using the specified camera and set");
		MGlobal::displayInfo("\t-cam -camera [<cameraName>]: Set/get the camera for a particular layer");
		MGlobal::displayInfo("\t-c -create : Create a new cameraSet node");
		MGlobal::displayInfo("\t-d -deleteLayer <layerIndex>: Delete the layer at the given index");
		MGlobal::displayInfo("\t-nl -numLayers: Returns the number of layers defined in the specified cameraSet");
		MGlobal::displayInfo("\t-l -layer <layerIndex>: Specifies the layer index to be used when accessing layer information");
		MGlobal::displayInfo("\t-lt -layerType [<layerTypeName>]: Set/get the layer type for a particular layer.  Possible values are Mono, Left, and Right.");
		MGlobal::displayInfo("\t-s -set [<setName>]: Set/get the set for a particular layer");
		MGlobal::displayInfo("\t-e -edit : Perform an edit operation");
		MGlobal::displayInfo("\t-q -query : Perform a query operation");
		MGlobal::displayInfo("");
	}

	unsigned nObjs = list.length();
	if (nObjs == 0)
	{
		if (createUsed)
		{
			// Create a new cameraSet node.
			MFnDependencyNode dirFn;
			MString noName;
			MObject dirObj = dirFn.create(exCameraSet::id, noName, &status);
			if (!status)
			{
				MGlobal::displayError("Could not create a cameraSet node");
				return status;
			}

			MGlobal::select(dirObj, MGlobal::kReplaceList);
			return status;
		}

		if (appendCameraUsed || appendCameraAndSetUsed || deleteLayerUsed || editUsed || cameraUsed || 
				setUsed || layerTypeUsed || activeUsed || numLayersUsed) {
			MGlobal::displayError("Must specify a cameraSet node");
			status = MS::kFailure;
			return status;
		}
	}
	else
	{
		if (createUsed)
		{
			MGlobal::displayError("-create cannot have any object specifed");
			status = MS::kFailure;
			return status;
		}

		if (appendCameraUsed)
		{
			if (nObjs != 1)
			{
				MGlobal::displayError("-appendCamera must have a single cameraSet node specified");
				status = MS::kFailure;
				return status;
			}

			// Get the specified cameraSet node.
			MObject dirNode = MObject::kNullObj;
			if (!getExCameraSetNode(dirNode))
			{
				MGlobal::displayError("-appendCamera must have a valid exCameraSet node specified");
				status = MS::kFailure;
				return status;
			}

			// Get a dag path to the specified camera.
			MSelectionList camList;
			camList.add(camName);
			MDagPath camPath;
			camList.getDagPath(0, camPath);
			if (!camPath.isValid())
			{
				MGlobal::displayError("-appendCamera must have a valid camera node specified");
				status = MS::kFailure;
				return status;
			}

			// Call the MFnCameraSet method to append the layer.
			MFnCameraSet dirFn(dirNode);
			dirFn.appendLayer(camPath, MObject::kNullObj);

			return status;
		}

		if (appendCameraAndSetUsed)
		{
			if (nObjs != 1)
			{
				MGlobal::displayError("-appendCameraAndSet must have a single cameraSet node specified");
				status = MS::kFailure;
				return status;
			}

			// Get the specified cameraSet node.
			MObject dirNode = MObject::kNullObj;
			if (!getExCameraSetNode(dirNode))
			{
				MGlobal::displayError("-appendCameraAndSet must have a valid exCameraSet node specified");
				status = MS::kFailure;
				return status;
			}

			// Get a dag path to the specified camera.
			MSelectionList camList;
			camList.add(camName);
			MDagPath camPath;
			camList.getDagPath(0, camPath);
			if (!camPath.isValid())
			{
				MGlobal::displayError("-appendCameraAndSet must have a valid camera node specified");
				status = MS::kFailure;
				return status;
			}

			// Get the specified set node.
			MSelectionList setList;
			setList.add(setName);
			MObject setObj = MObject::kNullObj;
			setList.getDependNode(0, setObj);
			if (setObj == MObject::kNullObj)
			{
				MGlobal::displayError("-appendCameraAndSet must have a valid set node specified");
				status = MS::kFailure;
				return status;
			}

			// Call the MFnCameraSet method to append the layer.
			MFnCameraSet dirFn(dirNode);
			dirFn.appendLayer(camPath, setObj);

			return status;
		}


		if (deleteLayerUsed)
		{
			if (nObjs != 1)
			{
				MGlobal::displayError("-deleteLayer must have a single cameraSet node specified");
				status = MS::kFailure;
				return status;
			}

			// Get the specified cameraSet node.
			MObject dirNode = MObject::kNullObj;
			if (!getExCameraSetNode(dirNode))
			{
				MGlobal::displayError("-deleteLayer must have a valid exCameraSet node specified");
				status = MS::kFailure;
				return status;
			}

			// Call the MFnCameraSet method to delete the layer.
			MFnCameraSet dirFn(dirNode);
			dirFn.deleteLayer(cameraLayer);
	
			return status;
		}

		if (numLayersUsed)
		{
			if (queryUsed)
			{
				// Get the specified cameraSet node.
				MObject dirNode = MObject::kNullObj;
				if (!getExCameraSetNode(dirNode))
				{
					MGlobal::displayError("-numLayers must have a valid exCameraSet node specified");
					status = MS::kFailure;
					return status;
				}

				// Call the MFnCameraSet method to get the number of layers.
				MFnCameraSet dirFn(dirNode);
				unsigned int numLayers = dirFn.getNumLayers(&status);
				if (status != MS::kSuccess)	
					MGlobal::displayError("Error getting the number of layers");
				setResult((int)numLayers);
			}
			else
			{
				MGlobal::displayError("-numLayers requires the query flag to be used");
				status = MS::kFailure;
			}
			return status;
		}

		if (cameraUsed)
		{
			if ((nObjs != 1) || (!layerUsed))
			{
				MGlobal::displayError("-camera must have a cameraSet node and layer specified");
				status = MS::kFailure;
				return status;
			}

			// Get the specified cameraSet node.
			MObject dirNode = MObject::kNullObj;
			if (!getExCameraSetNode(dirNode))
			{
				MGlobal::displayError("-camera must have a valid exCameraSet node specified");
				status = MS::kFailure;
				return status;
			}

			if (editUsed)
			{
				// Get a dag path to the specified camera.
				MSelectionList camList;
				camList.add(camName);
				MDagPath camPath;
				camList.getDagPath(0, camPath);
				if (!camPath.isValid())
				{
					MGlobal::displayError("-camera must have a valid camera node specified");
					status = MS::kFailure;
					return status;
				}

				// Call the MFnCameraSet method to set the camera.
				MFnCameraSet dirFn(dirNode);
				dirFn.setLayerCamera((unsigned int)cameraLayer, camPath);
			}
			else if (queryUsed)
			{
				// Call the MFnCameraSet method to get the camera.
				MDagPath camPath;
				MFnCameraSet dirFn(dirNode);
				status = dirFn.getLayerCamera((unsigned int)cameraLayer, camPath);
				if (status == MS::kSuccess)
				{
					MObject camNode = camPath.node();
					MFnDependencyNode nodeFn(camNode);
					setResult(nodeFn.name());
				}
				else
					setResult("");
			}
		}

		if (setUsed)
		{
			if ((nObjs != 1) || (!layerUsed))
			{
				MGlobal::displayError("-set must have a cameraSet node and layer specified");
				status = MS::kFailure;
				return status;
			}

			// Get the specified cameraSet node.
			MObject dirNode = MObject::kNullObj;
			if (!getExCameraSetNode(dirNode))
			{
				MGlobal::displayError("-set must have a valid exCameraSet node specified");
				status = MS::kFailure;
				return status;
			}

			if (editUsed)
			{
				// Get the specified set node.
				MObject setObj = MObject::kNullObj;
				if (setName != "")
				{
					MSelectionList setList;
					setList.add(setName);
					setList.getDependNode(0, setObj);
					if (setObj == MObject::kNullObj)
					{
						MGlobal::displayError("-set must have a valid set node specified");
						status = MS::kFailure;
						return status;
					}
				}

				// Call the MFnCameraSet method to set the set node.
				MFnCameraSet dirFn(dirNode);
				dirFn.setLayerSceneData((unsigned int)cameraLayer, setObj);
			}
			else if (queryUsed)
			{
				// Call the MFnCameraSet method to get the set node.
				MObject setObj;
				MFnCameraSet dirFn(dirNode);
				status = dirFn.getLayerSceneData((unsigned int)cameraLayer, setObj);
				if (status == MS::kSuccess)
				{
					MFnDependencyNode nodeFn(setObj);
					setResult(nodeFn.name());
				}
				else
					setResult("");
			}
		}

		if (layerTypeUsed)
		{
			if ((nObjs != 1) || (!layerUsed))
			{
				MGlobal::displayError("-layerType must have a cameraSet node and layer specified");
				status = MS::kFailure;
				return status;
			}

			// Get the specified cameraSet node.
			MObject dirNode = MObject::kNullObj;
			if (!getExCameraSetNode(dirNode))
			{
				MGlobal::displayError("-layerType must have a valid exCameraSet node specified");
				status = MS::kFailure;
				return status;
			}

			MFnDependencyNode nodeFn(dirNode);
			exCameraSet *exDir = (exCameraSet *)nodeFn.userNode();

			if (editUsed)
			{
				// Get the specified layer type.
				int pt = -1;
				if (layerTypeVal == "Mono")
					pt = 0;
				else if (layerTypeVal == "Left")
					pt = 1;
				else if (layerTypeVal == "Right")
					pt = 2;
				else
				{
					MGlobal::displayError("-layerType must have a valid type specified");
					status = MS::kFailure;
					return status;
				}

				// Call the exCameraSet method to set the layer type.
				exDir->setLayerType((unsigned int)cameraLayer, pt);
			}
			else if (queryUsed)
			{
				// Call the exCameraSet method to get the layer type.
				int lt;
				status = exDir->getLayerType((unsigned int)cameraLayer, lt);
				if (status == MS::kSuccess)
				{
					if (lt == 0)
						setResult("Mono");
					else if (lt == 1)
						setResult("Left");
					else if (lt == 2)
						setResult("Right");
				}
				else
				{
					MGlobal::displayError("exCameraSet node does not have a valid layer type");
					status = MS::kFailure;
					return status;
				}
			}
		}

		if (activeUsed)
		{
			if ((nObjs != 1) || (!layerUsed))
			{
				MGlobal::displayError("-active must have a cameraSet node and layer specified");
				status = MS::kFailure;
				return status;
			}

			// Get the specified cameraSet node.
			MObject dirNode = MObject::kNullObj;
			if (!getExCameraSetNode(dirNode))
			{
				MGlobal::displayError("-active must have a valid exCameraSet node specified");
				status = MS::kFailure;
				return status;
			}

			if (editUsed)
			{
				// Call the MFnCameraSet method to set the set node.
				MFnCameraSet dirFn(dirNode);
				dirFn.setLayerActive((unsigned int)cameraLayer, activeVal);
			}
			else if (queryUsed)
			{
				// Call the MFnCameraSet method to get the active value.
				MStatus stat = MS::kSuccess;
				MFnCameraSet dirFn(dirNode);
				activeVal = dirFn.isLayerActive((unsigned int)cameraLayer, &stat);
				if (stat == MS::kSuccess)
					setResult(activeVal);
				else
					MGlobal::displayError("Could not get active value");
			}
		}
	}
	
	return status;
}

MStatus testExCameraSetCmd::parseArgs( const MArgList& args)
//
// Parses the command line arguments.
//
{
	MStatus status;

	//	Get the flags.  If the create or help flags are used, return success and ignore the other flags.
	createUsed = (args.flagIndex(kCreateFlag, kCreateFlagLong) != MArgList::kInvalidArgIndex);
	editUsed = (args.flagIndex(kEditFlag, kEditFlagLong) != MArgList::kInvalidArgIndex);
	queryUsed = (args.flagIndex(kQueryFlag, kQueryFlagLong) != MArgList::kInvalidArgIndex);
	helpUsed = (args.flagIndex(kHelpFlag, kHelpFlagLong) != MArgList::kInvalidArgIndex);
	numLayersUsed = (args.flagIndex(kNumLayersFlag, kNumLayersFlagLong) != MArgList::kInvalidArgIndex);

	// If flags are used which require no other information, return now.
	if (createUsed || helpUsed)
		return MS::kSuccess;

	unsigned int maxArg = args.length() - 1;
	unsigned int activeIndex = args.flagIndex(kActiveFlag, kActiveFlagLong);
	unsigned int appendCameraIndex = args.flagIndex(kAppendCameraFlag, kAppendCameraFlagLong);
	unsigned int appendCameraAndSetIndex = args.flagIndex(kAppendCameraAndSetFlag, kAppendCameraAndSetFlagLong);
	unsigned int cameraIndex = args.flagIndex(kCameraFlag, kCameraFlagLong);
	unsigned int deleteLayerIndex = args.flagIndex(kDeleteLayerFlag, kDeleteLayerFlagLong);
	unsigned int layerIndex = args.flagIndex(kLayerFlag, kLayerFlagLong);
	unsigned int layerTypeIndex = args.flagIndex(kLayerTypeFlag, kLayerTypeFlagLong);
	unsigned int setIndex = args.flagIndex(kSetFlag, kSetFlagLong);
	activeUsed = (activeIndex != MArgList::kInvalidArgIndex);
	appendCameraUsed = (appendCameraIndex != MArgList::kInvalidArgIndex);
	appendCameraAndSetUsed = (appendCameraAndSetIndex != MArgList::kInvalidArgIndex);
	cameraUsed = (cameraIndex != MArgList::kInvalidArgIndex);
	deleteLayerUsed = (deleteLayerIndex != MArgList::kInvalidArgIndex);
	layerUsed = (layerIndex != MArgList::kInvalidArgIndex);
	layerTypeUsed = (layerTypeIndex != MArgList::kInvalidArgIndex);
	setUsed = (setIndex != MArgList::kInvalidArgIndex);

	// Process each flag.
	bool maxArgUsed = false;
	if (activeUsed)
	{
		if (editUsed)
		{
			activeVal = args.asBool((activeIndex+1), &status);
			if (status != MS::kSuccess)
			{
				MGlobal::displayError("-active must be either true or false");
				return status;
			}
			if ((layerTypeIndex+1) == maxArg)
				maxArgUsed = true;
		}
	}
	if (appendCameraUsed)
	{
		camName = args.asString((appendCameraIndex+1), &status);
		if (status != MS::kSuccess)
		{
			MGlobal::displayError("-appendCamera must have a valid camera node specified");
			return status;
		}

		if ((appendCameraIndex+1) == maxArg)
			maxArgUsed = true;
	}
	if (appendCameraAndSetUsed)
	{
		camName = args.asString((appendCameraAndSetIndex+1));
		setName = args.asString((appendCameraAndSetIndex+2));
		if ((appendCameraAndSetIndex+2) == maxArg)
			maxArgUsed = true;
	}
	if (cameraUsed)
	{
		if (editUsed)
		{
			camName = args.asString(cameraIndex+1);
			if ((cameraIndex+1) == maxArg)
				maxArgUsed = true;
		}
	}
	if (deleteLayerUsed)
	{
		cameraLayer = args.asInt(deleteLayerIndex+1);
		if ((deleteLayerIndex+1) == maxArg)
			maxArgUsed = true;
	}
	if (layerUsed)
	{
		cameraLayer = args.asInt(layerIndex+1);
		if ((layerIndex+1) == maxArg)
			maxArgUsed = true;
	}
	if (layerTypeUsed)
	{
		if (editUsed)
		{
			layerTypeVal = args.asString(layerTypeIndex+1);
			if ((layerTypeIndex+1) == maxArg)
				maxArgUsed = true;
		}
	}
	if (setUsed)
	{
		if (editUsed)
		{
			setName = args.asString(setIndex+1);
			if ((setIndex+1) == maxArg)
				maxArgUsed = true;
		}
	}

	// If all of the arguments have been used, get the cameraSet node from the selection list.
	// Otherwise, get it from the last argument.
	if (maxArgUsed)
		MGlobal::getActiveSelectionList(list);
	else
		list.add(args.asString(maxArg));

	return MS::kSuccess;
}

bool testExCameraSetCmd::getExCameraSetNode(MObject &dirObj)
{
	// Get the specified cameraSet node.
	MObject dirNode = MObject::kNullObj;
	list.getDependNode(0, dirNode);
	if (dirNode == MObject::kNullObj)
		return false;

	MFnDependencyNode nodeFn(dirNode);
	if (nodeFn.typeId() != exCameraSet::id)
		return false;

	dirObj = dirNode;
	return true;
}

