/*
 * BasicTutorial7.cpp
 *
 *  Created on: Feb 9, 2011
 *      Author: cpresser
 */

#include "BasicTutorial7.h"

//Ogre::Degree BasicTutorial7::ANGLE_CHANGE(5);

/*
//adapted from code from http://www.codeguru.com/forum/showthread.php?t=231054

//works with a string type S and a number type N
template <class N>
bool fromString(const char *from, N &to){
        std::istringstream stream(from);

        stream >> to;

        //if the conversion didn't work, return false
        return !stream.fail();
}


*/

CEGUI::MouseButton convertButton(OIS::MouseButtonID buttonID)
{
    switch (buttonID)
    {
    case OIS::MB_Left:
        return CEGUI::LeftButton;

    case OIS::MB_Right:
        return CEGUI::RightButton;

    case OIS::MB_Middle:
        return CEGUI::MiddleButton;

    default:
        return CEGUI::LeftButton;
    }
}

CEGUI::Window *createGUIObject(CEGUI::Window *parent,
                CEGUI::String name, CEGUI::String type, CEGUI::String text,
                float x, float y, float w, float h){

        CEGUI::WindowManager &wmgr = CEGUI::WindowManager::getSingleton();
        CEGUI::Window *window = wmgr.createWindow(type, name);
        window->setText(text);
        //window->setSize(CEGUI::UVector2(CEGUI::UDim(w, 0), CEGUI::UDim(h, 0)));
    window->setSize(CEGUI::USize(CEGUI::UDim(w, 0), CEGUI::UDim(h, 0)));
        window->setPosition(CEGUI::UVector2(CEGUI::UDim(x, 0), CEGUI::UDim(y, 0)));
        //parent->addChildWindow(window);
    parent->addChild(window);

        return window;
}

//-------------------------------------------------------------------------------------
BasicTutorial7::BasicTutorial7(void):
                m_overEdit(false),
                m_animState(0),
                m_pitch(0),
                m_yaw(0),
                m_roll(0)
{
}
//-------------------------------------------------------------------------------------
BasicTutorial7::~BasicTutorial7(void)
{
}
//-------------------------------------------------------------------------------------
void BasicTutorial7::createScene(void)
{
        //need something to see

        m_obj.init(mSceneMgr, "Object", Ogre::Vector3(0,0,0), "robot.mesh");

        //need a light
        mSceneMgr->setAmbientLight(Ogre::ColourValue(0.25, 0.25, 0.25));


        // create the light
        Ogre::Light *light = mSceneMgr->createLight("Light1");
        light->setType(Ogre::Light::LT_POINT);
        light->setPosition(Ogre::Vector3(0, 150, 250));
        light->setDiffuseColour(Ogre::ColourValue::White);
        light->setSpecularColour(Ogre::ColourValue::White);


        mRenderer = &CEGUI::OgreRenderer::bootstrapSystem();

        //CEGUI::Imageset::setDefaultResourceGroup("Imagesets");
    CEGUI::ImageManager::setImagesetDefaultResourceGroup("Imagesets");
        CEGUI::Font::setDefaultResourceGroup("Fonts");
        CEGUI::Scheme::setDefaultResourceGroup("Schemes");
        CEGUI::WidgetLookManager::setDefaultResourceGroup("LookNFeel");
        CEGUI::WindowManager::setDefaultResourceGroup("Layouts");

        //CEGUI::SchemeManager::getSingleton().create("TaharezLook.scheme");
    CEGUI::SchemeManager::getSingleton().createFromFile("TaharezLook.scheme");

        //CEGUI::System::getSingleton().setDefaultMouseCursor("TaharezLook", "MouseArrow");
    CEGUI::System::getSingleton().getDefaultGUIContext().getMouseCursor().
        setDefaultImage("TaharezLook/MouseArrow");



        CEGUI::WindowManager &wmgr = CEGUI::WindowManager::getSingleton();
        CEGUI::Window *sheet = wmgr.createWindow("DefaultWindow", "Sheet");
        //sheet->setPosition(CEGUI::UVector2(CEGUI::UDim(.25,0), CEGUI::UDim(.25,0)));
        //sheet->setSize(CEGUI::UVector2(CEGUI::UDim(.5,0), CEGUI::UDim(.5,0)));

        CEGUI::Window *quit = createGUIObject(sheet, "QuitButton",
                        "TaharezLook/Button", "Quit",
                        0.85, 0.9, 0.15, 0.05);

        CEGUI::Window *meshLabel = createGUIObject(sheet, "MeshLabel",
                        "TaharezLook/StaticText", "Mesh",
                        0, 0.9, 0.15, 0.05);

        CEGUI::Window *actionLabel = createGUIObject(sheet, "ActionLabel",
                        "TaharezLook/StaticText", "Action",
                        0, 0, 0.15, 0.05);

        CEGUI::Window *meshBox = createGUIObject(sheet, "MeshBox",
                        "TaharezLook/Editbox", "robot.mesh",
                        0.15, 0.9, 0.4, 0.05);

        CEGUI::Combobox *actionBox =
                        static_cast<CEGUI::Combobox *>(createGUIObject(sheet, "ActionBox",
                        "TaharezLook/Combobox", "",
                        0.15, 0, 0.6, 0.25));
        actionBox->setReadOnly(true);

        CEGUI::Window *open = createGUIObject(sheet, "OpenButton",
                        "TaharezLook/Button", "Open",
                        0.65, 0.9, 0.15, 0.05);

        CEGUI::Window *status = createGUIObject(sheet, "StatusText",
                        "TaharezLook/StaticText", "",
                        0, 0.95, 1, 0.05);


        //CEGUI::System::getSingleton().setGUISheet(sheet);
    CEGUI::System::getSingleton().getDefaultGUIContext().setRootWindow(sheet);

        //register event with a call back function
        quit->subscribeEvent(CEGUI::PushButton::EventClicked, 
                CEGUI::Event::Subscriber(&BasicTutorial7::quit, this));
        open->subscribeEvent(CEGUI::PushButton::EventClicked, 
                CEGUI::Event::Subscriber(&BasicTutorial7::openMesh, this));
        actionBox->subscribeEvent(CEGUI::Combobox::EventListSelectionAccepted,
                        CEGUI::Event::Subscriber(&BasicTutorial7::selectItem, this));
        //meshBox->subscribeEvent(CEGUI::Editbox::EventMouseEnters, 
                CEGUI::Event::Subscriber(&BasicTutorial7::mouseEnters, this));
    //meshBox->subscribeEvent(CEGUI::Editbox::EventMouseLeaves, 
        CEGUI::Event::Subscriber(&BasicTutorial7::mouseLeaves, this));
    meshBox->subscribeEvent(CEGUI::Editbox::EventMouseEntersArea, 
        CEGUI::Event::Subscriber(&BasicTutorial7::mouseEnters, this));
    meshBox->subscribeEvent(CEGUI::Editbox::EventMouseLeavesArea, 
        CEGUI::Event::Subscriber(&BasicTutorial7::mouseLeaves, this));
}
//-------------------------------------------------------------------------------------
void BasicTutorial7::createFrameListener(void)
{
    Ogre::LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
    OIS::ParamList pl;
    size_t windowHnd = 0;
    std::ostringstream windowHndStr;

    mWindow->getCustomAttribute("WINDOW", &windowHnd);
    windowHndStr << windowHnd;
    pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));

    mInputManager = OIS::InputManager::createInputSystem( pl );

    mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( 
        OIS::OISKeyboard, true ));
    mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( 
        OIS::OISMouse, true ));

    mMouse->setEventCallback(this);
    mKeyboard->setEventCallback(this);

    //Set initial mouse clipping size
    windowResized(mWindow);

    //Register as a Window listener
    Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this);

    mRoot->addFrameListener(this);

}
//-------------------------------------------------------------------------------------
bool BasicTutorial7::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
    if(mWindow->isClosed())
        return false;

    if(mShutDown)
        return false;

    //Need to capture/update each device
    mKeyboard->capture();
    mMouse->capture();

        //update the camera, man.
        mCameraMan->frameRenderingQueued(evt);

        Ogre::SceneNode *node = m_obj.getSceneNode();
        node->pitch(evt.timeSinceLastFrame*m_pitch);
        node->yaw(evt.timeSinceLastFrame*m_yaw);
        node->roll(evt.timeSinceLastFrame*m_roll);

        if(m_animState){
                m_animState->addTime(evt.timeSinceLastFrame);
        }
    return true;

}
//-------------------------------------------------------------------------------------
bool BasicTutorial7::keyPressed( const OIS::KeyEvent &arg )
{

        if(m_overEdit){
                CEGUI::System &sys = CEGUI::System::getSingleton();
                //sys.injectKeyDown(arg.key);
        //sys.injectChar(arg.text);
        sys.getDefaultGUIContext().injectKeyDown((CEGUI::Key::Scan)arg.key);
        sys.getDefaultGUIContext().injectChar((CEGUI::Key::Scan)arg.text);
        }
        else {
                switch(arg.key){
                case OIS::KC_I:
                        m_pitch = -ANGLE_CHANGE;
                        break;
                case OIS::KC_K:
                        m_pitch = ANGLE_CHANGE;
                        break;
                case OIS::KC_J:
                        m_yaw = -ANGLE_CHANGE;
                        break;
                case OIS::KC_L:
                        m_yaw = ANGLE_CHANGE;
                        break;
                case OIS::KC_U:
                        m_roll = ANGLE_CHANGE;
                        break;
                case OIS::KC_O:
                        m_roll = -ANGLE_CHANGE;
                        break;
                default:
                        break;
                }

                mCameraMan->injectKeyDown(arg);
        }
        return true;
}
//-------------------------------------------------------------------------------------
bool BasicTutorial7::keyReleased( const OIS::KeyEvent &arg )
{
        if(m_overEdit){
                CEGUI::System::getSingleton().getDefaultGUIContext().
                        injectKeyUp((CEGUI::Key::Scan)arg.key);
        }
        else {
                switch(arg.key){
                case OIS::KC_I:
                        m_pitch = 0;
                        break;
                case OIS::KC_K:
                        m_pitch = 0;
                        break;
                case OIS::KC_J:
                        m_yaw = 0;
                        break;
                case OIS::KC_L:
                        m_yaw = 0;
                        break;
                case OIS::KC_U:
                        m_roll = 0;
                        break;
                case OIS::KC_O:
                        m_roll = 0;
                        break;
                default:
                        break;
                }
                mCameraMan->injectKeyUp(arg);
        }
        return true;
}
//-------------------------------------------------------------------------------------
bool BasicTutorial7::mouseMoved( const OIS::MouseEvent &arg )
{
        if (arg.state.buttonDown(OIS::MB_Right))
        {

            mCameraMan->injectMouseMove(arg);
        }
        CEGUI::System &sys = CEGUI::System::getSingleton();
        sys.getDefaultGUIContext().injectMouseMove(arg.state.X.rel, arg.state.Y.rel);
        // Scroll wheel.
        if (arg.state.Z.rel)
            sys.getDefaultGUIContext().injectMouseWheelChange(arg.state.Z.rel / 120.0f);
        return true;
}
//-------------------------------------------------------------------------------------
bool BasicTutorial7::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
        CEGUI::System::getSingleton().getDefaultGUIContext().
                injectMouseButtonDown(convertButton(id));
        return true;
}
//-------------------------------------------------------------------------------------
bool BasicTutorial7::mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
        CEGUI::System::getSingleton().getDefaultGUIContext().
                injectMouseButtonUp(convertButton(id));
        return true;
}
//-------------------------------------------------------------------------------------
bool BasicTutorial7::quit(const CEGUI::EventArgs &e)
{
        mShutDown = true;
        return true;
}

//-------------------------------------------------------------------------------------
bool BasicTutorial7::openMesh(const CEGUI::EventArgs &e)
{

        CEGUI::WindowManager &wmgr = CEGUI::WindowManager::getSingleton();
    CEGUI::Window *guiRoot = CEGUI::System::getSingleton().getDefaultGUIContext().
        getRootWindow();
    
        //CEGUI::Editbox *meshBox = static_cast<CEGUI::Editbox *>(wmgr.getWindow("MeshBox"));
        //CEGUI::Window *status = wmgr.getWindow("StatusText");
        //CEGUI::Combobox *actionBox =
        //              static_cast<CEGUI::Combobox *>(wmgr.getWindow("ActionBox"));
    
    CEGUI::Editbox *meshBox = static_cast<CEGUI::Editbox *>(guiRoot->getChild("MeshBox"));
    CEGUI::Window *status = guiRoot->getChild("StatusText");
    CEGUI::Combobox *actionBox =
    static_cast<CEGUI::Combobox *>(guiRoot->getChild("ActionBox"));

        //get rid of old mesh
        m_obj.setInScene(false);

        GameObject oldObj = m_obj;
        try {
                //open new mesh
                m_obj = GameObject();

                std::stringstream str;
                str << m_objNum;
                m_objNum++;
                Ogre::String oStr("Object" + str.str());
                m_obj.init(mSceneMgr, oStr, Ogre::Vector3(0,0,0), meshBox->getText().c_str());
                status->setText("Object loaded");
                m_animState = 0;

                //fill combo box with actions?
                actionBox->resetList();

                //iterate through the animation states and put their names in the combo box
                Ogre::AnimationStateSet *states = m_obj.getEntity()->getAllAnimationStates();
                if(states){
                        Ogre::AnimationStateIterator iter = states->getAnimationStateIterator();
                        //Ogre::AnimationState &state = iter.begin();
                        while(iter.hasMoreElements()){
                                std::cerr << iter.peekNextKey() << std::endl;
                                actionBox->addItem(new CEGUI::ListboxTextItem(iter.peekNextKey()));
                                iter.moveNext();
                        }
                }

        }
        //catch(...){
        catch(Ogre::Exception e){
                CEGUI::String msg = "Unable to load ";
                msg += meshBox->getText();
                status->setText(msg);
                m_obj = oldObj;
                std::cerr << e.getDescription() << std::endl;
        }
        return true;
}

//-------------------------------------------------------------------------------------
bool BasicTutorial7::selectItem(const CEGUI::EventArgs &e)
{
        //CEGUI::WindowManager &wmgr = CEGUI::WindowManager::getSingleton();

        //CEGUI::Window *status = wmgr.getWindow("StatusText");
        //CEGUI::Combobox *actionBox =
        //              static_cast<CEGUI::Combobox *>(wmgr.getWindow("ActionBox"));

    
    CEGUI::Window *guiRoot = CEGUI::System::getSingleton().getDefaultGUIContext().
        getRootWindow();
    
    CEGUI::Window *status = guiRoot->getChild("StatusText");
    CEGUI::Combobox *actionBox =
    static_cast<CEGUI::Combobox *>(guiRoot->getChild("ActionBox"));
    
        //get the thing that is selected

        CEGUI::ListboxItem *item = actionBox->getSelectedItem();
        if(item){
                if(item->getText() != ""){
                        if(m_animState){
                                m_animState->setEnabled(false);
                        }
                        m_animState = m_obj.getEntity()->getAnimationState(item->getText().c_str());
                        if(m_animState){
                                m_animState->setLoop(true);
                                m_animState->setEnabled(true);
                        }
                }
                else {
                        m_animState = 0;
                }
        }


        return true;
}

bool BasicTutorial7::mouseEnters(const CEGUI::EventArgs &e)
{
        m_overEdit = true;
        return true;
}

bool BasicTutorial7::mouseLeaves(const CEGUI::EventArgs &e)
{
        m_overEdit = false;
        return true;
}