#include <stdio.h>
#include <malloc.h>
#include "dms/Object.h"

namespace dms
{

Object::Object(void)
    {
    material_ = 0;
    texture_ = 0;
    transparency_ = 0;
    transform_ = 0;
    parent_ = 0;
    numChildren_ = 0;
    maxChildren_ = 16;
    children_ = (Object **) malloc(maxChildren_ * sizeof(Object *));
    drawFunc_ = 0;
    drawData_ = 0;
    updateFunc_ = 0;
    updateData_ = 0;
    }


Object::~Object(void)
    {
    }


void Object::drawAll(void)
    {
    if (transform_)
        transform_->pushApply();
    if (material_)
        material_->apply();
    if (texture_)
        texture_->apply();
    if (transparency_)
        transparency_->apply();
    draw();
    if (transparency_)
        transparency_->disable();
    if (texture_)
        texture_->disable();
    if (material_)
        material_->disable();
    for (int i=0; i < numChildren_; i++)
        children_[i]->drawAll();
    if (transform_)
        transform_->pop();
    }


void Object::updateAll(void)
    {
    update();
    for (int i=0; i < numChildren_; i++)
        children_[i]->updateAll();
    }


void Object::draw(void)
    {
    if (drawFunc_)
        (*drawFunc_)(*this,drawData_);
    }


void Object::update(void)
    {
    if (updateFunc_)
        (*updateFunc_)(*this,updateData_);
    }


void Object::setTransform(Transform& t)
    {
    transform_ = &t;
    }


void Object::setMaterial(Material& m)
    {
    material_ = &m;
    }


void Object::setTexture(Texture& t)
    {
    texture_ = &t;
    }


void Object::setTransparency(Transparency& t)
    {
    transparency_ = &t;
    }


/* Ideally I would've just used an STL vector, but I've had bad experiences
   with STL lately, so I'm avoiding it. */
void Object::attach(Object& child)
    {
    if (numChildren_ == maxChildren_)
        {
        maxChildren_ *= 2;
        Object ** newchildren = (Object **)
                        realloc(children_, maxChildren_ * sizeof(Object *));
        if (newchildren)
            children_ = newchildren;
        else
            {
            cerr << "ERROR: Object::attach() failed to realloc space for "
                 << maxChildren_ << " children\n";
            perror("realloc");
            maxChildren_ /= 2;
            return;
            }
        }
    if (child.parent_)
        child.parent_->detach(child);
    child.parent_ = this;
    children_[numChildren_] = &child;
    numChildren_++;
    }


void Object::detach(Object& child)
    {
    int i;
    for (i=0; i < numChildren_; i++)
        if (children_[i] == &child)
            {
            child.parent_ = 0;
            for (; i < numChildren_-1; i++)
                children_[i] = children_[i+1];
            numChildren_--;
            break;
            }
    }


int Object::numChildren(void)
    {
    return numChildren_;
    }


Object& Object::child(int n)
    {
    if ((n < 0) || (n >= numChildren_))
        return *this;
    return *(children_[n]);
    }


void Object::setDrawCallback(CallbackFunc drawfunc,void *drawdata)
    {
    drawFunc_ = drawfunc;
    drawData_ = drawdata;
    }


void Object::setUpdateCallback(CallbackFunc updatefunc,void *updatedata)
    {
    updateFunc_ = updatefunc;
    updateData_ = updatedata;
    }


}
