global string $UnityFbxFilePathAttr = "unityFbxModelFilePath";
global string $UnityFbxFileNameAttr = "unityFbxModelFileName";
global string $UnityFbxAnimFilePathAttr = "unityFbxAnimFilePath";
global string $UnityFbxAnimFileNameAttr = "unityFbxAnimFileName";
global string $UnityFbxStripNamespaceAttr = "unityFbxStripNamespace";
global string $UnityFbxNamespaceAttr = "unityFbxStripSpecificNamespace";
global string $UnityFbxNamespaceAttrNiceName = "Strip Specific Namespace";
global string $UnityExportSetNameFormat = "^1s_UnityExportSet";

global string $UnityModuleName = "UnityFbxForMaya";

global string $UnityImportSettingsOptionVar = "UnityFbxImportSettings";
global string $UnityExportSettingsOptionVar = "UnityFbxExportSettings";

global string $UnityDefaultImportSettingsFileName = "unityFbxImportSettings.mel";
global string $UnityDefaultExportSettingsFileName = "unityFbxExportSettings.mel";

global string $UnityDefaultImportSettings = "\
FBXResetImport;\n\
FBXImportAxisConversionEnable -v true;\n\
FBXImportCameras -v true;\n\
FBXImportLights -v true;\n\
FBXImportSetTake -takeIndex -1;\n\
// Add and update animation\n\
FBXImportMode -v merge;";

global string $UnityDefaultExportSettings = "\
FBXResetExport;\n\
// FBX file format\n\
FBXExportInAscii -v false;\n\
FBXExportFileVersion -v FBX201600;\n\
\n\
// Geometry\n\
FBXExportSmoothMesh -v false;\n\
FBXExportInstances -v true;\n\
FBXExportReferencedAssetsContent -v false;\n\
\n\
// Animation\n\
FBXExportAnimationOnly -v false;\n\
\n\
FBXExportCameras -v true;\n\
FBXExportLights -v true;\n\
\n\
FBXExportEmbeddedTextures -v false;\n\
\n\
// Units\n\
FBXExportScaleFactor 1;\n\
FBXExportConvertUnitString cm;\n\
\n\
// Axis Conversion\n\
FBXExportUpAxis y;";

global int $UnityFbxFilePathIndex = 0;
global int $UnityFbxFileNameIndex = 1;
global int $UnityFbxAnimFilePathIndex = 2;
global int $UnityFbxAnimFileNameIndex = 3;
global int $UnityFileNameWithoutExtIndex = 4;

/* Enum */
global int $UnityExportAnim = 0;
global int $UnityExportModel = 1;
global int $UnityExportModelAnim = 2;

global proc unityRemoveNativeMenuOnLoad(){
    $removeSendToUnityMenu = `optionVar -q "UnityFbxForMaya_removeSendToUnityMenu"`;
    if($removeSendToUnityMenu && `menu -exists "sendToUnityMenu"`){
        //Remove the GamePipeline 'SendToUnity' button
        menu -e -visible false "sendToUnityMenu";
    }
}

// Load a specified settings file
proc int loadUnityFbxSettings(string $settingType, string $optionVarName, string $defaultSettingsFileName, string $defaultSettings){
    global string $UnityModuleName;

    $fileName = `optionVar -q $optionVarName`;

    // if no filename set (optionVar cleared), reset it to default filename
    if ($fileName == 0){
        $modulePath = `moduleInfo -moduleName $UnityModuleName -path`;
        // {$modulePath}/scripts/{$defaultSettingsFileName}
        $modulePath = $modulePath + "/scripts/" + $defaultSettingsFileName;

        $fileName = $modulePath;
        optionVar -stringValue $optionVarName $fileName;
    }

    // check if the file exists
    if (`file -q -ex $fileName` == false){
        // create file with default settings
        $fileId = `fopen $fileName "w"`;
        fprint $fileId $defaultSettings;
        fclose $fileId;
    }

    // if the file still doesn't exist (failed to create)
    // load the default settings and print a warning
    if (`file -q -ex $fileName` == false){
        warning ("Failed to find Unity Fbx "+$settingType+" Settings at: " + $fileName + ", loading default settings.");
        eval ($defaultSettings);
        return true;
    }
    
    eval ("source \"" + $fileName + "\"");
    return true;
}


// Load the Export Settings from file
proc int loadUnityFbxExportSettings(){
    global string $UnityExportSettingsOptionVar;
    global string $UnityDefaultExportSettings;
    global string $UnityDefaultExportSettingsFileName;
    return loadUnityFbxSettings(
        "Export",
        $UnityExportSettingsOptionVar,
        $UnityDefaultExportSettingsFileName,
        $UnityDefaultExportSettings
    );
}


// Load the Import Settings from a file
proc int loadUnityFbxImportSettings(){
    global string $UnityImportSettingsOptionVar;
    global string $UnityDefaultImportSettings;
    global string $UnityDefaultImportSettingsFileName;
    return loadUnityFbxSettings(
        "Import",
        $UnityImportSettingsOptionVar,
        $UnityDefaultImportSettingsFileName,
        $UnityDefaultImportSettings
    );
}


proc string getAttribute(string $node, string $attr){
    if (`attributeExists $attr $node`){
        return `getAttr ($node + "." + $attr)`;
    }
    return "";
}

proc int getBoolAttribute(string $node, string $attr){
        if (`attributeExists $attr $node`){
        return `getAttr ($node + "." + $attr)`;
    }
    return 0;
}

proc storeBoolAttribute(string $node, string $attr, int $attrValue){
    if (!attributeExists($attr, $node)){
        addAttr -shortName $attr -storable true -attributeType bool $node;
    }
    setAttr ($node+"."+$attr) $attrValue;
}

proc storeStringAttribute(string $node, string $attr, string $attrValue, string $niceName){
    $attrType = "string";
    if (!attributeExists($attr, $node)){
		if ($niceName != ""){
		    addAttr -shortName $attr -niceName $niceName -storable true -dataType $attrType $node;
		}
		else {
		    addAttr -shortName $attr -storable true -dataType $attrType $node;
		}
    }
    setAttr ($node+"."+$attr) -type $attrType $attrValue;
}


proc int setExists(string $setName){
    return stringArrayContains($setName, `ls -sets`);
}

proc int loadUnityPlugin(string $plugin){
    if (`pluginInfo -q -loaded $plugin` == false){
        loadPlugin $plugin;
        if (`pluginInfo -q -loaded $plugin` == false){
            return false;
        }
    }
    return true;
};

// show a yes/no style dialog, return true if user clicked confirm, false if user canceled
proc int showConfirmDialog(string $title, string $message, string $confirmButtonName, string $cancelButtonName){
    // create a confirm dialog with a yes and no button. Specif
    $response = `confirmDialog -title $title
                      -message $message
                      -button $confirmButtonName
                      -button $cancelButtonName
                      -defaultButton $confirmButtonName
                      -cancelButton $cancelButtonName
                      -dismissString $cancelButtonName`;
                      
    return ( $response == $confirmButtonName );
}

// get the namespace of the given object
proc string getObjectNamespace(string $objectName){
    string $lsResult[] = `ls -showNamespace -an $objectName`;
    return $lsResult[1];
}

// =======================

// Determine the export attributes to be used by the export set for the given export path.
// If animation only, check for {model}@{animation}.fbx naming convention and set the name to be used for the export set and namespace (filename without ext)
// to be {model} so that if {model}.fbx has already been imported, the animation is applied.
//
// returns an array of export attributes: 
// export file path, file name, animation file path, animation file name, and filename without ext (for the export set and namespace names)
proc string[] getExportSetAttributes(string $exportPath, int $exportAnimOnly){
    global int $UnityFbxFilePathIndex;
    global int $UnityFbxFileNameIndex;
    global int $UnityFbxAnimFilePathIndex;
    global int $UnityFbxAnimFileNameIndex;
    global int $UnityFileNameWithoutExtIndex;

    string $exportAttributes[5];
    
    $exportDir = dirname($exportPath);
    $exportFileName = basename($exportPath, "");
    $exportAnimDir = $exportDir;
    $fileNameWithoutExt = basename($exportPath, ".fbx");
    $exportAnimFileName = ($fileNameWithoutExt + "@Take1.fbx");
    
    if($exportAnimOnly){
        // import as animation
        $exportAnimFileName = $exportFileName;
        
        if(match("@", basename($exportPath, ".fbx")) != ""){
            $fileNameWithoutExt = match("[^@]+", $fileNameWithoutExt);
        }
    }
    $fileNameWithoutExt = formValidObjectName($fileNameWithoutExt);
    
    $exportAttributes[$UnityFbxFilePathIndex] = $exportDir;
    $exportAttributes[$UnityFbxFileNameIndex] = $exportFileName;
    $exportAttributes[$UnityFbxAnimFilePathIndex] = $exportAnimDir;
    $exportAttributes[$UnityFbxAnimFileNameIndex] = $exportAnimFileName;
    $exportAttributes[$UnityFileNameWithoutExtIndex] = $fileNameWithoutExt;
    
    return $exportAttributes;
}

// Get export set name with format "{$fileNameWithoutExt}_UnityExportSet"
proc string getNewExportSetName(string $fileNameWithoutExt){
    global string $UnityExportSetNameFormat;
    return `format -stringArg $fileNameWithoutExt $UnityExportSetNameFormat`;
}

// Get the name of the namespace to add contents of fbx into.
// Namespace name is {currentNamespace}:{$fileNameWithoutExt} or :{$fileNameWithoutExt} 
// if current namespace is root namespace.
proc string getTargetNamespaceName(string $fileNameWithoutExt){
    string $origNamespace = `namespaceInfo -cur -an`;
    string $targetNamespace = ":" + $fileNameWithoutExt;
    // make sure there are no duplicate colons in namespace name
    if($origNamespace != ":"){
        $targetNamespace = `format -s $origNamespace -s $fileNameWithoutExt "^1s:^2s"`;
    }
    return $targetNamespace;
}

// Get or create the export set in the root namespace.
// Return true if a set has been created, and false if it already exists.
proc int getOrCreateExportSet(string $unityExportSet, string $origNamespace){
    if (setExists($unityExportSet)){
        return false;
    }
   
    if(!`namespaceInfo -isRootNamespace $origNamespace`){
        namespace -set ":";
    }
    
    // if a set is selected when creating a new set, then
    // the selected set will be added into the new set.
    // avoid this by temporarily deselecting everything.
    $origSelection = `ls -sl`;
    select -clear;
    
    // couldn't find export set so create it
    sets -name $unityExportSet;
    
    if(size($origSelection) > 0){
        select -r $origSelection;
    }
    return true;
}

global proc unityOnToggleStripNamespace(string $exportSetName)
{
    global string $UnityFbxStripNamespaceAttr;
    global string $UnityFbxNamespaceAttr;

    int $stripNamespaces = `getAttr ($exportSetName + "." + $UnityFbxStripNamespaceAttr)`;

    $stripNamespaceAttrName = ($exportSetName + "." + $UnityFbxNamespaceAttr);

    // temporarily unlock to be able to modify namespace attr
    lockNode -lock false $exportSetName;

    setAttr -lock (!$stripNamespaces) $stripNamespaceAttrName;

    // lock set so it doesn't get deleted when empty
    lockNode -lock true $exportSetName;
}

// Add or update the following five attributes of the given export set, to be used for exporting:
// - export directory
// - export file name
// - export animation directory
// - export animation file name
// - target namespace name (namespace that the contents of set belong to)
proc setExportSetAttributes(
    string $unityExportSet, int $isAnimFile, int $setCreated, 
    string $exportAttrs[], int $stripNamespaces
    ){

    global string $UnityFbxFilePathAttr;
    global string $UnityFbxFileNameAttr;
    global string $UnityFbxAnimFilePathAttr;
    global string $UnityFbxAnimFileNameAttr;
    global string $UnityFbxStripNamespaceAttr;
    global string $UnityFbxNamespaceAttr;
    global string $UnityFbxNamespaceAttrNiceName;
    
    global int $UnityFbxFilePathIndex;
    global int $UnityFbxFileNameIndex;
    global int $UnityFbxAnimFilePathIndex;
    global int $UnityFbxAnimFileNameIndex;
    global int $UnityFileNameWithoutExtIndex;
    
    $exportDir = $exportAttrs[$UnityFbxFilePathIndex];
    $exportFileName = $exportAttrs[$UnityFbxFileNameIndex];
    $exportAnimDir = $exportAttrs[$UnityFbxAnimFilePathIndex];
    $exportAnimFileName = $exportAttrs[$UnityFbxAnimFileNameIndex];
    $fileNameWithoutExt = $exportAttrs[$UnityFileNameWithoutExtIndex];
    
    // unlock set so we can add attributes to it
    lockNode -lock false $unityExportSet;
    
    if ((!$isAnimFile || ($isAnimFile && $setCreated)) && $exportDir != ""){
        storeStringAttribute($unityExportSet, $UnityFbxFilePathAttr, $exportDir, "");
    }
    
    if ((!$isAnimFile || ($isAnimFile && $setCreated)) && $exportFileName != ""){
        storeStringAttribute($unityExportSet,$UnityFbxFileNameAttr,$exportFileName, "");
    }
    
    if($exportAnimDir != ""){
        storeStringAttribute($unityExportSet,$UnityFbxAnimFilePathAttr,$exportAnimDir, "");
    }
    
    if($exportAnimFileName != ""){
        storeStringAttribute($unityExportSet,$UnityFbxAnimFileNameAttr,$exportAnimFileName, "");
    }

    storeBoolAttribute($unityExportSet, $UnityFbxStripNamespaceAttr, $stripNamespaces);

    storeStringAttribute($unityExportSet, $UnityFbxNamespaceAttr, "", $UnityFbxNamespaceAttrNiceName);

    $stripNamespaceAttrName = ($unityExportSet + "." + $UnityFbxStripNamespaceAttr);
    setAttr -lock (!$stripNamespaces) $stripNamespaceAttrName;
    scriptJob -attributeChange $stripNamespaceAttrName ("unityOnToggleStripNamespace " + $unityExportSet) -protected;

    // lock set so it doesn't get deleted when empty
    lockNode -lock true $unityExportSet;
}

proc switchUnityProject(string $newProjectPath){
    $currentDir = dirname($newProjectPath);
    // Change Unity project if fbx is from a different Unity project.
    // Get the project based on the folder structure (i.e. folder above Assets)
    $head = dirname($currentDir);
    $tail = basename($currentDir, "");
    // Check that we are not at the root directory.
    // dirname($head) returns the last directory name in the path, 
    // or head if head is the root directory.
    while ($head != "" && dirname($head) != $head){
        if (`strcmp $tail "Assets"` == 0){
            // this is a valid Unity project, so set it
            optionVar -sv "UnityProject" $head;
            break;
        }
        $tail = basename($head, "");
        $head = dirname($head);
    }
}

// =======================

proc importFile(string $filePathStr){
    // get the global variables
    global string $UnityFbxFilePathAttr;
    global string $UnityFbxFileNameAttr;
    global string $UnityFbxAnimFilePathAttr;
    global string $UnityFbxAnimFileNameAttr;
    
    global int $UnityFbxFilePathIndex;
    global int $UnityFbxFileNameIndex;
    global int $UnityFbxAnimFilePathIndex;
    global int $UnityFbxAnimFileNameIndex;
    global int $UnityFileNameWithoutExtIndex;
    
    $isAnimFile = false;
    if(match("@", basename($filePathStr, ".fbx")) != ""){
        // import as animation
        $isAnimFile = true;
    }
    
    $exportAttrs = getExportSetAttributes($filePathStr, $isAnimFile);
    
    $currentDir = $exportAttrs[$UnityFbxFilePathIndex];
    $fileName = $exportAttrs[$UnityFbxFileNameIndex];
    $currentAnimDir = $exportAttrs[$UnityFbxAnimFilePathIndex];
    $animFileName = $exportAttrs[$UnityFbxAnimFileNameIndex];
    $fileNameWithoutExt = $exportAttrs[$UnityFileNameWithoutExtIndex];
    
    $unityExportSet = getNewExportSetName($fileNameWithoutExt);

    string $origNamespace = `namespaceInfo -cur -an`;
    string $targetNamespace = getTargetNamespaceName($fileNameWithoutExt);
    
    // warn if namespace already exists
    if(`namespace -exists $targetNamespace`){
        if(!showConfirmDialog("Warning: " + $fileName,
            $targetNamespace + " namespace already exists, the imported objects will be added to the existing namespace and export set.",
            "Continue", "Cancel"
            )){
            // cancelled, don't import this fbx
            return;
        }
    }
    else{
        namespace -add $targetNamespace;
    }
    
    // Gather everything that is in the scene
    $origItemsInScene = `ls -tr -o -r true`;
        
    // Get or create the Unity Fbx Export Set
    $setCreated = getOrCreateExportSet($unityExportSet, $origNamespace);
    
    // unlock set so we can add attributes to it
    lockNode -lock false $unityExportSet;
    
    if(!$isAnimFile){
        // reset attribute values, in case import fails
        storeStringAttribute($unityExportSet, $UnityFbxFilePathAttr, "", "");
        storeStringAttribute($unityExportSet, $UnityFbxFileNameAttr, "", "");
    }

    if(`namespaceInfo -cur -an` != $targetNamespace){
        namespace -set $targetNamespace;
    }
    file -import -type "FBX" -ignoreVersion -ra true -mergeNamespacesOnClash true -pr -importFrameRate true -importTimeRange "override" $filePathStr;
    
    if(`namespaceInfo -cur -an` != $origNamespace){
        namespace -set $origNamespace;
    }
    
    setExportSetAttributes($unityExportSet, $isAnimFile, $setCreated, $exportAttrs, /*strip namespaces*/ true);
    
    if (setExists($unityExportSet) == true){
        // figure out what has been added after import
        $itemsInScene = `ls -tr -o -r true`;
        
        $newItems = stringArrayRemove($origItemsInScene, $itemsInScene);
        
        // add newly imported items to set
        if (size($newItems) > 0){
            sets -include $unityExportSet $newItems;
        }
    }
}


global proc int loadUnityDependencies(){
    // GamePipeline plugin 'SendToUnitySelection' command used in export
    $pluginsToLoad = {"GamePipeline", "fbxmaya"};
    
    $ext = "mll";
    if (`about -macOS` == true){
        $ext = "bundle";
    }
            
    // iterate over all the plugins, loading them with extenstion ext, and combining the results
    // to return if any of the loads failed
    $result = true;
    for($plugin in $pluginsToLoad){
        $result = $result && `loadUnityPlugin ($plugin + "." + $ext)`;
    }
    
    unityRemoveNativeMenuOnLoad();
    
    return $result;
}

global proc unityImport(){
    if(!loadUnityDependencies()){
        error("Failed to load Unity dependencies");
        return;
    }
    
    if(!loadUnityFbxImportSettings()){
        return;
    }
        
    $unityProject = `optionVar -q "UnityProject"`;
    
    $filePaths = `fileDialog2 -dialogStyle 2 -caption "FBX Import" -dir ($unityProject + "/Assets") -fileFilter "*.fbx" -selectFileFilter "FBX" -fileMode 4`;
    
    // store path and filename
    if(size($filePaths) <= 0){
        return;
    }
    for($i=0; $i<size($filePaths); ++$i){
        $filePathStr = $filePaths[$i];
        importFile($filePathStr);
    }
    
    // switch project if file imported from a different Unity project
    switchUnityProject($filePaths[0]);
}

// returns the intersection of two string arrays
proc string[] getIntersection(string $set1[], string $set2[]){
    string $myIntersector = `stringArrayIntersector`;
    
    stringArrayIntersector -edit -reset $myIntersector;
    stringArrayIntersector -edit -intersect $set1 $myIntersector;
    stringArrayIntersector -edit -intersect $set2 $myIntersector;
    
    string $intersection[] = `stringArrayIntersector -query $myIntersector`;
    
    // Delete the intersector
    deleteUI $myIntersector;
    
    return $intersection;
}

// Find the most common namespace among the selected objects. If there are multiple (because of nested namespaces),
// prefer the most specific. For example if you have:
//
// test1:test2:sphere
// test1:test3:cube
// test1:test2:cylinder
//
// test1 will be returned because all objects have that namespace in common. However if you have:
//
// test1:test2:sphere
// test1:test2:cube
// test1:test2:cylinder
//
// Then it will return test1:test2.
proc string getCommonNamespace(string $origSelection[]){
    // gather up all the unique namespaces
    string $selectedNamespaces[];
    for($i = 0; $i < size($origSelection); $i++){
        string $currNamespace = getObjectNamespace($origSelection[$i]);
        while ($currNamespace != ":" && !stringArrayContains($currNamespace, $selectedNamespaces)){
            $selectedNamespaces[size($selectedNamespaces)] = $currNamespace;
            $currNamespace = `namespaceInfo -p $currNamespace`;
            // make sure the namespace always starts with a colon
            if(!startsWith($currNamespace, ":")){
                $currNamespace = ":" + $currNamespace;
            }
        }
    }

    // go through selection to find common namespace to set as default
    string $commonNamespace = ":";
    int $maxNamespaceCount = 0;
    for($i = 0; $i < size($selectedNamespaces); $i++){
        $currNamespace = $selectedNamespaces[$i];
        // get contents of namespace
        string $namespaceContents[] = `namespaceInfo -ls $currNamespace -r`;
        string $intersection[] = getIntersection($origSelection, $namespaceContents);
        int $intersectionSize = size($intersection);
        if($intersectionSize > $maxNamespaceCount ||
            // prefer more specific namespaces
            ($maxNamespaceCount > 0 &&
             $intersectionSize == $maxNamespaceCount &&
             size($currNamespace) > size($commonNamespace)))
        {
            $commonNamespace = $currNamespace;
            $maxNamespaceCount = $intersectionSize;
        }
    }
    return $commonNamespace;
}

proc exportSet(string $unitySet, int $exportAnim){
    global string $UnityFbxFilePathAttr;
    global string $UnityFbxFileNameAttr;
    global string $UnityFbxAnimFilePathAttr;
    global string $UnityFbxAnimFileNameAttr;
    global string $UnityFbxStripNamespaceAttr;
    global string $UnityFbxNamespaceAttr;

    string $unitySetContents[] = `listConnections $unitySet`;
    int $stripNamespaces = getBoolAttribute($unitySet, $UnityFbxStripNamespaceAttr);
    string $namespaceToStrip = getAttribute($unitySet, $UnityFbxNamespaceAttr);

    // if there is no namespace manually set, find the common namespace
    if ($stripNamespaces){
        if ($namespaceToStrip == ""){
            $namespaceToStrip = getCommonNamespace($unitySetContents);
        }
        else {
            // make sure the namespace to strip is an absolute namespace
            if(!startsWith($namespaceToStrip, ":")){
                $namespaceToStrip = ":" + $namespaceToStrip;
            }
        }
    }
        
    string $animatedObjectSet = "";
    if($exportAnim){
        string $animCurveSelect[] = `ls -typ animCurve`;
        string $animatedTransforms[] = `listConnections -t transform $animCurveSelect`;
        
        string $setAnimatedTransforms[] = getIntersection($animatedTransforms, $unitySetContents);
        
        select -r $setAnimatedTransforms;
        $animatedObjectSet = `sets`;
        select -r -ne $animatedObjectSet;
    }
    else{
        select -r -ne $unitySet;
    }
    
    $pathAttr = $UnityFbxFilePathAttr;
    $nameAttr = $UnityFbxFileNameAttr;
    
    if($exportAnim){
        $pathAttr = $UnityFbxAnimFilePathAttr;
        $nameAttr = $UnityFbxAnimFileNameAttr;
    }
    
    string $unityFbxFilePath = getAttribute($unitySet, $pathAttr);
    string $unityFbxFileName = getAttribute($unitySet, $nameAttr);

    // make sure the file path exists
    if(!(`filetest -d $unityFbxFilePath`)){
        sysFile -makeDir $unityFbxFilePath;
    }

    $strCmd = "";
    if ($unityFbxFilePath != "" && $unityFbxFileName != ""){
        // export selected, relative to given namespace
        string $exportFormat = "file -force -options \"\" -typ \"FBX export\" -relativeNamespace \"^1s\" -es \"^2s/^3s\"";
        string $relativeNamespace = ":";
        if ($stripNamespaces){
            $relativeNamespace = $namespaceToStrip;
        }
        $strCmd = `format -s $relativeNamespace -s $unityFbxFilePath -s $unityFbxFileName $exportFormat`;
        eval $strCmd;
    }
    
    if(`objExists $animatedObjectSet`){
       delete $animatedObjectSet; 
    }
}

proc int isUnityExportSet(string $mayaSet){
    global string $UnityFbxFilePathAttr;
    global string $UnityFbxFileNameAttr;

    if(!endsWith($mayaSet, "_UnityExportSet")){
        return false;
    }
    
    if(!`attributeExists $UnityFbxFilePathAttr $mayaSet`){
        return false;
    }
    
    if(!`attributeExists $UnityFbxFileNameAttr $mayaSet`){
        return false;
    }
    return true;
}

proc string[] getUnityExportSets(){
    //if the selection set ends w "_UnityExportSet" and it has at least the custom attributes UnityFbxModelFilePath & UnityFbxModelFileName then it's one of ours.
    string $unityExportSets[];
    
    string $mayaSets[] = `ls -sets`;
    
    int $i = 0;
    for($k=0; $k<size($mayaSets); ++$k){
        if(isUnityExportSet($mayaSets[$k])){
            $unityExportSets[$i] = $mayaSets[$k];
            $i++;
        }
    }
    return $unityExportSets;
}

proc setupNewExportSet(
    string $modelPath,
    string $modelFilename,
    string $animPath,
    string $animFilename,
    int $stripNamespaces,
    string $selectedObjects[]){
    
    // make sure all necessary variables are set
    if ($modelFilename == "" && $animFilename == ""){
        error ("Unity FBX Export Set Creation: Missing filename for export.");
        return;
    }
    
    if ($modelPath == "" && $animPath == ""){
        error ("Unity FBX Export Set Creation: Missing filepath for export.");
        return;
    }
    
    if ($modelFilename == ""){
        if(match("@", basename($animFilename, ".fbx")) != ""){
            $modelFilename = match("[^@]+", $animFilename) + ".fbx";
        }
        else{
            $modelFilename = basename($animFilename, ".fbx") + "_modelOnly.fbx";
        }
    }

    if ($animFilename == ""){
        $animFilename = basename($modelFilename, ".fbx") + "@Take1.fbx";
    }

    if($modelPath == ""){
        $modelPath = $animPath;
    }
    else if($animPath == ""){
        $animPath = $modelPath;
    }

    string $exportFileNameWithoutExt = formValidObjectName(basename($modelFilename, ".fbx"));
    
    $unityExportSet = getNewExportSetName($exportFileNameWithoutExt);
    
    string $origNamespace = `namespaceInfo -cur -an`;
    
    // Get or create the Unity Fbx Export Set
    $setCreated = getOrCreateExportSet($unityExportSet, $origNamespace);

    if(!$setCreated){
        // warn user
        if(!showConfirmDialog("Warning",
            "Creating set will overwrite contents of " + $unityExportSet + " export set. To export selection + contents of existing set, first add selection to set.",
            "Continue", "Cancel"
                )){
                // cancelled, don't export this fbx
                print ("Cancelled set creation");
                return;
        }
    }
    
    global int $UnityFbxFilePathIndex;
    global int $UnityFbxFileNameIndex;
    global int $UnityFbxAnimFilePathIndex;
    global int $UnityFbxAnimFileNameIndex;
    global int $UnityFileNameWithoutExtIndex;
    
    // Get the export set attributes
    string $exportAttrs[5];
    $exportAttrs[$UnityFbxFilePathIndex] = $modelPath;
    $exportAttrs[$UnityFbxFileNameIndex] = $modelFilename;
    $exportAttrs[$UnityFbxAnimFilePathIndex] = $animPath;
    $exportAttrs[$UnityFbxAnimFileNameIndex] = $animFilename;
    $exportAttrs[$UnityFileNameWithoutExtIndex] = $exportFileNameWithoutExt;
    
    setExportSetAttributes($unityExportSet, /*isAnimOnly*/ false, $setCreated, $exportAttrs, $stripNamespaces);
    
    if (setExists($unityExportSet) == true){
        // clear contents of set
        sets -clear $unityExportSet;
        
        // add newly imported items to set
        if (size($selectedObjects) > 0){
            sets -include $unityExportSet $selectedObjects;
        }
    }
    
    // switch project if file exported to a different Unity project
    switchUnityProject($modelPath);
}

// ==== Functions for creating export set dialog ==========

global proc unityOnCreateExportSet(
    string $window,
    string $modelPathField,
    string $modelFileField,
    string $animPathField,
    string $animFileField,
    string $stripNamespaceCheckbox){
    
    $origSelection = `ls -sl`;
    if(size($origSelection) <= 0){
        // nothing selected
        error ("Unity FBX Export Set Creation: Nothing selected");
        return;
    }

    string $modelPath = "";
    string $modelFilename = "";
    if($modelPathField != 0){
        $modelPath = `textField -q -text $modelPathField`;
        $modelFilename = `textField -q -text $modelFileField`;
        if ($modelFilename != "" && !endsWith($modelFilename, ".fbx")){
            $modelFilename = $modelFilename + ".fbx";
        }
    }

    string $animPath = "";
    string $animFilename = "";
    if($animPathField != 0){
        $animPath = `textField -q -text $animPathField`;
        $animFilename = `textField -q -text $animFileField`;
        if ($animFilename != "" && !endsWith($animFilename, ".fbx")){
            $animFilename = $animFilename + ".fbx";
        }
    }

    // make sure all necessary variables are set
    if ($modelFilename == "" && $animFilename == ""){
        error ("Unity FBX Export Set Creation: Missing filename for export.");
        return;
    }
    
    if ($modelPath == "" && $animPath == ""){
        error ("Unity FBX Export Set Creation: Missing filepath for export.");
        return;
    }

    int $stripNamespaces = `checkBox -q -value $stripNamespaceCheckbox`;
    
    setupNewExportSet(
        $modelPath,
        $modelFilename,
        $animPath,
        $animFilename,
        $stripNamespaces,
        $origSelection);
    
    deleteUI -window $window;
}

global proc unityOpenFileDialog(string $textField)
{
    string $currentPath = `textField -q -text $textField`;
    
    string $exportPaths[] = `fileDialog2 -ds 2 -cap "FBX Export Selection" -dir $currentPath -fm 3`;
    if(size($exportPaths)<=0){
        return;
    }
    string $exportFilePath = $exportPaths[0];
    
    textField -e -text $exportFilePath $textField;
}

proc string createFilePathField(string $label, string $parent, int $labelSize, int $textFieldSize){
    rowLayout
        -numberOfColumns 3
        -columnWidth3 $labelSize $textFieldSize 50
        -columnAlign3 "right" "left" "left"
        -p $parent;
        
    string $unityProject = `optionVar -q "UnityProject"`;
    $unityProject = $unityProject + "/Assets";
    
    text -label $label;
    string $textField = `textField -width $textFieldSize -text $unityProject`;
    button -label "..." -recomputeSize false -height 15 -command ("unityOpenFileDialog " + $textField);
    
    return $textField;
}

proc string createTextFieldWithLabel(string $label, string $parent, int $labelSize, int $textFieldSize)
{
    rowLayout 
        -numberOfColumns 2 
        -columnWidth2 $labelSize $textFieldSize
        -columnAlign2 "right" "left"
        -p $parent;
    
    text -label $label;
    string $textField = `textField -width $textFieldSize`;
    return $textField;
}

proc string createCheckboxWithLabelLeft(string $label, string $parent, int $labelSize, int $fieldSize){
    rowLayout 
        -numberOfColumns 2 
        -columnWidth2 $labelSize $fieldSize
        -columnAlign2 "left" "left"
        -p $parent;
    
    text -label $label;
    return `checkBox -value true -label " "`;
}

proc createExportSetDialog(int $exportType){
    $origSelection = `ls -sl`;
    if(size($origSelection) <= 0){
        // nothing selected
        print ("Nothing selected");
        return;
    }

    $exportAnim = false;
    $exportAnimOnly = false;
    switch($exportType){
    case 0 /* export animation only */:
        $exportAnim = true;
        $exportAnimOnly = true;
        break;
    case 1 /* export model only */:
        break;
    default: /* export model + animation */
        $exportAnim = true;
        break;
    }

    // open up a dialog for choosing the export set options
    string $window = `window -title "Unity FBX Export Options" -iconName "Short Name" -widthHeight 500 250`;
    
    string $container = `formLayout -numberOfDivisions 100`;
    
    string $mainOptions = `columnLayout -adjustableColumn true -p $container`;

    // go through selection to find common namespace to set as default
    string $commonNamespace = getCommonNamespace($origSelection);
    
    string $modelFilename = "Untitled";
    // if one item selected, take the name of it as the filename
    if (size($origSelection) == 1){
        // take the name of the selection without the namespace
        string $nTokens[];
        int $nNumTokens = `tokenize ("" + $origSelection[0]) ":" $nTokens`;
        $modelFilename = $nTokens[$nNumTokens-1];
    }
    else{
        // if multi items selected, but one of them is the root, then take the name of the root as the filename
        for($i = 0; $i < size($origSelection); $i++){
            string $descendents[] = `listRelatives -type "transform" -allDescendents $origSelection[$i]`;
            string $intersection[] = getIntersection($origSelection, $descendents);
            if (size($intersection) == size($origSelection)-1){
                // take the name of the selection without the namespace
                string $nTokens[];
                int $nNumTokens = `tokenize ("" + $origSelection[$i]) ":" $nTokens`;
                $modelFilename = $nTokens[$nNumTokens-1];
                break;
            }
        }
    }

    int $labelSize = 150;
    int $textFieldSize = 300;
    
    string $modelFilePath = " 0 0";
    if(!$exportAnimOnly){
        string $modelFilePathField = createFilePathField("Model File Path", $mainOptions, $labelSize, $textFieldSize);
        string $modelFileNameField = createTextFieldWithLabel("Model File Name", $mainOptions, $labelSize, $textFieldSize);
        textField -e -text ($modelFilename + ".fbx") $modelFileNameField;
        $modelFilePath = " " + $modelFilePathField + " " + $modelFileNameField;
    }
    
    string $animFilePath = " 0 0";
    if($exportAnim){
        string $animFilePathField = createFilePathField("Anim File Path", $mainOptions, $labelSize, $textFieldSize);
        string $animFileNameField = createTextFieldWithLabel("Anim File Name", $mainOptions, $labelSize, $textFieldSize);
        textField -e -text ($modelFilename + "@Take1.fbx") $animFileNameField;
        $animFilePath = " " + $animFilePathField + " " + $animFileNameField;
    }

    string $stripNamespaceCheckbox = createCheckboxWithLabelLeft("Strip Namespaces on Export", $mainOptions, $labelSize, $textFieldSize);
    
    int $buttonWidth = 166;
    string $buttons = `rowLayout
          -numberOfColumns 3
          -adjustableColumn3 1
          -columnWidth3 $buttonWidth $buttonWidth $buttonWidth
          -columnAlign3 "center" "center" "center" -p $container`;

    string $createExportSetCommand = "unityOnCreateExportSet " + $window + " " + $modelFilePath + $animFilePath + " " + $stripNamespaceCheckbox;
          
    button -label "Create Set and Export"
        -width $buttonWidth
        -command ($createExportSetCommand + ";" + "unityExportModelAnim()")
        -p $buttons;
    button -label "Create Set" 
        -width $buttonWidth
        -command ($createExportSetCommand)
        -p $buttons;
    button -label "Cancel"
        -width $buttonWidth
        -command ("deleteUI -window " + $window)
        -p $buttons;
    
    formLayout -edit 
        -attachForm $buttons "bottom" 1
        -attachForm $buttons "left" 1
        -attachPosition $buttons "right" 1 99
        -attachForm $mainOptions "left" 10
        -attachForm $mainOptions "top" 10
    $container;
     
    setParent ..;
    showWindow $window;
}
// =========================================

proc unityExport(int $exportType){
    
    if(!loadUnityDependencies()){
        return;
    }
    
    if(!loadUnityFbxExportSettings()){
        return;
    }
    
    $exportAnim = false;
    $exportAnimOnly = false;
    switch($exportType){
    case 0 /* export animation only */:
        $exportAnim = true;
        $exportAnimOnly = true;
        break;
    case 1 /* export model only */:
        break;
    default: /* export model + animation */
        $exportAnim = true;
        break;
    }
    FBXProperty "Export|IncludeGrp|Animation" -v $exportAnim;
    FBXExportAnimationOnly -v $exportAnimOnly;
    
    $origSelection = `ls -sl`;
    if(size($origSelection) <= 0){
        // nothing selected
        return;
    }
    
    $i = 0;
    string $setsToExport[];
    string $unityExportSets[] = getUnityExportSets();
    for($exportSet in $unityExportSets){
        if(!setExists($exportSet)){
            continue;
        }
        
        // TODO (UNI-39197) move functionality to separate mel file
        // check if the selection intersects with this export set
        string $exportSetContents[] = `listConnections $exportSet`; 
        string $intersection[] = getIntersection($origSelection, $exportSetContents);
        
        if(size($intersection) > 0 ||
           stringArrayContains($exportSet, $origSelection)){
            
            $setsToExport[$i] = $exportSet;
            $i++;
        }
    }
    
    // if selection doesn't belong to a set, export to a new file
    if(size($setsToExport) <= 0){
        createExportSetDialog($exportType);
        return;
    }
    
    for($unitySet in $setsToExport){
        print ("exporting set: " + $unitySet);
        exportSet($unitySet, $exportAnimOnly);
    }
    
    select -cl;
    if (size($origSelection) > 0){    
        select -add -ne $origSelection;
    }
}

global proc unityExportAnim(){
    global int $UnityExportAnim;
    unityExport($UnityExportAnim);
}

global proc unityExportModel(){
    global int $UnityExportModel;
    unityExport($UnityExportModel);
}

global proc unityExportModelAnim(){
    global int $UnityExportModelAnim;
    unityExport($UnityExportModelAnim);
}

global proc unityCreateExportSet(){
    global int $UnityExportModelAnim;
    createExportSetDialog($UnityExportModelAnim);
}
