#include "util.h"
#include "AlembicNode.h"
#include "CreateSceneHelper.h"
#include "CameraHelper.h"
#include "LocatorHelper.h"
#include "MeshHelper.h"
#include "NurbsCurveHelper.h"
#include "NurbsSurfaceHelper.h"
#include "PointHelper.h"
#include "XformHelper.h"
#include <maya/MAngle.h>
#include <maya/MGlobal.h>
#include <maya/MTime.h>
#include <maya/MFileObject.h>
#include <maya/MArrayDataHandle.h>
#include <maya/MFloatPointArray.h>
#include <maya/MFnDoubleArrayData.h>
#include <maya/MFnIntArrayData.h>
#include <maya/MFnVectorArrayData.h>
#include <maya/MFnStringArrayData.h>
#include <maya/MFnStringData.h>
#include <maya/MFnMeshData.h>
#include <maya/MFnNurbsCurveData.h>
#include <maya/MFnNurbsSurfaceData.h>
#include <maya/MFnGenericAttribute.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MFnUnitAttribute.h>
#include <maya/MFnEnumAttribute.h>
#include <maya/MExternalContentInfoTable.h>
#include <Alembic/AbcCoreFactory/IFactory.h>
#include <Alembic/AbcCoreOgawa/ReadWrite.h>
#include <Alembic/AbcGeom/Visibility.h>
MObject AlembicNode::mAbcFileNameAttr;
 
MObject AlembicNode::mAbcLayerFileNamesAttr;
 
MObject AlembicNode::mCycleTypeAttr;
 
MObject AlembicNode::mStartFrameAttr;
 
MObject AlembicNode::mEndFrameAttr;
 
MObject AlembicNode::mIncludeFilterAttr;
 
MObject AlembicNode::mExcludeFilterAttr;
 
MObject AlembicNode::mOutSubDArrayAttr;
 
MObject AlembicNode::mOutPolyArrayAttr;
 
MObject AlembicNode::mOutCameraArrayAttr;
 
MObject AlembicNode::mOutNurbsCurveGrpArrayAttr;
 
MObject AlembicNode::mOutNurbsSurfaceArrayAttr;
 
MObject AlembicNode::mOutTransOpArrayAttr;
 
MObject AlembicNode::mOutPropArrayAttr;
 
MObject AlembicNode::mOutLocatorPosScaleArrayAttr;
 
{
    
    status = addAttribute(mTimeAttr);
    
    mAbcFileNameAttr = tAttr.
create(
"abc_File", 
"fn",
 
    status = addAttribute(mAbcFileNameAttr);
    
    MObject layerFileNamesDefaultObject = fileFnStringArrayData.
create(dummyStringArray);
 
    mAbcLayerFileNamesAttr = tAttr2.
create(
"abc_layerFiles", 
"fns",
 
    status = addAttribute(mAbcLayerFileNamesAttr);
    
    mSpeedAttr = nAttr.
create(
"speed", 
"sp",
 
    status = addAttribute(mSpeedAttr);
    
    mOffsetAttr = nAttr.
create(
"offset", 
"of",
 
    status = addAttribute(mOffsetAttr);
    
    mCycleTypeAttr = eAttr.
create(
"cycleType", 
"ct", 0,  &status );
 
    status = eAttr.
addField(
"Hold", PLAYTYPE_HOLD);
 
    status = eAttr.
addField(
"Loop", PLAYTYPE_LOOP);
 
    status = eAttr.
addField(
"Reverse", PLAYTYPE_REVERSE);
 
    status = eAttr.
addField(
"Bounce", PLAYTYPE_BOUNCE);
 
    status = addAttribute(mCycleTypeAttr);
    
    
    
    mIncludeFilterAttr = tAttr.
create(
"regexIncludeFilter", 
"ift",
 
    status = addAttribute(mIncludeFilterAttr);
    
    
    
    mExcludeFilterAttr = tAttr.
create(
"regexExcludeFilter", 
"eft",
 
    status = addAttribute(mExcludeFilterAttr);
    
    mStartFrameAttr = nAttr.
create(
"startFrame", 
"sf",
 
    status = addAttribute(mStartFrameAttr);
    mEndFrameAttr = nAttr.
create(
"endFrame", 
"ef",
 
    status = addAttribute(mEndFrameAttr);
    
    
    mOutSubDArrayAttr = tAttr.
create(
"outSubDMesh", 
"osubd",
 
    status = addAttribute(mOutSubDArrayAttr);
    
    mOutPolyArrayAttr = tAttr.
create(
"outPolyMesh", 
"opoly",
 
    status = addAttribute(mOutPolyArrayAttr);
    
    mOutNurbsSurfaceArrayAttr = tAttr.
create(
"outNSurface", 
"ons",
 
    status = addAttribute(mOutNurbsSurfaceArrayAttr);
    
    mOutNurbsCurveGrpArrayAttr = tAttr.
create(
"outNCurveGrp", 
"onc",
 
    status = addAttribute(mOutNurbsCurveGrpArrayAttr);
    
    mOutLocatorPosScaleArrayAttr = nAttr.
create(
"outLoc", 
"olo",
 
    status = addAttribute(mOutLocatorPosScaleArrayAttr);
    
    mOutTransOpArrayAttr = nAttr.
create(
"transOp", 
"to",
 
    status = addAttribute(mOutTransOpArrayAttr);
    
    
    mOutCameraArrayAttr = nAttr.
create(
"outCamera", 
"ocam",
 
    status = addAttribute(mOutCameraArrayAttr);
    
    mOutPropArrayAttr = gAttr.
create(
"prop", 
"pr", &status);
 
    status = addAttribute(mOutPropArrayAttr);
    
    status = attributeAffects(mTimeAttr, mOutSubDArrayAttr);
    status = attributeAffects(mTimeAttr, mOutPolyArrayAttr);
    status = attributeAffects(mTimeAttr, mOutNurbsSurfaceArrayAttr);
    status = attributeAffects(mTimeAttr, mOutNurbsCurveGrpArrayAttr);
    status = attributeAffects(mTimeAttr, mOutTransOpArrayAttr);
    status = attributeAffects(mTimeAttr, mOutCameraArrayAttr);
    status = attributeAffects(mTimeAttr, mOutPropArrayAttr);
    status = attributeAffects(mTimeAttr, mOutLocatorPosScaleArrayAttr);
    status = attributeAffects(mSpeedAttr, mOutSubDArrayAttr);
    status = attributeAffects(mSpeedAttr, mOutPolyArrayAttr);
    status = attributeAffects(mSpeedAttr, mOutNurbsSurfaceArrayAttr);
    status = attributeAffects(mSpeedAttr, mOutNurbsCurveGrpArrayAttr);
    status = attributeAffects(mSpeedAttr, mOutTransOpArrayAttr);
    status = attributeAffects(mSpeedAttr, mOutCameraArrayAttr);
    status = attributeAffects(mSpeedAttr, mOutPropArrayAttr);
    status = attributeAffects(mSpeedAttr, mOutLocatorPosScaleArrayAttr);
    status = attributeAffects(mOffsetAttr, mOutSubDArrayAttr);
    status = attributeAffects(mOffsetAttr, mOutPolyArrayAttr);
    status = attributeAffects(mOffsetAttr, mOutNurbsSurfaceArrayAttr);
    status = attributeAffects(mOffsetAttr, mOutNurbsCurveGrpArrayAttr);
    status = attributeAffects(mOffsetAttr, mOutTransOpArrayAttr);
    status = attributeAffects(mOffsetAttr, mOutCameraArrayAttr);
    status = attributeAffects(mOffsetAttr, mOutPropArrayAttr);
    status = attributeAffects(mOffsetAttr, mOutLocatorPosScaleArrayAttr);
    status = attributeAffects(mCycleTypeAttr, mOutSubDArrayAttr);
    status = attributeAffects(mCycleTypeAttr, mOutPolyArrayAttr);
    status = attributeAffects(mCycleTypeAttr, mOutNurbsSurfaceArrayAttr);
    status = attributeAffects(mCycleTypeAttr, mOutNurbsCurveGrpArrayAttr);
    status = attributeAffects(mCycleTypeAttr, mOutTransOpArrayAttr);
    status = attributeAffects(mCycleTypeAttr, mOutCameraArrayAttr);
    status = attributeAffects(mCycleTypeAttr, mOutPropArrayAttr);
    status = attributeAffects(mCycleTypeAttr, mOutLocatorPosScaleArrayAttr);
    return status;
}
double AlembicNode::getFPS()
{
    float fps = 24.0f;
    {
        fps = static_cast<float>(time.as(unit));
    }
    if (fps <= 0.f )
    {
        fps = 24.0f;
    }
    return fps;
}
double AlembicNode::computeAdjustedTime(const double inputTime,
                                        const double speed,
                                        const double timeOffset)
{
   return ( inputTime - timeOffset ) * speed;
}
double AlembicNode::computeRetime(const double inputTime,
                                  const double firstTime,
                                  const double lastTime,
                                  const short playStyle)
{
    const double playTime = lastTime - firstTime;
    static const double eps = 0.001;
    double retime = inputTime;
    switch (playStyle)
    {
      case PLAYTYPE_HOLD:
          break;
      case PLAYTYPE_LOOP:
          if (inputTime < (firstTime - eps) || inputTime > (lastTime + eps))
          {
              const double timeOffset = inputTime - firstTime;
              const double playOffset = floor(timeOffset/playTime);
              const double fraction = fabs(timeOffset/playTime - playOffset);
              retime = firstTime + playTime * fraction;
          }
          break;
      case PLAYTYPE_REVERSE:
          if (inputTime > (firstTime + eps) && inputTime < (lastTime - eps))
          {
              const double timeOffset = inputTime - firstTime;
              const double playOffset = floor(timeOffset/playTime);
              const double fraction = fabs(timeOffset/playTime - playOffset);
              retime = lastTime - playTime * fraction;
          }
          else if (inputTime < (firstTime + eps))
          {
              retime = lastTime;
          }
          else
          {
              retime = firstTime;
          }
          break;
      case PLAYTYPE_BOUNCE:
          if (inputTime < (firstTime - eps) || inputTime > (lastTime + eps))
          {
              const double timeOffset = inputTime - firstTime;
              const double playOffset = floor(timeOffset/playTime);
              const double fraction = fabs(timeOffset/playTime - playOffset);
              
              if (fmod(playOffset, 2.0)==0.0)
              {
                  retime = firstTime + playTime * fraction;
              }
              
              else
              {
                  retime = lastTime - playTime * fraction;
              }
          }
          break;
    }
    return retime;
}
{
    if (plug == mAbcFileNameAttr)
    {
        if(mFileInitialized)
        {
        }
    }
}
{
    
    double offset = offsetHandle.
asDouble();
 
    double fps = getFPS();
    
    inputTime = computeAdjustedTime(inputTime, speed, offset/fps);
    
    if (mFileInitialized == false)
    {
        mFileInitialized = true;
        
        MPlug layerFilesPlug = depNode.findPlug(mAbcLayerFileNamesAttr, 
true);
 
        
        if( storedFilenames.length() == 0 )
        {
            storedFilenames.append( dataHandle.
asString() );
 
        }
        std::vector<std::string> abcFilenames;
        bool filenameChanged = false;
        
        for(unsigned int i = 0; i < storedFilenames.length(); i++)
        {
            
            
            }
            filenameChanged = filenameChanged || (fileObject.
resolvedFullName() != storedFilenames[i]);
 
            abcFilenames.push_back( fileName.
asChar() );
 
        }
        if (filenameChanged)
        {
            MObject newData = fnSAD.create(filenames, 
nullptr);
 
            storedFilenames = fnSAD.array();
        }
        Alembic::Abc::IArchive archive;
        Alembic::AbcCoreFactory::IFactory factory;
        factory.setPolicy(Alembic::Abc::ErrorHandler::kQuietNoopPolicy);
        archive = factory.getArchive( abcFilenames );
        if (!archive.valid())
        {
            MString theError = 
"Error opening these alembic files: ";
 
            const unsigned int numFilenames = storedFilenames.
length();
 
            for( unsigned int i = 0; i < numFilenames; i++ )
            {
                theError += storedFilenames[ i ];
                if( i != (numFilenames - 1) )
                {
                    theError += ", ";
                }
            }
            printError(theError);
        }
        
        mSubDInitialized = false;
        mPolyInitialized = false;
        
        
        
        
        
            dataBlock.
inputValue(mIncludeFilterAttr, &status);
 
        if (mIncludeFilterString.length() > 0)
        {
            includeFilterHandle.
set(mIncludeFilterString);
 
        }
        else if (includeFilterString.
length() > 0)
 
        {
            mIncludeFilterString = includeFilterString;
        }
            dataBlock.
inputValue(mExcludeFilterAttr, &status);
 
        if (mExcludeFilterString.length() > 0)
        {
            excludeFilterHandle.
set(mExcludeFilterString);
 
        }
        else if (excludeFilterString.
length() > 0)
 
        {
            mExcludeFilterString = excludeFilterString;
        }
        MPlug allSetsPlug = dep.findPlug(
"allColorSets", 
true);
 
        CreateSceneVisitor visitor(inputTime, !allSetsPlug.
isNull(),
 
            mIncludeFilterString, mExcludeFilterString);
        visitor.walk(archive);
        if (visitor.hasSampledData())
        {
            
            
            visitor.getData(mData);
            mData.getFrameRange(mSequenceStartTime, mSequenceEndTime);
                mStartFrameAttr, &status);
            startFrameHandle.
set(mSequenceStartTime*fps);
 
                mEndFrameAttr, &status);
            endFrameHandle.
set(mSequenceEndTime*fps);
 
        }
    }
    
    short playType = cycleHandle.
asShort();
 
    inputTime = computeRetime(inputTime, mSequenceStartTime, mSequenceEndTime,
                              playType);
    clamp<double>(mSequenceStartTime, mSequenceEndTime, inputTime);
    
    if (fabs(inputTime - mCurTime) > 0.00001)
    {
        mOutRead = std::vector<bool>(mOutRead.size(), false);
        mCurTime = inputTime;
    }
    if (plug == mOutPropArrayAttr)
    {
        if (mOutRead[0])
        {
            return MS::kSuccess;
        }
        mOutRead[0] = true;
        unsigned int propSize =
            static_cast<unsigned int>(mData.mPropList.size());
        if (propSize > 0)
        {
                mOutPropArrayAttr, &status);
            unsigned int outHandleIndex = 0;
            
            for (unsigned int i = 0; i < propSize; i++)
            {
                
                
                
                {
                }
                else
                {
                    continue;
                }
                if (mData.mPropList[i].mArray.valid())
                {
                    readProp(mCurTime, mData.mPropList[i].mArray, outHandle);
                }
                else if (mData.mPropList[i].mScalar.valid())
                {
                    
                    if (mData.mPropList[i].mScalar.getName() ==
                        Alembic::AbcGeom::kVisibilityPropertyName)
                    {
                        Alembic::Util::int8_t visVal = 1;
                        mData.mPropList[i].mScalar.get(&visVal,
                            Alembic::Abc::ISampleSelector(mCurTime,
                                Alembic::Abc::ISampleSelector::kNearIndex ));
                    }
                    else
                    {
                        
                        readProp(mCurTime, mData.mPropList[i].mScalar, outHandle);
                    }
                }
            }
        }
    }
    else if (plug == mOutTransOpArrayAttr )
    {
        if (mOutRead[1])
        {
            return MS::kSuccess;
        }
        mOutRead[1] = true;
        unsigned int xformSize =
            static_cast<unsigned int>(mData.mXformList.size());
        if (xformSize > 0)
        {
            MPlug arrayPlug(thisMObject(), mOutTransOpArrayAttr);
 
            unsigned int outHandleIndex = 0;
            for (unsigned int i = 0; i < xformSize; i++)
            {
                std::vector<double> sampleList;
                if (mData.mIsComplexXform[i])
                {
                    readComplex(mCurTime, mData.mXformList[i], sampleList);
                }
                else
                {
                    Alembic::AbcGeom::XformSample samp;
                    read(mCurTime, mData.mXformList[i], sampleList, samp);
                }
                unsigned int sampleSize = (unsigned int)sampleList.size();
                for (unsigned int j = 0; j < sampleSize; j++)
                {
                    
                    
                    
                    {
                    }
                    else
                        continue;
                    outHandle.
set(sampleList[j]);
 
                }
            }
        }
    }
    else if (plug == mOutLocatorPosScaleArrayAttr )
    {
        if (mOutRead[8])
        {
            return MS::kSuccess;
        }
        mOutRead[8] = true;
        unsigned int locSize =
            static_cast<unsigned int>(mData.mLocList.size());
        if (locSize > 0)
        {
                dataBlock.
outputValue(mOutLocatorPosScaleArrayAttr, &status);
 
            MPlug arrayPlug(thisMObject(), mOutLocatorPosScaleArrayAttr);
 
            unsigned int outHandleIndex = 0;
            for (unsigned int i = 0; i < locSize; i++)
            {
                std::vector< double > sampleList;
                read(mCurTime, mData.mLocList[i], sampleList);
                unsigned int sampleSize = (unsigned int)sampleList.size();
                for (unsigned int j = 0; j < sampleSize; j++)
                {
                    
                    
                    
                    {
                    }
                    else
                        continue;
                    outHandle.
set(sampleList[j]);
 
                }
            }
        }
    }
    else if (plug == mOutSubDArrayAttr)
    {
        if (mOutRead[2])
        {
            
            
            
            const unsigned int elementCount = outArrayHandle.
elementCount();
 
            for (unsigned int j = 0; j < elementCount; j++)
            {
            }
            return MS::kSuccess;
        }
        mOutRead[2] = true;
        unsigned int subDSize =
            static_cast<unsigned int>(mData.mSubDList.size());
        if (subDSize > 0)
        {
                mOutSubDArrayAttr, &status);
            for (unsigned int j = 0; j < subDSize; j++)
            {
                
                {
                    continue;
                }
                {
                    readSubD(mCurTime, fnMesh, obj, mData.mSubDList[j],
                        mSubDInitialized);
                }
            }
            mSubDInitialized = true;
        }
        
        
        
        
        else
        {
                mOutSubDArrayAttr, &status);
            {
                do
                {
                    {
                        emptyMesh.
create(0, 0, emptyVerts, emptyCounts,
 
                            emptyConnects, obj);
                    }
                }
                while (outArrayHandle.
next() == MS::kSuccess);
 
            }
            mSubDInitialized = true;
        }
    }
    else if (plug == mOutPolyArrayAttr)
    {
        if (mOutRead[3])
        {
            
            
            
            const unsigned int elementCount = outArrayHandle.
elementCount();
 
            for (unsigned int j = 0; j < elementCount; j++)
            {
            }
            return MS::kSuccess;
        }
        mOutRead[3] = true;
        unsigned int polySize =
            static_cast<unsigned int>(mData.mPolyMeshList.size());
        if (polySize > 0)
        {
            for (unsigned int j = 0; j < polySize; j++)
            {
                
                {
                    continue;
                }
                {
                    readPoly(mCurTime, fnMesh, obj, mData.mPolyMeshList[j],
                        mPolyInitialized);
                }
            }
            mPolyInitialized = true;
        }
        
        
        
        
        else
        {
                mOutPolyArrayAttr, &status);
            {
                do
                {
                    {
                        emptyMesh.
create(0, 0, emptyVerts, emptyCounts,
 
                            emptyConnects, obj);
                    }
                }
                while (outArrayHandle.
next() == MS::kSuccess);
 
            }
            mPolyInitialized = true;
        }
    }
    else if (plug == mOutCameraArrayAttr)
    {
        if (mOutRead[4])
        {
            return MS::kSuccess;
        }
        mOutRead[4] = true;
        unsigned int cameraSize =
            static_cast<unsigned int>(mData.mCameraList.size());
        if (cameraSize > 0)
        {
            MPlug arrayPlug(thisMObject(), mOutCameraArrayAttr);
 
            double angleConversion = 1.0;
            {
                    angleConversion = 0.017453292519943295;
                break;
                    angleConversion = 60.0;
                break;
                    angleConversion = 3600.0;
                break;
                default:
                break;
            }
            unsigned int index = 0;
            for (unsigned int cameraIndex = 0; cameraIndex < cameraSize;
                cameraIndex++)
            {
                Alembic::AbcGeom::ICamera & cam =
                    mData.mCameraList[cameraIndex];
                std::vector<double> array;
                read(mCurTime, cam, array);
                for (unsigned int dataIndex = 0; dataIndex < array.size();
                    dataIndex++, index++)
                {
                    
                    {
                        continue;
                    }
                    
                    if (dataIndex != 11)
                    {
                        outHandle.
set(array[dataIndex]);
 
                    }
                    else
                    {
                        outHandle.
set(array[dataIndex] * angleConversion);
 
                    }
                }  
            }  
        }
    }
    else if (plug == mOutNurbsSurfaceArrayAttr)
    {
        if (mOutRead[5])
        {
            
            
            
                dataBlock.
outputValue(mOutNurbsSurfaceArrayAttr, &status);
 
            const unsigned int elementCount = outArrayHandle.
elementCount();
 
            for (unsigned int j = 0; j < elementCount; j++)
            {
            }
            return MS::kSuccess;
        }
        mOutRead[5] = true;
        unsigned int nSurfaceSize =
            static_cast<unsigned int>(mData.mNurbsList.size());
        if (nSurfaceSize > 0)
        {
                dataBlock.
outputValue(mOutNurbsSurfaceArrayAttr, &status);
 
            for (unsigned int j = 0; j < nSurfaceSize; j++)
            {
                
                    continue;
                {
                    readNurbs(mCurTime, mData.mNurbsList[j], obj);
                }
            }
        }
    }
    else if (plug == mOutNurbsCurveGrpArrayAttr)
    {
        if (mOutRead[6])
        {
            
            
            
                dataBlock.
outputValue(mOutNurbsCurveGrpArrayAttr, &status);
 
            const unsigned int elementCount = outArrayHandle.
elementCount();
 
            for (unsigned int j = 0; j < elementCount; j++)
            {
            }
            return MS::kSuccess;
        }
        mOutRead[6] = true;
        unsigned int nCurveGrpSize =
            static_cast<unsigned int>(mData.mCurvesList.size());
        if (nCurveGrpSize > 0)
        {
                dataBlock.
outputValue(mOutNurbsCurveGrpArrayAttr, &status);
 
            std::vector<MObject> curvesObj;
            for (unsigned int i = 0; i < nCurveGrpSize; ++i)
            {
                readCurves(mCurTime, mData.mCurvesList[i],
                    mData.mNumCurves[i], curvesObj);
            }
            std::size_t numChild = curvesObj.size();
            
            
            
            for (unsigned int i = 0; i < numChild; i++)
            {
                {
                    continue;
                }
                status = outHandle.
set(curvesObj[i]);
 
            }
        }
    }
    else
    {
        return MS::kUnknownParameter;
    }
    return status;
}
bool AlembicNode::isPassiveOutput(
const MPlug & plug)
 const 
{
    MPlug arrayPlug(thisMObject(), mOutCameraArrayAttr);
 
    unsigned int farClipPlaneIndex = 11;
    if (status == MS::kSuccess && plug == farClipPlanePlug)
        return true;
}
AlembicNode::SchedulingType AlembicNode::schedulingType()const
{
    
    return kGloballySerialize;
}
    bool ,
    bool unresolvedName,
    bool ) const
{
    MPlug layerFilenamesPlug(thisMObject(), mAbcLayerFileNamesAttr);
 
    for( unsigned int i = 0; i < layerFilenames.length(); i++ )
    {
        MString fileName = layerFilenames[i];
 
        if (status == MS::kSuccess && fileName.
length() > 0)
 
        {
            if(unresolvedName)
            {
            }
            else
            {
                
                
            }
        }
    }
    return files;
}
{
   addExternalContentForFileAttr(table, mAbcLayerFileNamesAttr);
}
{
   setExternalContentForFileAttr(mAbcLayerFileNamesAttr, table);
}