#include <math.h>
#include <stdlib.h>
#include "SceneGraphRoot.h"
#include "MainLoop.h"
#include "create_task.h"
#include "types.h"
#include "MyFunc.h"
#include "matrix_calc.h"
#include "SgChange.h"

Property *property, *update_property;

// prototype
static void collision(SceneGraphPtr node, void *sgroot_, int screen_w, int screen_h, SceneGraphPtr tree);
static void move(SceneGraphPtr node, void *sgroot_, int screen_w, int screen_h);
static void createSceneGraphFromProperty(SchedTask *s, void *sgroot, void *arg1);
//static void createSceneGraphFromProperty(void *sgroot, void *property_, void *update_property_);
static void set_property(Property *p, SceneGraphPtr sg);
static void regist_task(SceneGraphRoot *sgroot);

static void
move(SceneGraphPtr node, void *sgroot_, int screen_w, int screen_h)
{
    SceneGraphRoot *sgroot = (SceneGraphRoot *)sgroot_;
    //TaskManager *manager = sgroot->tmanager;
    //HTaskPtr property_task = manager->create_task(PropertyTask);
    HTaskPtr property_task = sgroot->move_exec_task;

    property_task->add_inData(property, sizeof(Property));
    property_task->add_outData(update_property, sizeof(Property));

    //property_task->add_inData((Property *)node->property, sizeof(Property));
    //property_task->add_outData((Property *)node->update_property, sizeof(Property));
    property_task->set_cpu(SPE_ANY);
    
    property_task->set_post(createSceneGraphFromProperty, (void *)sgroot, 0);
    property_task->spawn();
}

static void
collision(SceneGraphPtr node, void *sgroot_, int screen_w, int screen_h,
	  SceneGraphPtr tree)
{
}

#if 1
static void
createSceneGraphFromProperty(SchedTask *s, void *sgroot_, void *arg1)
{
    SceneGraphRoot *sgroot = (SceneGraphRoot *)sgroot_;
    SceneGraphPtr node;

    // ここが allExecute の tree をたどって clone して行くところに相当する
    node = sgroot->createSceneGraph(update_property->name);
    //node = sgroot->createSceneGraph("Ball");
    node->set_move_collision(move, collision);
    node->xyz[0] = update_property->xyz[0];
    node->xyz[1] = update_property->xyz[1];
    node->xyz[2] = update_property->xyz[2];

    //float scale[] = {1,1,1};

    // get matrix
    get_matrix(node->matrix, node->angle, node->xyz, sgroot->camera->matrix);
    get_matrix(node->real_matrix, node->angle, node->xyz, sgroot->camera->real_matrix);

    sgroot->setSceneData(node);

    Property *tmp = property;
    property = update_property;
    update_property = tmp;

    sgroot->move_finish();
}
#else
static void
createSceneGraphFromProperty(void *sgroot_, void *property_, void *update_property_)
{
    SceneGraphPtr node;
    SceneGraphRoot *sgroot = (SceneGraphRoot *)sgroot_;
    Property *property = (Property *)property_;
    Property *update_property = (Property *)update_property_;

    node = sgroot->createSceneGraph(update_property->name);
    //node = sgroot->createSceneGraph("Ball");
    //node->set_move_collision(move, collision);
    node->set_move_collision(move, collision, createSceneGraphFromProperty);
    node->xyz[0] = update_property->xyz[0];
    node->xyz[1] = update_property->xyz[1];
    node->xyz[2] = update_property->xyz[2];
    sgroot->setSceneData(node);

    Property *tmp = property;
    property = update_property;
    update_property = tmp;    
}
#endif


static void
regist_task(SceneGraphRoot *sgroot)
{
    TaskManager *manager = sgroot->tmanager;
    HTaskPtr property_task = manager->create_task(PropertyTask);
    sgroot->move_exec_task = property_task;
}




static void
set_property(Property *p, SceneGraphPtr sg)
{
    p->xyz[0] = sg->xyz[0];
    p->xyz[1] = sg->xyz[1];
    p->xyz[2] = sg->xyz[2];
    p->name = sg->name;
}

MainLoopPtr 
create_task::init(Viewer *viewer, int screen_w, int screen_h)
{
    // SgChange を使うための2行
    SgChange *sgroot = new SgChange(viewer);
    sgroot->run_init();
    // 上で書いた regist_task() を登録
    sgroot->sgroot_A->appTaskRegist(regist_task);

    property        = (Property *)sgroot->manager->allocate(sizeof(Property));
    update_property = (Property *)sgroot->manager->allocate(sizeof(Property));
    /*
    Property *property        = (Property *)sgroot->manager->allocate(sizeof(Property));
    Property *update_property = (Property *)sgroot->manager->allocate(sizeof(Property));
    */

    SceneGraphPtr ball;

    sgroot->createFromXMLfile("xml_file/Ball.xml");

    ball = sgroot->createSceneGraph("Ball");
    ball->set_move_collision(move, collision);
    //ball->set_move_collision(move, collision, createSceneGraphFromProperty);

    ball->xyz[0] = screen_w/2;
    ball->xyz[1] = screen_h/2;
    ball->xyz[2] = 30.0f;

    //SceneGraph に property を持たせておく
    ball->property = (memaddr)property;
    ball->update_property = (memaddr)update_property;

    set_property(property, ball);
    
    sgroot->setSceneData(ball);

    return sgroot;
}

extern Application *
application() {
    return new create_task();
}

const char *usr_help_str = "Usage: ./test_nogl [OPTION]\n";

extern int init(TaskManager *manager, int argc, char *argv[]);
extern void task_initialize();
static void TMend(TaskManager *manager);

int
TMmain(TaskManager *manager, int argc, char *argv[])
{
    task_initialize();
    manager->set_TMend(TMend);
    return init(manager, argc, argv);

}

void
TMend(TaskManager *manager)
{
    printf("test_nogl end\n");
}

/* end */
