/*
* pathmanager.cpp - author: Keith Fulton <keith@paqrat.com>
*
* Copyright (C) 2003 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) 
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation (version 2 of the License)
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
*/
#include <psconfig.h>

#include <csutil/csstring.h>
#include <iutil/document.h>
#include <csutil/xmltiny.h>
#include <csgeom/vector3.h>

#include "util/log.h"
#include "pathmanager.h"
#include "npcbehave.h"

////////////////////////////////////////////////////////////////////////
void psPath::CalculateAtTime (float time)
{
    spline.Calculate (time+0.1);
    GetInterpolatedPosition(heading);
    spline.Calculate (time);
}

void psPath::GetInterpolatedForward (csVector3& pos)
{
    GetInterpolatedPosition(pos);
    pos = pos - heading;
}

////////////////////////////////////////////////////////////////////////


bool PathManager::Load(iDocumentNode *node)
{
    csRef<iDocumentNodeIterator> iter = node->GetNodes();

    while ( iter->HasNext() )
    {
        csRef<iDocumentNode> node = iter->Next();

        if ( node->GetType() != CS_NODE_ELEMENT )
            continue;

        // This is a widget so read it's factory to create it.
        if ( strcmp( node->GetValue(), "path" ) == 0)
        {
            Spline *spline = new Spline;
            if (spline->Load(node))
            {
                paths.Insert(spline);
            }
            else
            {
                delete spline;
                return false;
            }
        }
    }
    return true;
}

Spline *PathManager::Find(const char *name)
{
    Spline key(name);
    Spline *found = paths.Find(&key);

    return found;
}

csPath *PathManager::CreatePath(const char *name,csVector3& offset,csVector3& startpt)
{
    Spline key(name);
    Spline *found = paths.Find(&key);

    if (found)
    {
        csPath *path = new psPath( found->points.Length() );
        csVector3 *v = new csVector3[found->points.Length()];
        int i;
        for (i=0; i<found->points.Length(); i++)
        {
            v[i] = found->points[i]->pos;
        }
        path->SetPositionVectors(v);

        for (i=0; i<found->points.Length(); i++)
        {
            v[i] = found->points[i]->up;
        }
        path->SetUpVectors(v);
        delete [] v;


        float *f = new float[ found->points.Length() ];
        for (i=0; i<found->points.Length(); i++)
        {
            f[i] = found->points[i]->time_value;
        }
        path->SetTimeValues(f);
        delete [] f;

        return path;
    }
    return NULL;
}

bool Spline::Load(iDocumentNode *node)
{
    name = node->GetAttributeValue("name");
    if (name.Length() == 0)
    {
        Error1("Path does not have a name attribute specified.\n");
        return false;
    }

    sector = node->GetAttributeValue("sector");
    if (name.Length() == 0)
    {
        Error1("Path does not have a sector attribute specified.\n");
        return false;
    }

    constant_vel = node->GetAttributeValueAsFloat("constant_vel");

    csRef<iDocumentNodeIterator> iter = node->GetNodes();

    float time_so_far = 0;
    SplinePoint *last = NULL;

    while ( iter->HasNext() )
    {
        csRef<iDocumentNode> node = iter->Next();

        if ( node->GetType() != CS_NODE_ELEMENT )
            continue;

        // This is a widget so read it's factory to create it.
        if ( strcmp( node->GetValue(), "spline_pt" ) == 0)
        {
            SplinePoint *pt = new SplinePoint;
            pt->pos.x = node->GetAttributeValueAsFloat("x");
            pt->pos.y = node->GetAttributeValueAsFloat("y");
            pt->pos.z = node->GetAttributeValueAsFloat("z");

            pt->up.x = node->GetAttributeValueAsFloat("up_x");
            pt->up.y = node->GetAttributeValueAsFloat("up_y");
            pt->up.z = node->GetAttributeValueAsFloat("up_z");

            if (node->GetAttributeValue("anim"))
                pt->action = node->GetAttributeValue("anim");
            else
                pt->action = "default";

            if (constant_vel)
            {
                if (last)
                {
                    float dist = (last->pos-pt->pos).Norm();
                    time_so_far += (dist/constant_vel);
                    pt->time_value = time_so_far;
                }
                else
                {
                    pt->time_value = 0;
                }
                last = pt;
            }
            else
            {
                pt->time_value = node->GetAttributeValueAsFloat("time");
            }
            points.Push(pt);
        }
    }
    return true;
}

