#include "AbcBullet.h"
#include "AbcWriteJob.h"
#include "MayaUtility.h"
#include "AbcBulletStringTable.h"
#include <maya/MFnPlugin.h>
#include <maya/MFileObject.h>
#include <maya/MItDependencyNodes.h>
#include <fstream>
#include <maya/MItDependencyNodes.h>
#include <maya/MTimer.h>
namespace AbcA = Alembic::AbcCoreAbstract;
AbcBullet::AbcBullet()
{
}
AbcBullet::~AbcBullet()
{
}
{
    return syntax;
}
void* AbcBullet::creator()
{
    return new AbcBullet();
}
{
try
{
    if (argData.isFlagSet("help"))
    {
    }
    bool verbose = argData.isFlagSet("verbose");
    
    
    
    
    bool skipFrame = true;
    if (argData.isFlagSet("dontSkipUnwrittenFrames"))
        skipFrame = false;
    double startEvaluationTime = DBL_MAX;
    if (argData.isFlagSet("preRollStartFrame"))
    {
        double startAt = 0.0;
        argData.getFlagArgument("preRollStartFrame", 0, startAt);
        startEvaluationTime = startAt;
    }
    unsigned int jobSize = argData.numberOfFlagUses("jobArg");
    if (jobSize == 0)
        return status;
    
    
    std::set<double> allFrameRange;
    
    
    std::list < AbcWriteJobPtr > jobList;
    for (unsigned int jobIndex = 0; jobIndex < jobSize; jobIndex++)
    {
        JobArgs jobArgs;
        argData.getFlagArgumentList("jobArg", jobIndex, jobArgList);
        jobArgs.verbose = verbose;
        {
            
            
            
            
            enum State {
                kArgument,             
                kDoubleQuotedString,     
                kSingleQuotedString,     
            };
            State state = kArgument;
            for (
unsigned int charIdx = 0; charIdx < jobArgsStr.
numChars();
 
                charIdx++)
            {
                switch (state)
                {
                case kArgument:
                    if (ch == " ")
                    {
                        
                        if (stringBuffer.
length() > 0) {
 
                            jobArgsArray.
append(stringBuffer);
                        }
                        
                        state = kArgument;
                    }
                    else if (ch == "\"")
                    {
                        if (stringBuffer.
length() > 0)
 
                        {
                            
                            stringBuffer += ch;
                        }
                        else
                        {
                            
                            state = kDoubleQuotedString;
                        }
                    }
                    else if (ch == "'")
                    {
                        if (stringBuffer.
length() > 0)
 
                        {
                            
                            stringBuffer += ch;
                        }
                        else
                        {
                            
                            state = kSingleQuotedString;
                        }
                    }
                    else
                    {
                        stringBuffer += ch;
                    }
                break;
                case kDoubleQuotedString:
                    
                    if (ch == "\"")
                    {
                        jobArgsArray.
append(stringBuffer);
                        state = kArgument;
                    }
                    else if (ch == "\\")
                    {
                        
                        if (nextCh == "n")     stringBuffer += "\n";
                        else if (nextCh == "t")  stringBuffer += "\t";
                        else if (nextCh == "r")  stringBuffer += "\r";
                        else if (nextCh == "\\") stringBuffer += "\\";
                        else if (nextCh == "'")  stringBuffer += "'";
                        else if (nextCh == "\"") stringBuffer += "\"";
                        else                     stringBuffer += nextCh;
                    }
                    else
                    {
                        stringBuffer += ch;
                    }
                break;
                case kSingleQuotedString:
                    
                    if (ch == "'")
                    {
                        jobArgsArray.
append(stringBuffer);
                        state = kArgument;
                    }
                    else if (ch == "\\")
                    {
                        
                        if (nextCh == "n")     stringBuffer += "\n";
                        else if (nextCh == "t")  stringBuffer += "\t";
                        else if (nextCh == "r")  stringBuffer += "\r";
                        else if (nextCh == "\\") stringBuffer += "\\";
                        else if (nextCh == "'")  stringBuffer += "'";
                        else if (nextCh == "\"") stringBuffer += "\"";
                        else                     stringBuffer += nextCh;
                    }
                    else
                    {
                        stringBuffer += ch;
                    }
                break;
                }
            }
            
            if (stringBuffer.
length() > 0)
 
            {
                jobArgsArray.
append(stringBuffer);
            }
        }
        double startTime = oldCurTime.
value();
 
        double endTime = oldCurTime.
value();
 
        double strideTime = 1.0;
        bool hasRange = false;
        bool hasRoot = false;
        std::set <double> shutterSamples;
        std::string fileName;
        unsigned int numJobArgs = jobArgsArray.
length();
 
        for (unsigned int i = 0; i < numJobArgs; ++i)
        {
            if (arg == "-f" || arg == "-file")
            {
                if (i+1 >= numJobArgs)
                {
                }
                fileName = jobArgsArray[++i].asChar();
            } 
            else if (arg == "-fr" || arg == "-framerange")
            {
                if (i+2 >= numJobArgs || !jobArgsArray[i+1].isDouble() ||
                    !jobArgsArray[i+2].isDouble())
                {
                }
                hasRange = true;
                startTime = jobArgsArray[++i].asDouble();
                endTime = jobArgsArray[++i].asDouble();
                
                if (startTime > endTime)
                {
                    double temp = startTime;
                    startTime = endTime;
                    endTime = temp;
                }
            }
            else if (arg == "-frs" || arg == "-framerelativesample")
            {
                if (i+1 >= numJobArgs || !jobArgsArray[i+1].isDouble())
                {
                }
                shutterSamples.insert(jobArgsArray[++i].asDouble());
            }
            else if (arg == "-nn" || arg == "-nonormals")
            {
                jobArgs.noNormals = true;
            }
            else if (arg == "-ro" || arg == "-renderableonly")
            {
                jobArgs.excludeInvisible = true;
            }
            else if (arg == "-s" || arg == "-step")
            {
                if (i+1 >= numJobArgs || !jobArgsArray[i+1].isDouble())
                {
                }
                strideTime = jobArgsArray[++i].asDouble();
            }
            else if (arg == "-sl" || arg == "-selection")
            {
                jobArgs.useSelectionList = true;
            }
            else if (arg == "-sn" || arg == "-stripnamespaces")
            {
                if (i+1 >= numJobArgs || !jobArgsArray[i+1].isUnsigned())
                {
                    
                    
                    jobArgs.stripNamespace = 0xffffffff;
                }
                else
                {
                    jobArgs.stripNamespace = jobArgsArray[++i].asUnsigned();
                }
            }
            else if (arg == "-uv" || arg == "-uvwrite")
            {
                jobArgs.writeUVs = true;
            }
            else if (arg == "-wcs" || arg == "-writecolorsets")
            {
                jobArgs.writeColorSets = true;
            }
            else if (arg == "-wfs" || arg == "-writefacesets")
            {
                jobArgs.writeFaceSets = true;
            }
            else if (arg == "-ws" || arg == "-worldspace")
            {
                jobArgs.worldSpace = true;
            }
            else if (arg == "-wv" || arg == "-writevisibility")
            {
                jobArgs.writeVisibility = true;
            }
            else if (arg == "-mfc" || arg == "-melperframecallback")
            {
                if (i+1 >= numJobArgs)
                {
                        "melPerFrameCallback incorrectly specified.");
                }
                jobArgs.melPerFrameCallback = jobArgsArray[++i].asChar();
            }
            else if (arg == "-pfc" || arg == "-pythonperframecallback")
            {
                if (i+1 >= numJobArgs)
                {
                }
                jobArgs.pythonPerFrameCallback = jobArgsArray[++i].asChar();
            }
            else if (arg == "-mpc" || arg == "-melpostjobcallback")
            {
                if (i+1 >= numJobArgs)
                {
                }
                jobArgs.melPostCallback = jobArgsArray[++i].asChar();
            }
            else if (arg == "-ppc" || arg == "-pythonpostjobcallback")
            {
                if (i+1 >= numJobArgs)
                {
                }
                jobArgs.pythonPostCallback = jobArgsArray[++i].asChar();
            }
            
            else if (arg == "-atp" || arg == "-attrprefix")
            {
                if (i+1 >= numJobArgs)
                {
                }
                jobArgs.prefixFilters.push_back(jobArgsArray[++i].asChar());
            }
            else if (arg == "-a" || arg == "-attr")
            {
                if (i+1 >= numJobArgs)
                {
                }
                jobArgs.attribs.insert(jobArgsArray[++i].asChar());
            }
            
            else if (arg == "-uatp" || arg == "-userattrprefix")
            {
                if (i+1 >= numJobArgs)
                {
                }
                jobArgs.userPrefixFilters.push_back(jobArgsArray[++i].asChar());
            }
            else if (arg == "-u" || arg == "-userattr")
            {
                if (i+1 >= numJobArgs)
                {
                }
                jobArgs.userAttribs.insert(jobArgsArray[++i].asChar());
            }
            else if (arg == "-rt" || arg == "-root")
            {
                if (i+1 >= numJobArgs)
                {
                }
                hasRoot = true;
                {
                    warn += " could not be select, skipping.";
                    continue;
                }
                unsigned int numRoots = sel.
length();
 
                for (unsigned int j = 0; j < numRoots; ++j)
                {
                    {
                        warn += " (part of ";
                        warn += root;
                        warn += " ) not a DAG Node, skipping.";
                        continue;
                    }
                    jobArgs.dagPaths.insert(path);
                }
            }
            else if (arg == "-ef" || arg == "-eulerfilter")
            {
                jobArgs.filterEulerRotations = true;
            }
            else
            {
                MString warn = 
"Ignoring unsupported flag: ";
 
                warn += jobArgsArray[i];
            }
        } 
        if (fileName == "")
        {
            MString error = 
"-file not specified.";
 
        }
        {
            MString alembicFileRule = 
"alembicCache";
 
            MString alembicFilePath = 
"cache/alembic";
 
            queryFileRuleCmd.
format(
"workspace -q -fre \"^1s\"",
                alembicFileRule);
            queryFolderCmd.
format(
"workspace -en `workspace -q -fre \"^1s\"`",
                alembicFileRule);
            
            {
                
            }
            else
            {
                
                addFileRuleCmd.
format(
"workspace -fr \"^1s\" \"^2s\"",
                    alembicFileRule, alembicFilePath);
                
                
            }
            
            {
                expandName = alembicFilePath;
            }
            
            
            {
                
                createFolderCmd.
format(
"sysFile -md \"^1s\"", directoryName);
            }
            
#if MAYA_API_VERSION < 201300
            {
#else
#endif
                
                MString absoluteFileName = directoryName + 
"/" +
 
                    fileName.c_str();
            }
            else
            {
            }
            
            if (!absoluteFilePath.
exists()) {
 
            }
            
            for (; !dgIter.isDone(); dgIter.next()) {
                if (alembicNode.typeName() != "AlembicNode") {
                    continue;
                }
                MPlug abcFilePlug = alembicNode.findPlug(
"abc_File");
 
                    continue;
                }
                    continue;
                }
                    MString error = 
"Can't export to an Alembic file which is in use.";
 
                }
            }
            std::ofstream ofs(fileName.c_str());
            if (!ofs.is_open()) {
            }
            ofs.close();
        }
        if (shutterSamples.empty())
        {
            shutterSamples.insert(0.0);
        }
        if (jobArgs.prefixFilters.empty())
        {
            jobArgs.prefixFilters.push_back("ABC_");
        }
        
        std::set<double> transSamples;
        std::set <double>::const_iterator shutter;
        std::set <double>::const_iterator shutterStart = shutterSamples.begin();
        std::set <double>::const_iterator shutterEnd = shutterSamples.end();
        for (double frame = startTime; frame <= endTime; frame += strideTime)
        {
            for (shutter = shutterStart; shutter != shutterEnd; ++shutter)
            {
                double curFrame = *shutter + frame;
                transSamples.insert(curFrame);
            }
        }
        if (transSamples.empty())
        {
            transSamples.insert(startTime);
        }
        if (jobArgs.dagPaths.size() > 1)
        {
            
            util::ShapeSet::const_iterator m, n;
            util::ShapeSet::const_iterator end = jobArgs.dagPaths.end();
            for (m = jobArgs.dagPaths.begin(); m != end; )
            {
                m++;
                for (n = m; n != end; n++)
                {
                    if (util::isAncestorDescendentRelationship(path1,path2))
                    {
                        errorMsg += " and ";
                        errorMsg += " have an ancestor relationship.";
                    }
                }  
            }  
        }
        
        
        
        else if (!hasRoot && !jobArgs.useSelectionList)
        {
#if MAYA_API_VERSION >= 201100
#else
            
            
#endif
            unsigned int numRoots = sel.
length();
 
            for (unsigned int i = 0; i < numRoots; ++i)
            {
                jobArgs.dagPaths.insert(path);
            }
        }
        else if (hasRoot && jobArgs.dagPaths.empty())
        {
            MString errorMsg = 
"No valid root nodes were specified.";
 
        }
        else if (jobArgs.useSelectionList)
        {
            {
                    "-selection specified but nothing is actively selected.";
            }
        }
        AbcA::TimeSamplingPtr transTime;
        std::vector<double> samples;
        for (shutter = shutterStart; shutter != shutterEnd; ++shutter)
        {
            samples.push_back((startTime + *shutter) * util::spf());
        }
        if (hasRange)
        {
            transTime.reset(new AbcA::TimeSampling(AbcA::TimeSamplingType(
                static_cast<Alembic::Util::uint32_t>(samples.size()),
                strideTime * util::spf()), samples));
        }
        else
        {
            transTime.reset(new AbcA::TimeSampling());
        }
        AbcWriteJobPtr job(new AbcWriteJob(fileName.c_str(),
            transSamples, transTime, jobArgs));
       jobList.push_front(job);
        
        
        if (!skipFrame && !allFrameRange.empty())
        {
            double localMin = *(transSamples.begin());
            std::set<double>::iterator last = transSamples.end();
            last--;
            double localMax = *last;
            double globalMin = *(allFrameRange.begin());
            last = allFrameRange.end();
            last--;
            double globalMax = *last;
            
            
            if (localMin > globalMax)
            {
                for (double f = globalMax; f < localMin; f++)
                {
                    allFrameRange.insert(f);
                }
            }
            
            
            if (localMax < globalMin)
            {
                for (double f = localMax; f < globalMin; f++)
                {
                    allFrameRange.insert(f);
                }
            }
        }
        
        
        allFrameRange.insert(transSamples.begin(), transSamples.end());
    }
    
    if (startEvaluationTime != DBL_MAX && !allFrameRange.empty())
    {
        double firstFrame = *allFrameRange.begin();
        for (double f = startEvaluationTime; f < firstFrame; ++f)
        {
            allFrameRange.insert(f);
        }
    }
    std::set<double>::iterator it = allFrameRange.begin();
    std::set<double>::iterator itEnd = allFrameRange.end();
    
    
    
    
    
    for (; it != itEnd; it++)
    {
        std::list< AbcWriteJobPtr >::iterator j = jobList.begin();
        std::list< AbcWriteJobPtr >::iterator jend = jobList.end();
        while (j != jend)
        {
            bool lastFrame = (*j)->eval(*it);
            if (lastFrame)
            {
                j = jobList.erase(j);
            }
            else
                j++;
        }
        if (verbose)
        {
            double frame = *it;
            info.
format( 
"processed frame: ^1s in ^2s seconds", arg1, arg2 );
        }
    }
    
}
catch (Alembic::Util::Exception & e)
{
    MString theError(
"Alembic Exception encountered: ");
 
    theError += e.what();
}
catch (std::exception & e)
{
    MString theError(
"std::exception encountered: ");
 
    theError += e.what();
}
}
{
    MFnPlugin plugin(obj, 
"AbcBullet", ABCBULLET_VERSION, 
"Any");
 
    status = plugin.registerCommand(
        "AbcBulletExport", AbcBullet::creator,
        AbcBullet::createSyntax );
    if (!status)
    {
        status.
perror(
"registerCommand");
    }
    
    info += ABCBULLET_VERSION;
    info += " using ";
    info += Alembic::Abc::GetLibraryVersion().c_str();
    return status;
}
{
    status = plugin.deregisterCommand("AbcBulletExport");
    if (!status)
    {
        status.
perror(
"deregisterCommand");
    }
    
    return status;
}