#include <maya/MDagPath.h>
#include <maya/MDagPathArray.h>
#include <maya/MFileIO.h>
#include <maya/MFileObject.h>
#include <maya/MFnAttribute.h>
#include <maya/MFnCompoundAttribute.h>
#include <maya/MFnDagNode.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MFnPlugin.h>
#include <maya/MGlobal.h>
#include <maya/MItDag.h>
#include <maya/MItDependencyNodes.h>
#include <maya/MObjectArray.h>
#include <maya/MPlug.h>
#include <maya/MPlugArray.h>
#include <maya/MPxFileTranslator.h>
#include <maya/MString.h>
#include <maya/MStringArray.h>
#include <ctype.h>
#include <maya/MFStream.h>
#include <time.h>
class maTranslator : public MPxFileTranslator
{
public:
        bool            haveReadMethod() const;
        bool            haveWriteMethod() const;
        MString         defaultExtension() const;
        MFileKind       identifyFile(
                                        const MFileObject& file,
                                        const char* buffer,
                                        short size
                                ) const;
        MStatus         reader(
                                        const MFileObject& file,
                                        const MString& options,
                                        FileAccessMode mode
                                );
        MStatus         writer(
                                        const MFileObject& file,
                                        const MString& options,
                                        FileAccessMode mode
                                );
        static void*    creator();
        static void             setPluginName(const MString& name);
        static MString  translatorName();
protected:
        void    getAddAttrCmds(const MObject& node, MStringArray& cmds);
        void    getSetAttrCmds(const MObject& node, MStringArray& cmds);
        void    writeBrokenRefConnections(fstream& f);
        void    writeConnections(fstream& f);
        void    writeCreateNode(fstream& f, const MObject& node);
        void    writeCreateNode(
                                fstream& f, const MDagPath& nodePath, const MDagPath& parentPath
                        );
        void    writeDagNodes(fstream& f);
        void    writeDefaultNodes(fstream& f);
        void    writeFileInfo(fstream& f);
        void    writeFooter(fstream& f, const MString& fileName);
        void    writeHeader(fstream& f, const MString& fileName);
        void    writeInstances(fstream& f);
        void    writeLockNode(fstream& f, const MObject& node);
        void    writeNodeAttrs(fstream& f, const MObject& node, bool isSelected);
        void    writeNodeConnections(fstream& f, const MObject& node);
        void    writeNonDagNodes(fstream& f);
        void    writeParent(
                                fstream& f,
                                const MDagPath& parent,
                                const MDagPath& child,
                                bool addIt
                        );
        void    writePlugSizeHint(fstream& f, const MPlug& plug);
        void    writeReferences(fstream& f);
        void    writeReferenceNodes(fstream& f);
        void    writeRefNodeParenting(fstream& f);
        void    writeRequirements(fstream& f);
        void    writeSelectNode(fstream& f, const MObject& node);
        void    writeUnits(fstream& f);
        static MString  comment(const MString& text);
        static MString  quote(const MString& text);
        static MString  fExtension;
        static MString  fFileVersion;
        static MString  fPluginName;
        static MString  fTranslatorName;
private:
        
        
        
        
        MPlugArray              fBrokenConnSrcs;
        MPlugArray              fBrokenConnDests;
        
        
        
        MObjectArray    fDefaultNodes;
        
        
        
        
        
        MDagPathArray   fInstanceChildren;
        MDagPathArray   fInstanceParents;
        
        
        
        
        
        MDagPathArray   fParentingRequired;
        
        
        
        
        unsigned int    fAttrFlag;
        unsigned int    fCreateFlag;
        unsigned int    fConnectionFlag;
};
MString maTranslator::fFileVersion = "4.5ff01";
MString maTranslator::fExtension = "pma";
MString maTranslator::fPluginName = "";
MString maTranslator::fTranslatorName = "Maya ASCII (via plugin)";
inline MString maTranslator::defaultExtension() const
{       return fExtension;              }
inline bool maTranslator::haveReadMethod() const
{       return false;                   }
inline bool maTranslator::haveWriteMethod() const
{       return true;                    }
inline void maTranslator::setPluginName(const MString& name)
{       fPluginName = name;             }
inline MString maTranslator::translatorName()
{       return fTranslatorName; }
void* maTranslator::creator()
{
        return new maTranslator();
}
MPxFileTranslator::MFileKind maTranslator::identifyFile(
                const MFileObject& file, const char* buffer, short bufferLen
) const
{
        MString tagStr = comment(fTranslatorName);
        int             tagLen = tagStr.length();
        
        
        
        
        
        if (bufferLen >= tagLen)
        {
                MString initialContents(buffer, bufferLen);
                MStringArray    initialLines;
                initialContents.split('\n', initialLines);
                if (initialLines.length() > 0)
                {
                        if (((int)initialLines[0].length() >= tagLen)
                        &&      (initialLines[0].substring(0, tagLen-1) == tagStr))
                        {
                                return kIsMyFileType;
                        }
                }
        }
        else
        {
                MString fileName(file.name());
                int             fileNameLen = fileName.length();
                int             startOfExtension = fileName.rindex('.') + 1;
                if ((startOfExtension > 0)
                &&      (startOfExtension < fileNameLen)
                &&      (fileName.substring(startOfExtension, fileNameLen) == fExtension))
                {
                        return kIsMyFileType;
                }
        }
        return kNotMyFileType;
}
MStatus maTranslator::writer(
                const MFileObject& file,
                const MString& ,
                MPxFileTranslator::FileAccessMode mode
)
{
        
        
        
        if ((mode != kSaveAccessMode) && (mode != kExportAccessMode))
                return MS::kNotImplemented;
        
        
        
        fstream output(file.fullName().asChar(), ios::out | ios::trunc);
        if (!output.good()) return MS::kNotFound;
        
        
        
        
        MStatus status;
        fCreateFlag = MFnDependencyNode::allocateFlag(fPluginName, &status);
        if (status)
                fAttrFlag = MFnDependencyNode::allocateFlag(fPluginName, &status);
        if (status)
                fConnectionFlag = MFnDependencyNode::allocateFlag(fPluginName, &status);
        if (!status)
        {
                MGlobal::displayError(
                        "Could not allocate three free node flags."
                        "  Try unloading some other plugins."
                );
                return MS::kFailure;
        }
        
        
        
        MItDependencyNodes      nodesIter;
        for (; !nodesIter.isDone(); nodesIter.next())
        {
                MObject                         node = nodesIter.item();
                MFnDependencyNode       nodeFn(node);
                nodeFn.setFlag(fCreateFlag, false);
                nodeFn.setFlag(fAttrFlag, false);
                nodeFn.setFlag(fConnectionFlag, false);
        }
        
        
        
        writeHeader(output, file.name());
        writeFileInfo(output);
        writeReferences(output);
        writeRequirements(output);
        writeUnits(output);
        writeDagNodes(output);
        writeNonDagNodes(output);
        writeDefaultNodes(output);
        writeReferenceNodes(output);
        writeConnections(output);
        writeFooter(output, file.name());
        output.close();
        MFnDependencyNode::deallocateFlag(fPluginName, fCreateFlag);
        return MS::kSuccess;
}
void maTranslator::writeHeader(fstream& f, const MString& fileName)
{
        
        
        
        
        time_t          tempTime = time(NULL);
        struct tm*      curTime = localtime(&tempTime);
        char            formattedTime[100];
        strftime(
                formattedTime, sizeof(formattedTime), "%a, %b %e, %Y %r", curTime
        );
        
        
        
        f << comment(fTranslatorName).asChar() << " "
                << fFileVersion.asChar() << " scene" << endl;
        f << comment("Name: ").asChar() << fileName.asChar() << endl;
        f << comment("Last modified: ").asChar() << formattedTime << endl;
}
void maTranslator::writeFileInfo(fstream& f)
{
        
        
        
        
        MStringArray    fileInfo;
        if (MGlobal::executeCommand("fileInfo -q", fileInfo))
        {
                unsigned        numEntries = fileInfo.length();
                unsigned        i;
                for (i = 0; i < numEntries; i += 2)
                {
                        f << "fileInfo " << quote(fileInfo[i]).asChar() << " "
                                        << quote(fileInfo[i+1]).asChar() << ";" << endl;
                }
        }
        else
                MGlobal::displayWarning("Could not get scene's fileInfo.");
}
void maTranslator::writeReferences(fstream& f)
{
        MStringArray    files;
        MFileIO::getReferences(files);
        unsigned        numRefs = files.length();
        unsigned        i;
        for (i = 0; i < numRefs; i++)
        {
                MString refCmd = "file -r";
                MString fileName = files[i];
                MString nsName = "";
                
                
                
                
                MString tempCmd = "file -q -ns \"";
                tempCmd += fileName + "\"";
                if (MGlobal::executeCommand(tempCmd, nsName))
                {
                        refCmd += " -ns \"";
                        refCmd += nsName + "\"";
                }
                else
                        MGlobal::displayWarning("Could not get namespace name.");
                
                
                
                tempCmd = "file -q -dr \"";
                tempCmd += fileName + "\"";
                int     isDeferred;
                if (MGlobal::executeCommand(tempCmd, isDeferred))
                {
                        if (isDeferred) refCmd += " -dr 1";
                }
                else
                        MGlobal::displayWarning("Could not get deferred reference info.");
                
                
                
                tempCmd = "file -q -rfn \"";
                tempCmd += fileName + "\"";
                MString refNode;
                if (MGlobal::executeCommand(tempCmd, refNode))
                {
                        if (refNode.length() > 0)
                        {
                                refCmd += " -rfn \"";
                                refCmd += refNode + "\"";
                        }
                }
                else
                        MGlobal::displayInfo("Could not query reference node name.");
                
                
                
                f << refCmd.asChar() << " \"" << fileName.asChar() << "\";" << endl;
        }
}
void maTranslator::writeRequirements(fstream& f)
{
        
        
        
        f << "requires maya \"" << fFileVersion.asChar() << "\";" << endl;
        
        
        
        MStringArray    pluginsUsed;
        if (MGlobal::executeCommand("pluginInfo -q -pluginsInUse", pluginsUsed))
        {
                unsigned        numPlugins = pluginsUsed.length();
                unsigned        i;
                for (i = 0; i < numPlugins; i += 2)
                {
                        f << "requires " << quote(pluginsUsed[i]).asChar() << " "
                                        << quote(pluginsUsed[i+1]).asChar() << ";" << endl;
                }
        }
        else
        {
                MGlobal::displayWarning(
                        "Could not get list of plugins currently in use."
                );
        }
}
void maTranslator::writeUnits(fstream& f)
{
        MString args = "";
        MString result;
        
        
        
        if (MGlobal::executeCommand("currentUnit -q -fullName -linear", result))
                args += " -l " + result;
        else
                MGlobal::displayWarning("Could not get current linear units.");
        
        
        
        if (MGlobal::executeCommand("currentUnit -q -fullName -angle", result))
                args += " -a " + result;
        else
                MGlobal::displayWarning("Could not get current linear units.");
        
        
        
        if (MGlobal::executeCommand("currentUnit -q -fullName -time", result))
                args += " -t " + result;
        else
                MGlobal::displayWarning("Could not get current linear units.");
        if (args != "")
        {
                f << "currentUnit" << args.asChar() << ";" << endl;
        }
}
void maTranslator::writeDagNodes(fstream& f)
{
        fParentingRequired.clear();
        MItDag          dagIter;
        dagIter.traverseUnderWorld(true);
        MDagPath        worldPath;
        dagIter.getPath(worldPath);
        
        
        
        
        for (dagIter.next(); !dagIter.isDone(); dagIter.next())
        {
                MDagPath        path;
                dagIter.getPath(path);
                
                
                
                
                
                MFnDagNode      dagNodeFn(path);
                if (dagNodeFn.isFlagSet(fCreateFlag))
                {
                        dagIter.prune();
                        continue;
                }
                
                
                
                
                if (dagNodeFn.isDefaultNode()) continue;
                
                
                
                
                if (!dagNodeFn.canBeWritten() && !dagNodeFn.isShared())
                {
                        dagNodeFn.setFlag(fCreateFlag, true);
                        continue;
                }
                unsigned int    numParents = dagNodeFn.parentCount();
                if (dagNodeFn.isFromReferencedFile())
                {
                        
                        
                        
                        
                        
                        
                        unsigned int i;
                        for (i = 0; i < numParents; i++)
                        {
                                MObject         altParent = dagNodeFn.parent(i);
                                MFnDagNode      altParentFn(altParent);
                                if (!altParentFn.isFromReferencedFile()
                                &&      (altParentFn.object() != worldPath.node()))
                                {
                                        fParentingRequired.append(path);
                                        break;
                                }
                        }
                }
                else
                {
                        
                        
                        
                        MDagPath        parentPath = worldPath;
                        if (path.length() > 1)
                        {
                                
                                
                                
                                parentPath = path;
                                parentPath.pop();
                                
                                
                                
                                
                                if (parentPath.pathCount() > 1)
                                {
                                        
                                        
                                        
                                        
                                        
                                        
                                        path.getPath(parentPath, 0);
                                }
                        }
                        MFnDagNode      parentNodeFn(parentPath);
                        if (parentNodeFn.isFromReferencedFile())
                        {
                                
                                
                                
                                
                                
                                
                                
                                unsigned i;
                                for (i = 0; i < numParents; i++)
                                {
                                        if (dagNodeFn.parent(i) != parentNodeFn.object())
                                        {
                                                MObject         altParent = dagNodeFn.parent(i);
                                                MFnDagNode      altParentFn(altParent);
                                                if (!altParentFn.isFromReferencedFile()
                                                &&      !altParentFn.isFlagSet(fCreateFlag))
                                                {
                                                        break;
                                                }
                                        }
                                }
                                if (i < numParents) continue;
                                
                                
                                
                                
                                
                                writeCreateNode(f, path, worldPath);
                                fParentingRequired.append(path);
                        }
                        else
                        {
                                writeCreateNode(f, path, parentPath);
                                
                                
                                
                                
                                
                                unsigned        int i;
                                bool            hasRefParents = false;
                                bool            hasOtherNonRefParents = false;
                                for (i = 0; i < numParents; i++)
                                {
                                        if (dagNodeFn.parent(i) != parentNodeFn.object())
                                        {
                                                MObject         altParent = dagNodeFn.parent(i);
                                                MFnDagNode      altParentFn(altParent);
                                                if (altParentFn.isFromReferencedFile())
                                                        hasRefParents = true;
                                                else
                                                        hasOtherNonRefParents = true;
                                                
                                                
                                                
                                                
                                                if (hasRefParents && hasOtherNonRefParents) break;
                                        }
                                }
                                
                                
                                
                                
                                
                                if (hasRefParents) fParentingRequired.append(path);
                                
                                
                                
                                
                                
                                if (hasOtherNonRefParents)
                                {
                                        fInstanceChildren.append(path);
                                        fInstanceParents.append(parentPath);
                                }
                        }
                        
                        
                        
                        
                        writeNodeAttrs(f, path.node(), true);
                        writeLockNode(f, path.node());
                }
                
                
                
                dagNodeFn.setFlag(fCreateFlag, true);
        }
        
        
        
        writeInstances(f);
}
void maTranslator::writeInstances(fstream& f)
{
        unsigned int numInstancedNodes = fInstanceChildren.length();
        unsigned int i;
        for (i = 0; i < numInstancedNodes; i++)
        {
                MFnDagNode      nodeFn(fInstanceChildren[i]);
                unsigned int numParents = nodeFn.parentCount();
                unsigned int p;
                for (p = 0; p < numParents; p++)
                {
                        
                        
                        
                        
                        if (nodeFn.parent(i) != fInstanceParents[i].node())
                        {
                                MObject         parent = nodeFn.parent(i);
                                MFnDagNode      parentFn(parent);
                                if (!parentFn.isFromReferencedFile())
                                {
                                        
                                        
                                        
                                        MDagPath        parentPath;
                                        MDagPath::getAPathTo(parentFn.object(), parentPath);
                                        writeParent(f, parentPath, fInstanceChildren[i], true);
                                }
                        }
                }
        }
        
        
        
        fInstanceChildren.clear();
        fInstanceParents.clear();
}
void maTranslator::writeParent(
                fstream& f, const MDagPath& parent, const MDagPath& child, bool addIt
)
{
        f << "parent -s -nc -r ";
 
        
        
        
        
        if (addIt) f << "-a ";
        
        
        
        if (parent.length() == 0) f << "-w ";
        f << "\"" << child.partialPathName().asChar() << "\"";
        
        
        
        if (parent.length() != 0)
                f << " \"" << parent.partialPathName().asChar() << "\"";
        f << ";" << endl;
}
void maTranslator::writeNonDagNodes(fstream& f)
{
        MItDependencyNodes      nodeIter;
        for (; !nodeIter.isDone(); nodeIter.next())
        {
                MObject                         node = nodeIter.item();
                MFnDependencyNode       nodeFn(node);
                
                
                
                if (nodeFn.isDefaultNode())
                {
                        fDefaultNodes.append(node);
                }
                else if (!nodeFn.isFromReferencedFile()
                &&      !nodeFn.isFlagSet(fCreateFlag))
                {
                        
                        
                        
                        
                        
                        if (nodeFn.canBeWritten() || nodeFn.isShared())
                        {
                                writeCreateNode(f, node);
                                writeNodeAttrs(f, node, true);
                                writeLockNode(f, node);
                        }
                        nodeFn.setFlag(fCreateFlag, true);
                        nodeFn.setFlag(fAttrFlag, true);
                }
        }
}
void maTranslator::writeDefaultNodes(fstream& f)
{
        
        
        
        
        unsigned int    numNodes = fDefaultNodes.length();
        unsigned int    i;
        for (i = 0; i < numNodes; i++)
        {
                writeNodeAttrs(f, fDefaultNodes[i], false);
                MFnDependencyNode       nodeFn(fDefaultNodes[i]);
                nodeFn.setFlag(fAttrFlag, true);
        }
}
void maTranslator::writeNodeAttrs(
                fstream& f, const MObject& node, bool isSelected
)
{
        MFnDependencyNode       nodeFn(node);
        if (nodeFn.canBeWritten())
        {
                MStringArray    addAttrCmds;
                MStringArray    setAttrCmds;
                getAddAttrCmds(node, addAttrCmds);
                getSetAttrCmds(node, setAttrCmds);
                unsigned int    numAddAttrCmds = addAttrCmds.length();
                unsigned int    numSetAttrCmds = setAttrCmds.length();
                if (numAddAttrCmds + numSetAttrCmds > 0)
                {
                        
                        
                        
                        
                        if (!isSelected) writeSelectNode(f, node);
                        unsigned int i;
                        for (i = 0; i < numAddAttrCmds; i++)
                                f << addAttrCmds[i].asChar() << endl;
                        for (i = 0; i < numSetAttrCmds; i++)
                                f << setAttrCmds[i].asChar() << endl;
                }
        }
}
void maTranslator::writeReferenceNodes(fstream& f)
{
        
        
        
        
        
        
        writeRefNodeParenting(f);
        
        
        
        MItDag  dagIter;
        for (dagIter.next(); !dagIter.isDone(); dagIter.next())
        {
                MObject                         node = dagIter.item();
                MFnDependencyNode       nodeFn(node);
                if (nodeFn.isFromReferencedFile()
                &&      !nodeFn.isFlagSet(fAttrFlag))
                {
                        writeNodeAttrs(f, node, false);
                        
                        
                        
                        
                        MFileIO::getReferenceConnectionsBroken(
                                node, fBrokenConnSrcs, fBrokenConnDests, true, true
                        );
                        nodeFn.setFlag(fAttrFlag, true);
                }
        }
        
        
        
        MItDependencyNodes      nodeIter;
        for (; !nodeIter.isDone(); nodeIter.next())
        {
                MObject                         node = nodeIter.item();
                MFnDependencyNode       nodeFn(node);
                if (nodeFn.isFromReferencedFile()
                &&      !nodeFn.isFlagSet(fAttrFlag))
                {
                        writeNodeAttrs(f, node, false);
                        
                        
                        
                        
                        MFileIO::getReferenceConnectionsBroken(
                                node, fBrokenConnSrcs, fBrokenConnDests, true, true
                        );
                        nodeFn.setFlag(fAttrFlag, true);
                }
        }
}
void maTranslator::writeConnections(fstream& f)
{
        
        
        
        
        
        writeBrokenRefConnections(f);
        
        
        
        
        
        
        
        
        
        
        
        
        
        MItDag  dagIter;
        dagIter.traverseUnderWorld(true);
        for (dagIter.next(); !dagIter.isDone(); dagIter.next())
        {
                MObject         node = dagIter.item();
                MFnDagNode      dagNodeFn(node);
                if (!dagNodeFn.isFlagSet(fConnectionFlag)
                &&      dagNodeFn.canBeWritten()
                &&      !dagNodeFn.isDefaultNode())
                {
                        writeNodeConnections(f, dagIter.item());
                        dagNodeFn.setFlag(fConnectionFlag, true);
                }
        }
        
        
        
        MItDependencyNodes      nodeIter;
        for (; !nodeIter.isDone(); nodeIter.next())
        {
                MFnDependencyNode       nodeFn(nodeIter.item());
                if (!nodeFn.isFlagSet(fConnectionFlag)
                &&      nodeFn.canBeWritten()
                &&      !nodeFn.isDefaultNode())
                {
                        writeNodeConnections(f, nodeIter.item());
                        nodeFn.setFlag(fConnectionFlag, true);
                }
        }
        
        
        
        unsigned int    numNodes = fDefaultNodes.length();
        unsigned int    i;
        for (i = 0; i < numNodes; i++)
        {
                MFnDependencyNode       nodeFn(fDefaultNodes[i]);
                if (!nodeFn.isFlagSet(fConnectionFlag)
                &&      nodeFn.canBeWritten()
                &&      nodeFn.isDefaultNode())
                {
                        writeNodeConnections(f, fDefaultNodes[i]);
                        nodeFn.setFlag(fConnectionFlag, true);
                }
        }
}
void maTranslator::writeBrokenRefConnections(fstream& f)
{
        unsigned int    numBrokenConnections = fBrokenConnSrcs.length();
        unsigned int    i;
        for (i = 0; i < numBrokenConnections; i++)
        {
                f << "disconnectAttr \""
                  << fBrokenConnSrcs[i].partialName(true).asChar()
                  << "\" \""
                  << fBrokenConnDests[i].partialName(true).asChar()
                  << "\"";
                
                
                
                
                
                MObject                 attr = fBrokenConnDests[i].attribute();
                MFnAttribute    attrFn(attr);
                if (!attrFn.indexMatters()) f << " -na";
                f << ";" << endl;
        }
}
void maTranslator::writeNodeConnections(fstream& f, const MObject& node)
{
        MFnDependencyNode       nodeFn(node);
        MPlugArray                      plugs;
        nodeFn.getConnections(plugs);
        unsigned int            numBrokenConns = fBrokenConnSrcs.length();
        unsigned int            numPlugs = plugs.length();
        unsigned int            i;
        for (i = 0; i < numPlugs; i++)
        {
                
                
                
                MPlug           destPlug = plugs[i];
                MPlugArray      srcPlug;
                destPlug.connectedTo(srcPlug, true, false);
                if (srcPlug.length() > 0)
                {
                        MObject                         srcNode = srcPlug[0].node();
                        MFnDependencyNode       srcNodeFn(srcNode);
                        
                        
                        
                        if (!srcNodeFn.canBeWritten()) continue;
                        
                        
                        
                        if (destPlug.isFromReferencedFile()) continue;
                        
                        
                        
                        if (destPlug.isProcedural()) continue;
                        
                        
                        
                        
                        if (srcNodeFn.isDefaultNode() && nodeFn.isShared()) continue;
                        f << "connectAttr \"";
                        
                        
                        
                        if (srcNodeFn.isDefaultNode()) f << ":";
                        f << srcPlug[0].partialName(true).asChar()
                          << "\" \"";
                        if (nodeFn.isDefaultNode()) f << ":";
                        f << destPlug.partialName(true).asChar()
                          << "\"";
                        
                        
                        
                        
                        
                        
                        if (srcNodeFn.isFromReferencedFile())
                        {
                                unsigned int j;
                                for (j = 0; j < numBrokenConns; j++)
                                {
                                        if (fBrokenConnSrcs[j] == srcPlug[0])
                                        {
                                                f << " -rd \""
                                                  << fBrokenConnDests[j].partialName(true).asChar()
                                                  << "\"";
                                                break;
                                        }
                                }
                        }
                        
                        
                        
                        
                        if (destPlug.isLocked()) f << " -l on";
                        
                        
                        
                        
                        
                        MObject                 attr = destPlug.attribute();
                        MFnAttribute    attrFn(attr);
                        if (!attrFn.indexMatters()) f << " -na";
                        f << ";" << endl;
                }
        }
}
void maTranslator::writeCreateNode(
                fstream& f, const MDagPath& nodePath, const MDagPath& parentPath
)
{
        MObject         node(nodePath.node());
        MFnDagNode      nodeFn(node);
        
        
        
        f << "createNode " << nodeFn.typeName().asChar();
        
        
        
        if (nodeFn.isShared()) f << " -s";
        f << " -n \"" << nodeFn.name().asChar() << "\"";
        
        
        
        
        if (parentPath.length() > 0)
                f << " -p \"" << parentPath.partialPathName().asChar() << "\"";
   
        f << ";" << endl;
}
void maTranslator::writeCreateNode(fstream& f, const MObject& node)
{
        MFnDependencyNode       nodeFn(node);
        
        
        
        f << "createNode " << nodeFn.typeName().asChar();
        
        
        
        if (nodeFn.isShared()) f << " -s";
        f << " -n \"" << nodeFn.name().asChar() << "\";" << endl;
}
void maTranslator::writeLockNode(fstream& f, const MObject& node)
{
        MFnDependencyNode       nodeFn(node);
        
        
        
        
        if (nodeFn.isLocked()) f << "lockNode;" << endl;
}
void maTranslator::writeSelectNode(fstream& f, const MObject& node)
{
        MStatus                         status;
        MFnDependencyNode       nodeFn(node);
        MString                         nodeName;
        
        
        
        
        
        if (nodeFn.hasUniqueName())
                nodeName = nodeFn.name();
        else
        {
                
                
                
                MFnDagNode      dagNodeFn(node, &status);
                if (!status)
                {
                        MGlobal::displayWarning(
                                MString("Node '") + nodeFn.name()
                                + "' has a non-unique name but claimes to not be a DAG node.\n"
                                + "Using non-unique name."
                        );
                        nodeName = nodeFn.name();
                }
                else
                        nodeName = dagNodeFn.partialPathName();
        }
        
        
        
        
        f << "select -ne ";
        
        
        
        if (nodeFn.isDefaultNode()) f << ":";
        f << nodeName.asChar() << ";\n";
}
void maTranslator::writeRefNodeParenting(fstream& f)
{
        unsigned int numNodes = fParentingRequired.length();
        unsigned int i;
        for (i = 0; i < numNodes; i++)
        {
                MFnDagNode      nodeFn(fParentingRequired[i]);
                
                
                
                
                bool                    hasRefParents = false;
                bool                    hasNonRefParents = false;
                unsigned int    numParents = nodeFn.parentCount();
                unsigned int    p;
                for (p = 0; p < numParents; p++)
                {
                        MObject         parent = nodeFn.parent(p);
                        MFnDagNode      parentFn(parent);
                        if (parentFn.isFromReferencedFile())
                                hasRefParents = true;
                        else
                                hasNonRefParents = true;
                        if (hasRefParents && hasNonRefParents) break;
                }
                
                
                
                
                
                
                
                
                bool    alreadyHasFirstParent =
                        (nodeFn.isFromReferencedFile() ? hasRefParents : hasNonRefParents);
                
                
                
                
                for (p = 0; p < numParents; p++)
                {
                        MObject         parent = nodeFn.parent(p);
                        MFnDagNode      parentFn(parent);
                        if (parentFn.isFromReferencedFile() != nodeFn.isFromReferencedFile())
                        {
                                
                                
                                
                                MDagPath        parentPath;
                                MDagPath::getAPathTo(parentFn.object(), parentPath);
                                writeParent(
                                        f, parentPath, fParentingRequired[i], alreadyHasFirstParent
                                );
                                
                                
                                
                                alreadyHasFirstParent = true;
                        }
                }
        }
}
void maTranslator::writeFooter(fstream& f, const MString& fileName)
{
        f << comment(" End of ").asChar() << fileName.asChar() << endl;
}
void maTranslator::getAddAttrCmds(const MObject& node, MStringArray& cmds)
{
        
        
        
        MFnDependencyNode       nodeFn(node);
        unsigned int            numAttrs = nodeFn.attributeCount();
        unsigned int            i;
        for (i = 0; i < numAttrs; i++)
        {
                
                
                
                MObject attr = nodeFn.reorderedAttribute(i);
                
                
                
                
                if (nodeFn.isNewAttribute(attr))
                {
                        MFnAttribute    attrFn(attr);
                        
                        
                        
                        
                        MStatus status;
                        attrFn.parent(&status);
                        if (status == MS::kNotFound)
                        {
                                
                                
                                
                                
                                MFnCompoundAttribute    cAttrFn(attr, &status);
                                if (status)
                                {
                                        MStringArray    newCmds;
                                        cAttrFn.getAddAttrCmds(newCmds);
                                        unsigned int    numCommands = newCmds.length();
                                        unsigned int    c;
                                        for (c = 0; c < numCommands; c++)
                                        {
                                                if (newCmds[c] != "")
                                                        cmds.append(newCmds[c]);
                                        }
                                }
                                else
                                {
                                        MString newCmd = attrFn.getAddAttrCmd();
                                        if (newCmd != "") cmds.append(newCmd);
                                }
                        }
                }
        }
}
void maTranslator::getSetAttrCmds(const MObject& node, MStringArray& cmds)
{
        
        
        
        cmds.clear();
        
        
        
        MFnDependencyNode       nodeFn(node);
        unsigned int            numAttrs = nodeFn.attributeCount();
        unsigned int            i;
        for (i = 0; i < numAttrs; i++)
        {
                
                
                
                MObject                 attr = nodeFn.reorderedAttribute(i);
                MFnAttribute    attrFn(attr);
                MStatus                 status;
                attrFn.parent(&status);
                bool                    isChild = (status != MS::kNotFound);
                
                
                
                
                
                
                if (!isChild && attrFn.isStorable() && attrFn.isWritable())
                {
                        
                        
                        
                        MPlug   plug(node, attr);
                        
                        
                        
                        
                        MStringArray    newCmds;
                        plug.getSetAttrCmds(newCmds, MPlug::kChanged, false);
                        unsigned int    numCommands = newCmds.length();
                        unsigned int    c;
                        for (c = 0; c < numCommands; c++)
                        {
                                if (newCmds[c] != "")
                                        cmds.append(newCmds[c]);
                        }
                }
        }
}
MStatus maTranslator::reader(
                const MFileObject& ,
                const MString& ,
                MPxFileTranslator::FileAccessMode 
)
{
        return MS::kNotImplemented;
}
MString maTranslator::comment(const MString& text)
{
        MString result("//");
        result += text;
        return result;
}
MString maTranslator::quote(const MString& str)
{
        const char* cstr = str.asChar();
        int     strLen = str.length();
        int i;
        MString result("\"");
        for (i = 0; i < strLen; i++)
        {
                int c = cstr[i];
                if (isprint(c))
                {
                        
                        
                        
                        
                        
                        switch (c)
                        {
                                case '"':
                                        result += "\\\"";
                                break;
                                case '\\':
                                        result += "\\\\";
                                break;
                                default:
                                        result += MString((const char*)&c, 1);
                                break;
                        }
                }
                else
                {
                        
                        
                        
                        switch (c)
                        {
                                case '\n':
                                        result += "\\n";
                                break;
                                case '\t':
                                        result += "\\t";
                                break;
                                case '\b':
                                        result += "\\b";
                                break;
                                case '\r':
                                        result += "\\r";
                                break;
                                case '\f':
                                        result += "\\f";
                                break;
                                case '\v':
                                        result += "\\v";
                                break;
                                case '\007':
                                        result += "\\a";
                                break;
                                default:
                                {
                                        
                                        
                                        
                                        char buff[5];
                                        sprintf(buff, "\\%.3o", c);
                                        result += MString(buff, 4);
                                }
                        }
                }
        }
        
        
        
        result += "\"";
        return result;
}
MStatus initializePlugin(MObject obj)
{
        MFnPlugin plugin(obj, PLUGIN_COMPANY, "1.0", "Any");
        maTranslator::setPluginName(plugin.name());
        plugin.registerFileTranslator(
                maTranslator::translatorName(),
                NULL,
                maTranslator::creator,
                NULL,
                NULL,
                false
        );
        return MS::kSuccess;
}
MStatus uninitializePlugin(MObject obj)
{
        MFnPlugin plugin( obj );
        plugin.deregisterFileTranslator(maTranslator::translatorName());
        return MS::kSuccess;
}