Abc::FloatArraySamplePtr getKnotVector(AbcG::ICurves& obj)
{
  ESS_PROFILE_FUNC();

  Abc::ICompoundProperty arbGeom = obj.getSchema().getArbGeomParams();

  if (!arbGeom.valid()) {
    return Abc::FloatArraySamplePtr();
  }

  if (arbGeom.getPropertyHeader(".knot_vectors") != NULL) {
    Abc::IFloatArrayProperty knotProp =
        Abc::IFloatArrayProperty(arbGeom, ".knot_vectors");
    if (knotProp.valid() && knotProp.getNumSamples() != 0) {
      return knotProp.getValue(0);
    }
  }
  if (arbGeom.getPropertyHeader(".knot_vector") != NULL) {
    Abc::IFloatArrayProperty knotProp =
        Abc::IFloatArrayProperty(arbGeom, ".knot_vector");
    if (knotProp.valid() && knotProp.getNumSamples() != 0) {
      return knotProp.getValue(0);
    }
  }

  return Abc::FloatArraySamplePtr();
}
Abc::UInt16ArraySamplePtr getCurveOrders(AbcG::ICurves& obj)
{
   ESS_PROFILE_FUNC();

   Abc::ICompoundProperty arbGeom = obj.getSchema().getArbGeomParams();

   if(!arbGeom.valid()){
      return Abc::UInt16ArraySamplePtr();
   }

   if ( arbGeom.getPropertyHeader( ".orders" ) != NULL ){
      Abc::IUInt16ArrayProperty orders = Abc::IUInt16ArrayProperty( arbGeom, ".orders" );
      if(orders.valid() && orders.getNumSamples() != 0){
         return orders.getValue(0);
      }
   }

   return Abc::UInt16ArraySamplePtr();
}
MStatus AlembicCurvesLocatorNode::compute(const MPlug &plug,
                                          MDataBlock &dataBlock)
{
  ESS_PROFILE_SCOPE("AlembicCurvesLocatorNode::compute");
  MStatus status;

  // update the frame number to be imported
  double inputTime =
      dataBlock.inputValue(mTimeAttr).asTime().as(MTime::kSeconds);
  MString &fileName = dataBlock.inputValue(mFileNameAttr).asString();
  MString &identifier = dataBlock.inputValue(mIdentifierAttr).asString();

  AbcG::ICurves obj;

  // check if we have the file
  if (fileName != mFileName || identifier != mIdentifier) {
    mSchema.reset();
    if (fileName != mFileName) {
      delRefArchive(mFileName);
      mFileName = fileName;
      addRefArchive(mFileName);
    }
    mIdentifier = identifier;

    // get the object from the archive
    Abc::IObject iObj = getObjectFromArchive(mFileName, identifier);
    if (!iObj.valid()) {
      MGlobal::displayWarning("[ExocortexAlembic] Identifier '" + identifier +
                              "' not found in archive '" + mFileName + "'.");
      return MStatus::kFailure;
    }
    obj = AbcG::ICurves(iObj, Abc::kWrapExisting);
    if (!obj.valid()) {
      MGlobal::displayWarning("[ExocortexAlembic] Identifier '" + identifier +
                              "' in archive '" + mFileName +
                              "' is not a Curves.");
      return MStatus::kFailure;
    }
    mSchema = obj.getSchema();
  }

  if (!mSchema.valid()) {
    return MStatus::kFailure;
  }

  // get the sample
  SampleInfo sampleInfo = getSampleInfo(inputTime, mSchema.getTimeSampling(),
                                        mSchema.getNumSamples());

  // check if we have to do this at all
  if (mNbCurves == 0 || mLastSampleInfo.floorIndex != sampleInfo.floorIndex ||
      mLastSampleInfo.ceilIndex != sampleInfo.ceilIndex) {
    AbcG::ICurvesSchema::Sample sample;
    AbcG::ICurvesSchema::Sample sample2;
    mSchema.get(sample, sampleInfo.floorIndex);
    if (sampleInfo.alpha != 0.0) {
      mSchema.get(sample2, sampleInfo.ceilIndex);
    }

    // update the indices
    Abc::P3fArraySamplePtr samplePos = sample.getPositions();
    if (mNbCurves != sample.getNumCurves() ||
        mNbVertices != samplePos->size()) {
      mNbCurves = (unsigned int)sample.getNumCurves();
      mNbVertices = (unsigned int)samplePos->size();

      Abc::Int32ArraySamplePtr nbVertices = sample.getCurvesNumVertices();
      mIndices.clear();
      unsigned int offset = 0;
      for (unsigned int i = 0; i < mNbCurves; i++) {
        unsigned int verticesPerCurve = nbVertices->get()[i];
        for (unsigned j = 0; j < verticesPerCurve - 1; j++) {
          mIndices.push_back(offset);
          offset++;
          mIndices.push_back(offset);
        }
        offset++;
      }
    }

    if (mPositions.size() != samplePos->size()) {
      mPositions.resize(samplePos->size());
    }

    // check if we need to interpolate
    bool done = false;
    mBoundingBox.clear();
    if (sampleInfo.alpha != 0.0) {
      Abc::P3fArraySamplePtr samplePos2 = sample2.getPositions();
      if (samplePos->size() == samplePos2->size()) {
        float alpha = float(sampleInfo.alpha);
        float ialpha = 1.0f - alpha;
        for (unsigned int i = 0; i < samplePos->size(); i++) {
          mPositions[i].x =
              ialpha * samplePos->get()[i].x + alpha * samplePos2->get()[i].x;
          mPositions[i].y =
              ialpha * samplePos->get()[i].y + alpha * samplePos2->get()[i].y;
          mPositions[i].z =
              ialpha * samplePos->get()[i].z + alpha * samplePos2->get()[i].z;
          mBoundingBox.expand(
              MPoint(mPositions[i].x, mPositions[i].y, mPositions[i].z));
        }
        done = true;
      }
    }

    if (!done) {
      for (unsigned int i = 0; i < samplePos->size(); i++) {
        mPositions[i].x = samplePos->get()[i].x;
        mPositions[i].y = samplePos->get()[i].y;
        mPositions[i].z = samplePos->get()[i].z;
        mBoundingBox.expand(
            MPoint(mPositions[i].x, mPositions[i].y, mPositions[i].z));
      }
    }

    // get the colors
    // mColors.clear();

    Abc::IC4fArrayProperty propColor;
    if (getArbGeomParamPropertyAlembic(obj, "color", propColor)) {
      mColors.clear();
      SampleInfo colorSampleInfo = getSampleInfo(
          inputTime, propColor.getTimeSampling(), propColor.getNumSamples());
      Abc::C4fArraySamplePtr sampleColor =
          propColor.getValue(colorSampleInfo.floorIndex);
      mColors.resize(mPositions.size());
      if (sampleColor->size() == 1) {
        for (unsigned int i = 0; i < (unsigned int)mColors.size(); i++) {
          mColors[i].r = sampleColor->get()[0].r;
          mColors[i].g = sampleColor->get()[0].g;
          mColors[i].b = sampleColor->get()[0].b;
          mColors[i].a = sampleColor->get()[0].a;
        }
      }
      else if (sampleColor->size() == mPositions.size()) {
        for (unsigned int i = 0; i < sampleColor->size(); i++) {
          mColors[i].r = sampleColor->get()[i].r;
          mColors[i].g = sampleColor->get()[i].g;
          mColors[i].b = sampleColor->get()[i].b;
          mColors[i].a = sampleColor->get()[i].a;
        }
      }
      else if (sampleColor->size() == mNbCurves) {
        Abc::Int32ArraySamplePtr nbVertices = sample.getCurvesNumVertices();
        unsigned int offset = 0;
        for (unsigned int i = 0; i < nbVertices->size(); i++) {
          for (unsigned j = 0; j < (unsigned int)nbVertices->get()[i]; j++) {
            mColors[offset].r = sampleColor->get()[i].r;
            mColors[offset].g = sampleColor->get()[i].g;
            mColors[offset].b = sampleColor->get()[i].b;
            mColors[offset].a = sampleColor->get()[i].a;
            offset++;
          }
        }
      }
    }
  }

  mLastSampleInfo = sampleInfo;

  MDataHandle outSent = dataBlock.outputValue(mSentinelAttr);
  // increment, this tells the draw routine that the display list needs to be
  // regenerated
  outSent.set((mSent + 1 % 10));
  dataBlock.setClean(mSentinelAttr);

  return MStatus::kSuccess;
}