#include <osg/Notify>
#include <osg/Geometry>
#include <osg/AnimationPath>

#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>

using namespace osg;
using namespace osgDB;


// forward declare functions to use later.
bool  AnimationPath_readLocalData(osg::Object &obj, osgDB::Input &fr);
bool  AnimationPath_writeLocalData(const osg::Object &obj, osgDB::Output &fw);


// register the read and write functions with the osgDB::Registry.
osgDB::RegisterDotOsgWrapperProxy  AnimationPath_Proxy
(
    new osg::AnimationPath,
    "AnimationPath",
    "Object AnimationPath",
    AnimationPath_readLocalData,
    AnimationPath_writeLocalData,
    DotOsgWrapper::READ_AND_WRITE
);


bool AnimationPath_readLocalData(osg::Object &obj, osgDB::Input &fr)
{
    osg::AnimationPath *ap = dynamic_cast<osg::AnimationPath*>(&obj);
    if (!ap) return false;
    
    
    bool itAdvanced = false;

    if (fr[0].matchWord("LoopMode"))
    {
        if (fr[1].matchWord("SWING"))
        {
            ap->setLoopMode(AnimationPath::SWING);
            fr += 2;
            itAdvanced = true;            
        }
        else if (fr[1].matchWord("LOOP"))
        {
            ap->setLoopMode(AnimationPath::LOOP);
            fr += 2;
            itAdvanced = true;                        
        } 
        else if (fr[1].matchWord("NO_LOOPING"))
        {
            ap->setLoopMode(AnimationPath::NO_LOOPING);
            fr += 2;
            itAdvanced = true;                        
        } 
    }



    if (fr.matchSequence("ControlPoints {"))
    {
        int entry = fr[0].getNoNestedBrackets();

        fr += 2;
        

        float time;
        Vec3 position,scale;
        Quat rotation;
        
        while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
        {
            if (fr[0].getFloat(time) &&
                fr[1].getFloat(position[0]) && 
                fr[2].getFloat(position[1]) && 
                fr[3].getFloat(position[2]) &&
                fr[4].getFloat(rotation[0]) && 
                fr[5].getFloat(rotation[1]) && 
                fr[6].getFloat(rotation[2]) &&
                fr[7].getFloat(rotation[3]) &&
                fr[8].getFloat(scale[0]) && 
                fr[9].getFloat(scale[1]) && 
                fr[10].getFloat(scale[2]))
            {


                osg::AnimationPath::ControlPoint ctrlPoint;
                ctrlPoint._position = position;
                ctrlPoint._rotation = rotation;
                ctrlPoint._scale = scale;

                ap->insert(time, ctrlPoint);

                fr+=11; 
            } 
            else fr.advanceOverCurrentFieldOrBlock();

        }

        itAdvanced = true;

    }
    
    return itAdvanced;
}


bool AnimationPath_writeLocalData(const osg::Object &obj, osgDB::Output &fw)
{
    const osg::AnimationPath* ap = dynamic_cast<const osg::AnimationPath*>(&obj);
    if (!ap) return false;

    fw.indent() << "LoopMode ";
    switch(ap->getLoopMode())
    {
        case AnimationPath::SWING:
            fw << "SWING" <<std::endl;
            break;
        case AnimationPath::LOOP:
            fw << "LOOP"<<std::endl;
            break;
        case AnimationPath::NO_LOOPING:
            fw << "NO_LOOPING"<<std::endl;
            break;
    }

    const AnimationPath::TimeControlPointMap& tcpm = ap->getTimeControlPointMap();

    fw.indent() << "ControlPoints {"<< std::endl;
    fw.moveIn();

    for (AnimationPath::TimeControlPointMap::const_iterator itr=tcpm.begin();
         itr!=tcpm.end(); 
         ++itr)
    {
        fw.indent() << itr->first << " " << itr->second._position << " " << itr->second._rotation << " " << itr->second._scale << std::endl;

    }

    fw.moveOut();
    fw.indent() << "}"<< std::endl;

    return true;
}




// forward declare functions to use later.
bool  AnimationPathCallback_readLocalData(osg::Object &obj, osgDB::Input &fr);
bool  AnimationPathCallback_writeLocalData(const osg::Object &obj, osgDB::Output &fw);


// register the read and write functions with the osgDB::Registry.
osgDB::RegisterDotOsgWrapperProxy  AnimationPathCallback_Proxy
(
    new osg::AnimationPathCallback,
    "AnimationPathCallback",
    "Object AnimationPathCallback",
    AnimationPathCallback_readLocalData,
    AnimationPathCallback_writeLocalData,
    DotOsgWrapper::READ_AND_WRITE
);

bool AnimationPathCallback_readLocalData(osg::Object &obj, osgDB::Input &fr)
{
    osg::AnimationPathCallback *apc = dynamic_cast<osg::AnimationPathCallback*>(&obj);
    if (!apc) return false;

    static osg::ref_ptr<osg::AnimationPath> s_path = new osg::AnimationPath;
    ref_ptr<osg::Object> object = fr.readObjectOfType(*s_path);
    osg::AnimationPath* animpath = dynamic_cast<osg::AnimationPath*>(object.get());
    if (animpath) apc->setAnimationPath(animpath);
    
    bool itrAdvanced = object.valid();
    
    return itrAdvanced;
}


bool AnimationPathCallback_writeLocalData(const osg::Object &obj, osgDB::Output &fw)
{
    const osg::AnimationPathCallback* apc = dynamic_cast<const osg::AnimationPathCallback*>(&obj);
    if (!apc) return false;

    if (apc->getAnimationPath())
    {
        fw.writeObject(*(apc->getAnimationPath()));
    }

    return true;
}
