#include "squareScaleManip.h"
#include <maya/MHardwareRenderer.h>
#include <maya/MIOStream.h>
#include <maya/MMatrix.h>
#include <maya/MPoint.h>
#include <maya/MVector.h>
#include <maya/MSelectionList.h>
#include <maya/MItSelectionList.h>
#include <maya/MFnTransform.h>
#include <maya/MGlobal.h>
#include <maya/MFnCamera.h>
#include <maya/MTemplateCommand.h>
MTypeId squareScaleManipulator::id( 0x81046 );
class squareGeometry
{
public:
        static MPoint topLeft() {
                return MPoint( -0.5f, 0.5f, 0.0f );
        }
        static MPoint topRight() {
                return MPoint( 0.5f, 0.5f, 0.0f );
        }
        static MPoint bottomLeft() {
                return MPoint( -0.5f, -0.5f, 0.0f );
        }
        static MPoint bottomRight() {
                return MPoint( 0.5f, -0.5f, 0.0f );
        }
};
squareScaleManipulator::squareScaleManipulator()
{
        
        
        MPoint pointOnPlane(squareGeometry::topLeft());
        
        MVector normalToPlane = (MVector(squareGeometry::topLeft()) - MVector(squareGeometry::topRight())) ^ 
                                        (MVector(squareGeometry::topRight()) - MVector(squareGeometry::bottomRight()));
        
        normalToPlane.normalize();
        
        plane.setPlane( pointOnPlane, normalToPlane );
}
squareScaleManipulator::~squareScaleManipulator()
{
        
}
void squareScaleManipulator::draw(M3dView &view, const MDagPath &path,
                                M3dView::DisplayStyle style, M3dView::DisplayStatus status)
{
        
        static MGLFunctionTable *gGLFT = 0;
        if ( 0 == gGLFT )
                gGLFT = MHardwareRenderer::theRenderer()->glFunctionTable();
        
        MDagPath dpath;
        view.getCamera(dpath);
        MFnCamera viewCamera(dpath);
        const char *nameBuffer = viewCamera.name().asChar();
        if ( 0 == nameBuffer )
                return;
        if ( ( 0 == strstr(nameBuffer,"persp") ) && ( 0 == strstr(nameBuffer,"front") ) )
                return;
        
        float tl[4],tr[4],br[4],bl[4];
        squareGeometry::topLeft().get(tl);
        squareGeometry::topRight().get(tr);
        squareGeometry::bottomLeft().get(bl);
        squareGeometry::bottomRight().get(br);
        
        
        
        MGLuint active = 0;
        if ( glActiveName( active ) )
        {
                float *a = 0,*b = 0;
                if ( active == topName )
                {
                        a = &tl[0]; b = &tr[0];
                }
                if ( active == bottomName )
                {
                        a = &bl[0]; b = &br[0];
                }
                if ( active == rightName )
                {
                        a = &tr[0]; b = &br[0];
                }
                if ( active == leftName )
                {
                        a = &tl[0]; b = &bl[0];
                }
                if ( active != 0 )
                {
                        a[0] += (float) mousePointGlName.x; a[1] += (float) mousePointGlName.y; a[2] += (float) mousePointGlName.z;
                        b[0] += (float) mousePointGlName.x; b[1] += (float) mousePointGlName.y; b[2] += (float) mousePointGlName.z;
                }
        }
        
        view.beginGL();
        
        MGLuint glPickableItem;
        glFirstHandle( glPickableItem );
        
        topName = glPickableItem;
        
        
        colorAndName( view, glPickableItem, true, mainColor() );
        gGLFT->glBegin( MGL_LINES );
                gGLFT->glVertex3fv( tl );
                gGLFT->glVertex3fv( tr );
        gGLFT->glEnd();
        
        glPickableItem++;
        rightName = glPickableItem;
        colorAndName( view, glPickableItem, true, mainColor() );
        gGLFT->glBegin( MGL_LINES );
                gGLFT->glVertex3fv( tr );
                gGLFT->glVertex3fv( br );
        gGLFT->glEnd();
        
        glPickableItem++;
        bottomName = glPickableItem;
        colorAndName( view, glPickableItem, true, mainColor() );
        gGLFT->glBegin( MGL_LINES );
                gGLFT->glVertex3fv( br );
                gGLFT->glVertex3fv( bl );
        gGLFT->glEnd();
        
        glPickableItem++;
        leftName = glPickableItem;
        colorAndName( view, glPickableItem, true, mainColor() );
        gGLFT->glBegin( MGL_LINES );
                gGLFT->glVertex3fv( bl );
                gGLFT->glVertex3fv( tl );
        gGLFT->glEnd();
        
        view.endGL();
}
MStatus squareScaleManipulator::doPress( M3dView& view )
{
        
        
        mousePointGlName = MPoint::origin;
        updateDragInformation();
        return MS::kSuccess;
}
MStatus squareScaleManipulator::doDrag( M3dView& view )
{
        updateDragInformation();        
        return MS::kSuccess;
}
 MStatus squareScaleManipulator::doRelease( M3dView& view )
{
        
        
        MSelectionList list;
        MGlobal::getActiveSelectionList( list );
        for ( MItSelectionList iter( list ); !iter.isDone(); iter.next() ) 
        {
                MObject node;
                MStatus status;
                iter.getDependNode( node );
                MFnTransform xform( node, &status );
                if ( MS::kSuccess == status )
                {
                        double newScale[3];
                        newScale[0] = mousePointGlName.x + 1;
                        newScale[1] = mousePointGlName.y + 1;
                        newScale[2] = mousePointGlName.z + 1;
                        xform.setScale( newScale );
                }
        }
        return MS::kSuccess;
}
MStatus squareScaleManipulator::updateDragInformation()
{
        
        MPoint localMousePoint;
        MVector localMouseDirection;
        if ( MS::kFailure == mouseRay( localMousePoint, localMouseDirection) )
                return MS::kFailure;
        
        
        MPoint mouseIntersectionWithManipPlane;
        if ( ! plane.intersect( localMousePoint, localMouseDirection,   mouseIntersectionWithManipPlane ) )
                return MS::kFailure;
        mousePointGlName = mouseIntersectionWithManipPlane;
        MGLuint active = 0;
        if ( glActiveName( active ) )
        {
                float start[4],end[4];
                if ( active == topName )
                {
                        squareGeometry::topLeft().get(start);
                        squareGeometry::topRight().get(end);
                }
                if ( active == bottomName )
                {
                        squareGeometry::bottomLeft().get(start);
                        squareGeometry::bottomRight().get(end);
                }
                if ( active == rightName )
                {
                        squareGeometry::topRight().get(start);
                        squareGeometry::bottomRight().get(end);
                }
                if ( active == leftName )
                {
                        squareGeometry::topLeft().get(start);
                        squareGeometry::bottomLeft().get(end);
                }
                if ( active != 0 )
                {
                        lineMath line;
                        
                        MPoint a( start[0], start[1], start[2] );
                        MPoint b( end[0], end[1], end[2] );
                        MPoint vab = a - b;
                        
                        line.setLine( start, vab );
                        MPoint cpt;
                        
                        
                        if ( line.closestPoint( mousePointGlName, cpt ) )
                        {
                                mousePointGlName.x -= cpt.x;
                                mousePointGlName.y -= cpt.y;
                                mousePointGlName.z -= cpt.z;
                        }
                }
        }
        return MS::kSuccess;
}
class squareManipCmd;
char cmdName[] = "squareManipCmd";
char nodeName[] = "squareScaleManipulator";
class squareManipCmd : public MTemplateCreateNodeCommand<squareManipCmd,cmdName,nodeName>
{
public:
        
        squareManipCmd()
        {}
};
static squareManipCmd _squareManipCmd;
void* squareScaleManipulator::creator()
{
        return new squareScaleManipulator();
}
MStatus squareScaleManipulator::initialize()
{
        
        return MS::kSuccess;
}
MStatus initializePlugin( MObject obj )
{ 
        MStatus   status;
        MFnPlugin plugin( obj, PLUGIN_COMPANY, "2009", "Any");
        status = plugin.registerNode( nodeName, squareScaleManipulator::id, squareScaleManipulator::creator,
                squareScaleManipulator::initialize, MPxNode::kManipulatorNode );
        if (!status) {
                status.perror("registerNode");
                return status;
        }
        status = _squareManipCmd.registerCommand( obj );
        if (!status) {
                status.perror("registerCommand");
                return status;
        }
        return status;
}
MStatus uninitializePlugin( MObject obj )
{
        MStatus   status;
        MFnPlugin plugin( obj );
        status = plugin.deregisterNode( squareScaleManipulator::id );
        if (!status) {
                status.perror("deregisterNode");
                return status;
        }
        status = _squareManipCmd.deregisterCommand( obj );
        if (!status) {
                status.perror("deregisterCommand");
                return status;
        }
        return status;
}