#include "precompiled/pchnscene.h"
//------------------------------------------------------------------------------
//  nlodnode_main.cc
//  (C) 2004 RadonLabs GmbH
//------------------------------------------------------------------------------
#include "nscene/nlodnode.h"
#include "nscene/nscenegraph.h"
#include "gfx2/ngfxserver2.h"

nNebulaScriptClass(nLodNode, "ntransformnode");

//------------------------------------------------------------------------------
/**
*/
nLodNode::nLodNode() :
    minDistance(-100.0f),
    maxDistance(100.0f)
{
    this->transformNodeClass = kernelServer->FindClass("ntransformnode");
}

//------------------------------------------------------------------------------
/**
*/
nLodNode::~nLodNode()
{
    // empty
}

//------------------------------------------------------------------------------
/**
    Attach to the scene server.
    FIXME FLOH: NOTE, this method will only be correct if this node and
    its parent nodes are not animated.
*/
void
nLodNode::Attach(nSceneGraph* sceneGraph, nEntityObject* entityObject)
{
    n_assert(sceneGraph);
    n_assert(entityObject);

    if (this->CheckFlags(Active))
    {
        // get camera distance
        const matrix44& viewer = nGfxServer2::Instance()->GetTransform(nGfxServer2::InvView);
        // get global render context position
        const matrix44& transform = sceneGraph->GetModelTransform();

        // compute position by stepping up node hierarchy (Argh)
        /*
        nTransformNode* tNode = this;
        while ((tNode = (nTransformNode*) tNode->GetParent()) && tNode->IsA(this->transformNodeClass))
        {
            transform = transform * tNode->GetTransform();
        }
        */

	    vector3 lodViewer = viewer.pos_component() - transform.pos_component();
        float distance = lodViewer.len();

        if ((distance > this->minDistance) && (distance < this->maxDistance))
        {
            // get number of child nodes
            int num = 0;
            nSceneNode* curChild;
            for (curChild = (nSceneNode*) this->GetHead();
                curChild;
                curChild = (nSceneNode*) curChild->GetSucc())
            {
                if (curChild->IsA(this->transformNodeClass))
                {
                    num++;
                }
            }

            // if there are not enough thresholds, set some default values
            if (!this->thresholds.Size()) 
            {
                thresholds.Append(100.0f);
            }
            while (this->thresholds.Size() < (num - 1))
            {
                this->thresholds.Append(thresholds[this->thresholds.Size()-1] * 2.0f);
            }

            // find the proper child to attach
            int index = 0;
            if (this->GetHead())
            {
                nSceneNode* childToAttach = (nSceneNode*) this->GetHead(); 
                for (curChild = (nSceneNode*) childToAttach->GetSucc();
                    curChild;
                    curChild = (nSceneNode*) curChild->GetSucc(), index++)
                {
                    if (curChild->IsA(this->transformNodeClass))
                    {
                        if (distance >= this->thresholds[index])
                        {
                            childToAttach = curChild;
                        }
                    }
                }     
                childToAttach->Attach(sceneGraph, entityObject);
            }
        }
    }
}
