//===========================================================================//
// File:	falltool.cpp                                                 
// Project: MechWarrior 4
// Contents: Plugin to modify mech falling animations
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 05/26/99  jkyle  Initial coding, 
//---------------------------------------------------------------------------//
// Copyright (C) 1999, Fasa Interactive, Inc.
// All Rights reserved worldwide
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL
//===========================================================================//


#include "stdafx.h"

#ifdef STRICT							// Already defined by stdafx,
#undef STRICT							// so we avoid warning linking msg
#endif
#ifdef _MBCS							// The same as above
#undef _MBCS
#endif


#include "FallTool.hpp"



#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


//////////////////////////////////////////////////////////////////////
// ProtoTypes
int NegateKeys(Control *pControl,int key_number = 0);
int SwapKeys(Control *pCtrl1,Control *pCtrl2,int key_number = 0);

//////////////////////////////////////////////////////////////////////
// Global Variables
FallToolPanel g_fallToolPanel;


////////////////////////////////////////////////////////////////////////////////
// FallToolPanel Dialog Procedure to handle User and System Interactions
static BOOL CALLBACK FallToolPanelProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    
    switch (msg) {
    case WM_INITDIALOG:						//Panel's extra initialization
        g_fallToolPanel.Init(hWnd);
        break;
    case WM_DESTROY:						//Panel's extra destruction
        g_fallToolPanel.Destroy(hWnd);
        break;
    case WM_COMMAND :
        switch (LOWORD(wParam)) {			//Handle Panel's controls
        case IDC_ABOUT: {
            CAbout dlg;
            dlg.DoModal();
            break;}
        case IDC_FALLTOOL_FALLLEFT:
            {
                // Spec is reversed
                g_fallToolPanel.m_iFallType = FallToolPanel::FALL_RIGHT;
                break;
            }
        case IDC_FALLTOOL_FALLRIGHT:
            {
                g_fallToolPanel.m_iFallType = FallToolPanel::FALL_LEFT;
                break;
            }
        case IDC_FALLTOOL_FALLBACK:
            {
                g_fallToolPanel.m_iFallType = FallToolPanel::FALL_BACK;
                break;
            }
        case IDC_FALLTOOL_EXECUTE:
            {
                g_fallToolPanel.ExecuteFallTool();
                break;
            }
        }
        break;
        
        ////////////////////////////////////////////////////////////////////////
        //The following lines are not necessary for MAX2 Plugins
        case WM_LBUTTONDOWN:
        case WM_LBUTTONUP:
        case WM_MOUSEMOVE:
            g_fallToolPanel.m_ip->RollupMouseMessage(hWnd, msg, wParam, lParam);
            break;
            ////////////////////////////////////////////////////////////////////////
            
        default:
            return FALSE;
    }
    return TRUE;
}

////////////////////////////////////////////////////////////////////////////////
// Display the Plugin's Panel
void FallToolPanel::BeginEditParams(Interface* ip, IUtil* iu)
{
    m_ip = ip;								//Get the Plugin's Interface
    m_iu = iu;								//Get the Utility Plugin's Interface
    
    //Display the plugin's Rollup Dialog
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    HINSTANCE loc_hInstance = AfxGetResourceHandle ();
    
    m_hPanel = m_ip->AddRollupPage(loc_hInstance, MAKEINTRESOURCE(IDD_FALLTOOL_PANEL),
        FallToolPanelProc, GetString(IDS_FALLTOOL_NAME),0);
    
    
}

////////////////////////////////////////////////////////////////////////////////
// Free the Plugins' Panel
void FallToolPanel::EndEditParams(Interface *ip, IUtil *iu)
{
    m_iu = NULL;
    m_ip = NULL;
    
    //Remove the Rollup Dialog
    ip->DeleteRollupPage(m_hPanel);
    m_hPanel = NULL;
}

////////////////////////////////////////////////////////////////////////////////
// Panel Initialization callback
void FallToolPanel::Init(HWND hWnd)
{
    SendDlgItemMessage(hWnd, IDC_FALLTOOL_FALLLEFT, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
}

////////////////////////////////////////////////////////////////////////////////
// Panel Destruction callback
void FallToolPanel::Destroy(HWND hWnd)
{
}

////////////////////////////////////////////////////////////////////////////////
// Execute the fall tool
int FallToolPanel::ExecuteFallTool()
{
    INode *pjoint_VEL = m_ip->GetINodeByName("joint_VEL");
    INode *pjoint_ROOT = m_ip->GetINodeByName("joint_ROOT");
    INode *phandle_lfoot = m_ip->GetINodeByName("handle_lfoot");
    INode *phandle_rfoot = m_ip->GetINodeByName("handle_rfoot");
    // Make sure we have all of these nodes, or else the model will mess up pretty bad
    if (pjoint_VEL && pjoint_ROOT && phandle_lfoot && phandle_rfoot)
    {
        // Adjust pjoint_VEL
        if (TRUE)
        {
            // Adjust the joint_VEL node
            if (Control *pControl = pjoint_VEL->GetTMController())
            {
                // Adjust the position controllers
                if (Control *pPosControl = pControl->GetPositionController())
                {
                    // Adjust the XPosition Controller
                    Control *pXControl = NULL;
                    
                    if (pXControl = pPosControl->GetXController())
                    {
                        if (IKeyControl *pKeyControl = GetKeyControlInterface(pXControl))
                        {
							if (pKeyControl->GetNumKeys()<1)
								return -1;

                            switch (m_iFallType)
                            {
                            case FALL_LEFT:
                                {
                                    break;
                                }
                            case FALL_RIGHT:
                                {
                                    break;
                                }
                            case FALL_BACK:
                                {
                                    NegateKeys(pXControl);
                                    break;
                                }
                            }
                        }
                    }
                    
                    // Adjust the YPosition Controller
                    if (Control *pYControl = pPosControl->GetYController())
                    {
                        if (IKeyControl *pKeyControl = GetKeyControlInterface(pYControl))
                        {
                            switch (m_iFallType)
                            {
                            case FALL_RIGHT:
                                {
                                    SwapKeys(pYControl,pXControl);
                                    NegateKeys(pXControl);
                                    NegateKeys(pYControl);
                                    break;
                                }
                            case FALL_LEFT:
                                {
                                    SwapKeys(pYControl,pXControl);
                                    // Fall through to negate key
                                }
                            case FALL_BACK:
                                {							
                                    NegateKeys(pYControl);
                                    break;
                                }
                            }
                        }
                    }
                }
                
                // Adjust the rotation controllers
                if (Control *pRotControl = pControl->GetRotationController())
                {
                    // Adjust the ZRotation Controller
                    if (Control *pZControl = pRotControl->GetZController())
                    {
                        if (IKeyControl *pKeyControl = GetKeyControlInterface(pZControl))
                        {
                            float rot = (float)M_PI;
                            switch (m_iFallType)
                            {
                            case FALL_RIGHT:
                                {
                                    rot *= -1.0;
                                }
                            case FALL_LEFT:
                                {
                                    rot /= -2.0;
                                    // Fall through to FALL_BACK
                                }
                            case FALL_BACK:
                                {
                                    IBezFloatKey key;
                                    key.time = 0;
                                    //key.flags = IKEY_ZSEL;
                                    key.val = 0;
                                    key.intan = 0;
                                    key.outtan = 0;
                                    pKeyControl->AppendKey(&key);
                                    Interval iv = m_ip->GetAnimRange();
                                    key.time = iv.End();
                                    key.val = rot;
                                    pKeyControl->AppendKey(&key);
                                    pKeyControl->SortKeys();
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        
        // Adjust the foot nodes - same for both feet
        if (TRUE)
        {
            int foot = 2;
            do
            {
                foot--;
                Control *pControl= NULL;
                if (1==foot)
                    pControl = phandle_lfoot->GetTMController();
                else
                    pControl = phandle_rfoot->GetTMController();
                
                if (pControl)
                {
                    if (Control *pPosControl = pControl->GetPositionController())
                    {
                        //Adjust the XPosition
                        Control *pXControl;
                        if (pXControl = pPosControl->GetXController())
                        {
                            if (IKeyControl *pKeyControl = GetKeyControlInterface(pXControl))
                            {
                                switch (m_iFallType)
                                {
                                case FALL_LEFT:
                                    {
                                        break;
                                    }
                                case FALL_RIGHT:
                                    {
                                        break;
                                    }
                                case FALL_BACK:
                                    {
                                        NegateKeys(pXControl,1);
                                        break;
                                    }
                                }
                            }
                            
                        }
                        
                        //Adjust the YPosition
                        if (Control *pYControl = pPosControl->GetYController())
                        {
                            if (IKeyControl *pKeyControl = GetKeyControlInterface(pYControl))
                            {
                                switch (m_iFallType)
                                {
                                case FALL_RIGHT:
                                    {
                                        NegateKeys(pYControl,1);			
                                    }
                                case FALL_LEFT:
                                    {
                                        // Fall through to negate Y in FALL_BACK
                                        SwapKeys(pYControl,pXControl,1);
                                    }
                                case FALL_BACK:
                                    {
                                        if (m_iFallType != FALL_RIGHT)
                                            NegateKeys(pYControl,1);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    
                    if (Control *pRotControl = pControl->GetRotationController())
                    {
                        //Adjust the ZRotation Controller
                        if (Control *pZControl = pRotControl->GetZController())
                        {
                            if (IKeyControl *pKeyControl = GetKeyControlInterface(pZControl))
                            {
                                float rot = (float)M_PI;
                                switch (m_iFallType)
                                {
                                case FALL_LEFT:
                                    {
                                        rot *= -1.0;
                                    }
                                case FALL_RIGHT:
                                    {
                                        rot /= 2.0;
                                        // Fall through to FALL_BACK
                                    }
                                case FALL_BACK:
                                    {
                                        IBezFloatKey key;
                                        int i;
                                        pKeyControl->GetKey(i = (pKeyControl->GetNumKeys()-1),&key);
                                        key.val += rot;
                                        pKeyControl->SetKey(i,&key);
                                        break;
                                    }
                                }
                            }
                        }
                        
                    }
                }
            } while (foot);
        }
        return 0;
    }
    return -1;
}



int NegateKeys(Control *pControl,int key_number)
{
    int MaxKeys;
    IKeyControl *ikc = GetKeyControlInterface(pControl);
    Class_ID id = pControl->ClassID();
    
    MaxKeys=ikc->GetNumKeys();
    
    for(;key_number<MaxKeys;key_number++)
    {
        if (id == Class_ID(LININTERP_FLOAT_CLASS_ID,0))
        {
            ILinFloatKey key;
            ikc->GetKey(key_number, &key);
            key.val=key.val*-1;
            ikc->SetKey(key_number, &key);
        }
        else if (id == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))
        {
            IBezFloatKey key;
            ikc->GetKey(key_number, &key);
            key.val*=-1;
            key.intan*=-1;
            key.outtan*=-1;
            ikc->SetKey(key_number, &key);
        }
        else if (id == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0))
        {	
            ITCBFloatKey key;
            ikc->GetKey(key_number, &key);
            key.val*=-1;
            ikc->SetKey(key_number, &key);
        }	
        else if (id == Class_ID(LININTERP_POSITION_CLASS_ID,0))
        {
            ILinPoint3Key key;
            ikc->GetKey(key_number, &key);
            key.val.x*=-1;
            key.val.y*=-1;
            key.val.z*=-1;
            ikc->SetKey(key_number, &key);
        }
        else if (id == Class_ID(HYBRIDINTERP_POSITION_CLASS_ID,0))
        {
            IBezPoint3Key key;
            ikc->GetKey(key_number, &key);
            key.val.x*=-1;
            key.intan.x*=-1;
            key.outtan.x*=-1;
            key.val.y*=-1;
            key.intan.y*=-1;
            key.outtan.y*=-1;
            key.val.z*=-1;
            key.intan.z*=-1;
            key.outtan.z*=-1;
            ikc->SetKey(key_number, &key);
        }
        else if (id == Class_ID(TCBINTERP_POSITION_CLASS_ID,0))
        {
            ITCBPoint3Key key;
            ikc->GetKey(key_number, &key);
            key.val.x*=-1;
            key.val.y*=-1;
            key.val.z*=-1;
            ikc->SetKey(key_number, &key);
        }
        else if (id == Class_ID(LININTERP_ROTATION_CLASS_ID,0))
        {
            ILinRotKey key;
            ikc->GetKey(key_number, &key);
            key.val.w*=-1;
            ikc->SetKey(key_number, &key);
        }
        else if (id == Class_ID(HYBRIDINTERP_ROTATION_CLASS_ID,0))
        {
            IBezQuatKey key;
            ikc->GetKey(key_number, &key);
            key.val.w*=-1;
            ikc->SetKey(key_number, &key);
        }
        else if (id == Class_ID(TCBINTERP_ROTATION_CLASS_ID,0))
        {
            ITCBRotKey key;
            ikc->GetKey(key_number, &key);
            key.val.angle*=-1;
            ikc->SetKey(key_number, &key);
        }
        else if (id == Class_ID(HYBRIDINTERP_POINT3_CLASS_ID,0))
        {
            IBezPoint3Key key;
            ikc->GetKey(key_number, &key);
            key.val.x*=-1;
            key.val.y*=-1;
            key.val.z*=-1;
            ikc->SetKey(key_number, &key);
        }
        else if (id == Class_ID(TCBINTERP_POINT3_CLASS_ID,0))
        {
            ITCBPoint3Key key;
            ikc->GetKey(key_number, &key);
            key.val.x*=-1;
            key.val.y*=-1;
            key.val.z*=-1;
            ikc->SetKey(key_number, &key);
        }
    }			// end of for i				
    
    return MaxKeys;
}

static int SwapKeys(Control *pCtrl1,Control *pCtrl2,int key_number)
{
    if (!(pCtrl1 && pCtrl2))
    {
        return 0;
    }
    // Only swap same IDs
    Class_ID id;
    if ((id = pCtrl1->ClassID()) != pCtrl2->ClassID())
        return 1;
    IKeyControl *pKey1 = GetKeyControlInterface(pCtrl1);
    IKeyControl *pKey2 = GetKeyControlInterface(pCtrl2);
    int MaxKeys1 = pKey1->GetNumKeys();
    int MaxKeys2 = pKey2->GetNumKeys();
    
    // First copy all the keys, then delete them from both controls, then append them back
    if (id == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))
    {
        
        IBezFloatKey *keyarr = new IBezFloatKey[MaxKeys1-key_number];
        for (int i=key_number;i<MaxKeys1;i++)
        {
            IBezFloatKey key;
            pKey1->GetKey(i,&keyarr[i-key_number]);
        }
        pKey1->SetNumKeys(key_number);
        for (i=key_number;i<MaxKeys2;i++)
        {
            IBezFloatKey key;
            pKey2->GetKey(i,&key);
            pKey1->AppendKey(&key);
        }
        pKey2->SetNumKeys(key_number);
        for (i=0;i<(MaxKeys1-key_number);i++)
        {
            IBezFloatKey key;
            pKey2->AppendKey(&keyarr[i]);
        }
        
        delete keyarr;
        pKey1->SortKeys();
        pKey2->SortKeys();
    }
    return 0;
}
