#include "polyModifierCmd.h"
#include <maya/MGlobal.h>
#include <maya/MFloatVector.h>
#include <maya/MObjectArray.h>
#include <maya/MPlugArray.h>
#include <maya/MIOStream.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MFnDagNode.h>
#include <maya/MFnNumericData.h>
#ifdef _DEBUG
#   define MCheckStatus(status,message)         \
        if( MS::kSuccess != status ) {          \
            MString error("Status failed: ");   \
            error += message;                   \
            MGlobal::displayError(error);       \
            return status;                      \
        }
#else
#   define MCheckStatus(status,message)
#endif
#ifdef _DEBUG
#   define MAssert(state,message)                   \
        if( !state ) {                              \
            MString error("Assertion failed: ");    \
            error += message;                       \
            MGlobal::displayError(error);           \
            return;                                 \
        }
#else
#   define MAssert(state,message)
#endif
#ifdef _DEBUG
#   define MStatusAssert(state,message)             \
        if( !state ) {                              \
            MString error("Assertion failed: ");    \
            error += message;                       \
            MGlobal::displayError(error);           \
            return MS::kFailure;                    \
        }
#else
#   define MStatusAssert(state,message)
#endif
polyModifierCmd::polyModifierCmd()
{
    fDagPathInitialized = false;
    fModifierNodeTypeInitialized = false;
    fModifierNodeNameInitialized = false;
}
polyModifierCmd::~polyModifierCmd()
{}
{
}
{
}
MStatus polyModifierCmd::doModifyPoly()
 
{
    if( isCommandDataValid() )
    {
        
        
        collectNodeState();
        if( !fHasHistory && !fHasRecordHistory )
        {
            MObject meshNode = fDagPath.node();
 
            
            
            cacheMeshData();
            cacheMeshTweaks();
            
            
            status = directModifier( meshNode );
        }
        else
        {
            createModifierNode( modifierNode );
            initModifierNode( modifierNode );
            status = connectNodes( modifierNode );
        }
    }
    return status;
}
MStatus polyModifierCmd::redoModifyPoly()
 
{
    if( !fHasHistory && !fHasRecordHistory )
    {
        MObject meshNode = fDagPath.node();
 
        
        
        
        status = directModifier( meshNode );
    }
    else
    {
        
        
        if( !fHasHistory )
        {
            fDagModifier.doIt();
        }
        status = fDGModifier.doIt();
    }
    return status;
}
MStatus polyModifierCmd::undoModifyPoly()
 
{
    if( !fHasHistory && !fHasRecordHistory )
    {
        status = undoDirectModifier();
    }
    else
    {
        fDGModifier.undoIt();
        
        
        
        
        if( !fHasHistory )
        {
            status = undoCachedMesh();
            MCheckStatus( status, "undoCachedMesh" );
            fDagModifier.undoIt();
        }
        status = undoTweakProcessing();
        MCheckStatus( status, "undoTweakProcessing" );
    }
    return status;
}
bool polyModifierCmd::isCommandDataValid()
{
    bool valid = true;
    
    
    if( fDagPathInitialized )
    {
        fDagPath.extendToShape();
        if( !fDagPath.isValid() || fDagPath.apiType() != 
MFn::kMesh )
 
        {
            valid = false;
        }
    }
    else
    {
        valid = false;
    }
    
    
    if( !fModifierNodeTypeInitialized && !fModifierNodeNameInitialized )
    {
        valid = false;
    }
    return valid;
}
void polyModifierCmd::collectNodeState()
{
    
    
    
    
    
    
    fDagPath.extendToShape();
    MObject meshNodeShape = fDagPath.node();
 
    
    
    
    
    fHasTweaks = false;
    {
        
        
                 "tweakPlug.isArray() -- tweakPlug is not an array plug" );
        int i;
        for( i = 0; i < numElements; i++ )
        {
            {
                getFloat3PlugValue( tweak, tweakData );
                {
                    fHasTweaks = true;
                    break;
                }
            }
        }
    }
    int result;
    fHasRecordHistory = (0 != result);
}
{
    if( fModifierNodeTypeInitialized || fModifierNodeNameInitialized )
    {
        if( fModifierNodeTypeInitialized )
        {
            modifierNode = fDGModifier.createNode( fModifierNodeType, &status );
        }
        else if( fModifierNodeNameInitialized )
        {
            modifierNode = fDGModifier.createNode( fModifierNodeName, &status );
        }
        
        
        
        inMeshAttr = depNodeFn.
attribute( 
"inMesh" );
        outMeshAttr = depNodeFn.
attribute( 
"outMesh" );
        {
            displayError( "Invalid Modifier Node: inMesh and outMesh attributes are required." );
        }
    }
    
    return status;
}
MStatus polyModifierCmd::processMeshNode( modifyPolyData& data )
 
{
    
    
    
    
    
    data.meshNodeShape = fDagPath.node();
    
    
                   "0 < dagNodeFn.parentCount() -- meshNodeshape has no parent transform" );
    data.meshNodeTransform = dagNodeFn.
parent(0);
    
    data.meshNodeDestPlug = dagNodeFn.
findPlug( 
"inMesh" );
    data.meshNodeDestAttr = data.meshNodeDestPlug.
attribute();
    return status;
}
MStatus polyModifierCmd::processUpstreamNode( modifyPolyData& data )
 
{
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    if( fHasHistory )
    {
        
        
        
        
        data.meshNodeDestPlug.connectedTo( tempPlugArray, true, false);
        
        
        MStatusAssert( (tempPlugArray.
length() == 1),
                       "tempPlugArray.length() == 1 -- 0 or >1 connections on meshNodeShape.inMesh" );
        data.upstreamNodeSrcPlug = tempPlugArray[0];
        
        
        
        data.upstreamNodeShape = data.upstreamNodeSrcPlug.node();
        depNodeFn.
setObject( data.upstreamNodeShape );
        data.upstreamNodeSrcAttr = data.upstreamNodeSrcPlug.attribute();
        
        
        
        fDGModifier.disconnect( data.upstreamNodeSrcPlug,
                                data.meshNodeDestPlug );
    }
    else    
    {
        
        
        
        
        
        
        data.upstreamNodeTransform = dagNodeFn.
duplicate( 
false, 
false );
        dagNodeFn.
setObject( data.upstreamNodeTransform );
        
        
                       "0 < dagNodeFn.childCount() -- Duplicate meshNode transform has no shape." );
        data.upstreamNodeShape = dagNodeFn.
child(0);
        
        
        status = fDagModifier.reparentNode( data.upstreamNodeShape, data.meshNodeTransform );
        MCheckStatus( status, "reparentNode" );
        
        
        
        
        
        status = fDagModifier.doIt();
        MCheckStatus( status, "fDagModifier.doIt()" );
        
        
        
        dagNodeFn.
setObject( data.upstreamNodeShape );
        
        
        data.upstreamNodeSrcAttr = dagNodeFn.
attribute( 
"outMesh" );
        data.upstreamNodeSrcPlug = dagNodeFn.
findPlug( 
"outMesh", &status );
        
        
        status = fDagModifier.deleteNode( data.upstreamNodeTransform );
        MCheckStatus( status, "deleteNode" );
        
        
        
        
        
        
        status = fDagModifier.doIt();
        MCheckStatus( status, "fDagModifier.doIt()" );
        
        
        dagNodeFn.
getPath( fDuplicateDagPath );
    }
    return status;
}
                                              modifyPolyData& data )
{
    data.modifierNodeSrcAttr = depNodeFn.
attribute( 
"outMesh" );
    data.modifierNodeDestAttr = depNodeFn.
attribute( 
"inMesh" );
    return status;
}
MStatus polyModifierCmd::processTweaks( modifyPolyData& data )
 
{
    
    
    fTweakIndexArray.clear();
    fTweakVectorArray.clear();
    
    
    
    
    
    
    
    
    if( fHasTweaks )
    {
        
        
        
        
        
        
        unsigned i;
        unsigned j;
        unsigned k;
        
        
        data.tweakNode = fDGModifier.createNode( "polyTweak" );
        data.tweakNodeSrcAttr = depNodeFn.
attribute( 
"output" );
        data.tweakNodeDestAttr = depNodeFn.
attribute( 
"inputPolymesh" );
        tweakNodeTweakAttr = depNodeFn.
attribute( 
"tweak" );
        meshTweakPlug = depNodeFn.
findPlug( 
"pnts" );
        
        
        MStatusAssert( (meshTweakPlug.
isArray()),
                       "meshTweakPlug.isArray() -- meshTweakPlug is not an array plug" );
        
        
        for( i = 0; i < numElements; i++ )
        {
            
            
            
            
            
            
            
            {
                
                
                
                
                tweakDataArray.
append( tweakData );
                getFloat3PlugValue( tweak, tweakVector );
                fTweakIndexArray.append( logicalIndex );
                fTweakVectorArray.append( tweakVector );
                
                
                
                
                
                
                
                
                
                               "tweak.isCompound() -- Element tweak plug is not compound" );
                for( j = 0; j < numChildren; j++ )
                {
                    tweakChild = tweak.
child(j);
                    {
                        
                        
                        if( tweakChild.
connectedTo( tempPlugArray, 
false, 
true ) )
 
                        {
                            unsigned numSrcConnections = tempPlugArray.
length();
 
                            tweakSrcConnectionCountArray.
append( numSrcConnections );
                            for( k = 0; k < numSrcConnections; k++ )
                            {
                                tweakSrcConnectionPlugArray.
append( tempPlugArray[k] );
                                fDGModifier.disconnect( tweakChild, tempPlugArray[k] );
                            }
                        }
                        else
                        {
                            tweakSrcConnectionCountArray.
append(0);
                        }
                        
                        
                        if( tweakChild.
connectedTo( tempPlugArray, 
true, 
false ) )
 
                        {
                            
                            
                            MStatusAssert( (tempPlugArray.
length() == 1),
                                           "tempPlugArray.length() == 1 -- 0 or >1 connections on tweakChild" );
                            tweakDstConnectionCountArray.
append(1);
                            tweakDstConnectionPlugArray.
append( tempPlugArray[0] );
                            fDGModifier.disconnect( tempPlugArray[0], tweakChild );
                        }
                        else
                        {
                            tweakDstConnectionCountArray.
append(0);
                        }
                    }
                    else
                    {
                        tweakSrcConnectionCountArray.
append(0);
                        tweakDstConnectionCountArray.
append(0);
                    }
                }
            }
        }
        
        
        MPlug polyTweakPlug( data.tweakNode, tweakNodeTweakAttr );
 
        unsigned numTweaks = fTweakIndexArray.length();
        int srcOffset = 0;
        int dstOffset = 0;
        for( i = 0; i < numTweaks; i++ )
        {
            
            
            
            
                           "tweak.isCompound() -- Element plug, 'tweak', is not compound" );
            for( j = 0; j < numChildren; j++ )
            {
                tweakChild = tweak.
child(j);
                
                
                if( 0 < tweakSrcConnectionCountArray[i*numChildren + j] )
                {
                    for( k = 0;
                         k < (unsigned) tweakSrcConnectionCountArray[i*numChildren + j];
                         k++ )
                    {
                        fDGModifier.connect( tweakChild,
                                             tweakSrcConnectionPlugArray[srcOffset] );
                        srcOffset++;
                    }
                }
                        
                
                
                if( 0 < tweakDstConnectionCountArray[i*numChildren + j] )
                {
                    fDGModifier.connect( tweakDstConnectionPlugArray[dstOffset],
                                         tweakChild );
                    dstOffset++;
                }
            }
        }
  }
    return status;
}
{
    
    
    modifyPolyData data;
    
    
    status = processMeshNode( data );
    MCheckStatus( status, "processMeshNode" );
    
    
    status = processUpstreamNode( data );
    MCheckStatus( status, "processUpstreamNode" );
    
    
    status = processModifierNode( modifierNode,
                         data );
    MCheckStatus( status, "processModifierNode" );
    
    
    status = processTweaks( data );
    MCheckStatus( status, "processTweaks" );
    
    
    if( fHasTweaks )
    {
        MPlug tweakDestPlug( data.tweakNode, data.tweakNodeDestAttr );
 
        status = fDGModifier.connect( data.upstreamNodeSrcPlug, tweakDestPlug );
        MCheckStatus( status, "upstream-tweak connect failed" );
        MPlug tweakSrcPlug( data.tweakNode, data.tweakNodeSrcAttr );
 
        MPlug modifierDestPlug( modifierNode, data.modifierNodeDestAttr );
 
        status = fDGModifier.connect( tweakSrcPlug, modifierDestPlug );
        MCheckStatus( status, "tweak-modifier connect failed" );
    }
    else
    {
        MPlug modifierDestPlug( modifierNode, data.modifierNodeDestAttr );
 
        status = fDGModifier.connect( data.upstreamNodeSrcPlug, modifierDestPlug );
        MCheckStatus( status, "upstream-modifier connect failed" );
    }
    MPlug modifierSrcPlug( modifierNode, data.modifierNodeSrcAttr );
 
    MPlug meshDestAttr( data.meshNodeShape, data.meshNodeDestAttr );
 
    status = fDGModifier.connect( modifierSrcPlug, meshDestAttr );
    MCheckStatus( status, "modifier-mesh connect failed" );
    
    status = fDGModifier.doIt();
    return status;
}
MStatus polyModifierCmd::cacheMeshData()
 
{
    MObject meshNode = fDagPath.node();
 
    MPlug dupMeshNodeOutMeshPlug;
 
    
    
    dupMeshNodeOutMeshPlug = depNodeFn.
findPlug( 
"outMesh", &status );
    MCheckStatus( status, "Could not retrieve outMesh" );
    
    
    status = dupMeshNodeOutMeshPlug.
getValue( fMeshData );
    MCheckStatus( status, "Could not retrieve meshData" );
    
    
    return status;
}
MStatus polyModifierCmd::cacheMeshTweaks()
 
{
    
    
    fTweakIndexArray.clear();
    fTweakVectorArray.clear();
    
    
    if( fHasTweaks )
    {
        
        
        MObject meshNode = fDagPath.node();
 
        
        
        unsigned i;
        meshTweakPlug = depNodeFn.
findPlug( 
"pnts" );
        
        
        MStatusAssert( (meshTweakPlug.
isArray()),
                       "meshTweakPlug.isArray() -- meshTweakPlug is not an array plug" );
        
        
        for( i = 0; i < numElements; i++ )
        {
            
            
            
            
            
            
            
            {
                
                
                
                
                getFloat3PlugValue( tweak, tweakVector );
                fTweakIndexArray.append( logicalIndex );
                fTweakVectorArray.append( tweakVector );
            }
        }
    }
    return status;
}
MStatus polyModifierCmd::undoCachedMesh()
 
{
    
    
    
    MStatusAssert( (fHasRecordHistory), "fHasRecordHistory == true" );
    if( !fHasHistory )
    {
        MPlug   meshNodeOutMeshPlug;
 
        MPlug   dupMeshNodeSrcPlug;
 
        meshNodeShape = fDagPath.node();
        dupMeshNodeShape = fDuplicateDagPath.node();
        meshNodeName = depNodeFn.
name();
        meshNodeDestPlug = depNodeFn.
findPlug( 
"inMesh", &status );
        MCheckStatus( status, "Could not retrieve inMesh" );
        meshNodeOutMeshPlug = depNodeFn.
findPlug( 
"outMesh", &status );
        MCheckStatus( status, "Could not retrieve outMesh" );
        dupMeshNodeSrcPlug = depNodeFn.
findPlug( 
"outMesh", &status );
        MCheckStatus( status, "Could not retrieve outMesh" );
        
        
        
        
        
        
        
        
        if( fHasTweaks )
        {
            dgModifier.
connect( dupMeshNodeSrcPlug, meshNodeDestPlug );
            status = dgModifier.
doIt();
            MCheckStatus( status, "Could not connect dupMeshNode -> meshNode" );
            
            
            cmd += meshNodeName;
            cmd += ".inMesh";
            MCheckStatus( status, "Could not force DG eval" );
            
            
        }
        else
        {
            status = dupMeshNodeSrcPlug.
getValue( meshData );
            MCheckStatus( status, "Could not retrieve meshData" );
            status = meshNodeOutMeshPlug.
setValue( meshData );
            MCheckStatus( status, "Could not set outMesh" );
        }
    }
    return status;
}
MStatus polyModifierCmd::undoTweakProcessing()
 
{
    if( fHasTweaks )
    {
        meshNodeShape = fDagPath.node();
        meshTweakPlug = depNodeFn.
findPlug( 
"pnts" );
        MStatusAssert( (meshTweakPlug.
isArray()),
                       "meshTweakPlug.isArray() -- meshTweakPlug is not an array plug" );
        unsigned i;
        unsigned numElements = fTweakIndexArray.length();
        for( i = 0; i < numElements; i++ )
        {
            getFloat3asMObject( fTweakVectorArray[i], tweakData );
        }
        
        
        
    }
    return status;
}
MStatus polyModifierCmd::undoDirectModifier()
 
{
    MObject meshNode = fDagPath.node();
 
    
    
    
    
    
    
    
    
    
    
    if( fHasTweaks )
    {
        
        
        MPlug meshNodeInMeshPlug = depNodeFn.
findPlug( 
"inMesh", &status );
 
        MCheckStatus( status, "Could not retrieve inMesh" );
        
        
        
        
        
        
        
        
        MPlug dupMeshNodeOutMeshPlug = depNodeFn.
findPlug( 
"outMesh", &status );
 
        MCheckStatus( status, "Could not retrieve outMesh" );
        status = dupMeshNodeOutMeshPlug.
setValue( fMeshData );
        
        
        dgModifier.
connect( dupMeshNodeOutMeshPlug, meshNodeInMeshPlug );
        status = dgModifier.
doIt();
        MCheckStatus( status, "Could not connect dupMeshNode -> meshNode" );
        
        
        cmd += meshNodeName;
        cmd += ".inMesh";
        MCheckStatus( status, "Could not force DG eval" );
        
        
        
        
        status = undoTweakProcessing();
    }
    else
    {
        
        
        
        MPlug meshNodeOutMeshPlug = depNodeFn.
findPlug( 
"outMesh", &status );
 
        MCheckStatus( status, "Could not retrieve outMesh" );
        status = meshNodeOutMeshPlug.
setValue( fMeshData );
        MCheckStatus( status, "Could not set meshData" );
    }
    return status;
}
{
    
    
    
    
    numDataFn.getData( value[0], value[1], value[2] );
}
{
    
    
    numDataFn.
setData( value[0], value[1], value[2] );
}