#ifndef SCENE_H
#define SCENE_H

#include <string>
#include "object.h"
#include "mesh.h"
#include "utils.h"

using namespace std;

class Scene
{
public:

    // return camera
    Camera* camera() { return &_camera; }

    // draw the scene
    void draw(Shader* prog, bool colorPicking=false);

    // return number of object
    uint n_object() { return _objs.size(); }

    // return the i-th object
    Object* object(uint i);

protected:
    Object openObject(const string path);
    virtual void init();

public:
    vector<Object> _objs;

protected:
    Object _frame;
    static Camera _camera;
};



/******** SCENE 1 ********/
class Scene1 : public Scene
{
public:
    Scene1()
    {
        init();
    }

private:
    virtual void init()
    {
        // init parent
        Scene::init();

        // object
        Object obj = openObject(OBJECT_BOX);
        obj.setRenderType(1);
        _objs.push_back(obj);
    }
};

/******** SCENE 2 ********/
class Scene2 : public Scene
{
public:
    Scene2()
    {
        init();
    }

private:
    virtual void init()
    {
        // init parent
        Scene::init();

        // camera
        _camera.setFovY(M_PI/3.);
        _camera.lookAt(Vector3f(1, 1, 1).normalized()*2, Vector3f(0, 0, 0), Vector3f::UnitY());

        // object
        Object obj = openObject(OBJECT_BOX);
        obj.setRenderType(1);
        _objs.push_back(obj);
    }
};

/******** SCENE 3 ********/
class Scene3 : public Scene
{
public:
    Scene3()
    {
        init();
    }

private:
    virtual void init()
    {
        // init parent
        Scene::init();

        // object
        Object obj = openObject(OBJECT_BOX);
        obj.setRenderType(1);
        obj.setTranslation(Translation3f(1, 0, 0));
        obj.setRotation(Affine3f(AngleAxisf(-45*M_PI/180., Vector3f::UnitY())));
        _objs.push_back(obj);
    }
};

/******** SCENE 4 ********/
class Scene4 : public Scene
{
public:
    Scene4()
    {
        init();
    }

private:
    virtual void init()
    {
        // init parent
        Scene::init();

        // object
        Object obj = openObject(OBJECT_BOX);
        obj.setRenderType(1);
        obj.setTranslation(Translation3f(0.2, 0, 0));
        obj.setRotation(Affine3f(AngleAxisf(-12*M_PI/180., Vector3f::UnitY())));
        obj.setTranslation(Translation3f(0.9, 0, 0));
        obj.setRotation(Affine3f(AngleAxisf(-41*M_PI/180., Vector3f::UnitY())));
        obj.setTranslation(Translation3f(-0.1, 0, 0));
        obj.setRotation(Affine3f(AngleAxisf(8*M_PI/180., Vector3f::UnitY())));
        _objs.push_back(obj);
    }
};

/******** SCENE 5 ********/
class Scene5 : public Scene
{
public:
    Scene5()
    {
        init();
    }

private:
    virtual void init()
    {
        // init parent
        Scene::init();
        _camera.setFovY(M_PI/3.);
        _camera.lookAt(Vector3f(0, 1, 0.01).normalized()*2, Vector3f(0, 0, 0), Vector3f::UnitY());

        // object
        Object obj = openObject(OBJECT_BOX);
        obj.setRenderType(1);
        obj.setTranslation(Translation3f(1, 0, 0));
        obj.setRotation(Affine3f(AngleAxisf(-45*M_PI/180., Vector3f::UnitY())));
        _objs.push_back(obj);
    }
};



/******** SCENE 6 ********/
class Scene6 : public Scene
{
public:
    Scene6()
        : Scene()
    {
        init();
    }

private:
    virtual void init()
    {
        // init parent
        Scene::init();

        // object
        Object obj = openObject(OBJECT_BOX);
        obj.setRenderType(1);
        _objs.push_back(obj);
    }
};

/******** SCENE 7 ********/
class Scene7 : public Scene
{
public:
    Scene7()
        : Scene()
    {
        init();
    }

private:
    virtual void init()
    {
        // init parent
        Scene::init();

        // object
        Object obj = openObject(OBJECT_BOX);
        obj.setRenderType(3);
        _objs.push_back(obj);
    }
};

/******** SCENE 8 ********/
class Scene8 : public Scene
{
public:
    Scene8()
        : Scene()
    {
        init();
    }

private:
    virtual void init()
    {
        // init parent
        Scene::init();
        _camera.lookAt(Vector3f(0, 0.01, 1).normalized()*5, Vector3f(0, 0, 0), Vector3f::UnitY());

        // object 1
        Object obj1 = openObject(OBJECT_BOX);
        obj1.setRenderType(3);
        obj1.setTranslation(Translation3f(1, -1, 0));
        _objs.push_back(obj1);

        // object 2
        Object obj2 = openObject(OBJECT_BOX);
        obj2.setRenderType(3);
        obj2.setTranslation(Translation3f(-1, -1, 0));
        _objs.push_back(obj2);

        // object 3
        Object obj3 = openObject(OBJECT_BOX);
        obj3.setRenderType(3);
        obj3.setTranslation(Translation3f(1, 1, 0));
        _objs.push_back(obj3);

        // object 4
        Object obj4 = openObject(OBJECT_BOX);
        obj4.setRenderType(3);
        obj4.setTranslation(Translation3f(-1, 1, 0));
        _objs.push_back(obj4);
    }
};


/******** SCENE 9 ********/
class Scene9 : public Scene
{
public:
    Scene9()
        : Scene()
    {
        init();
    }

private:
    virtual void init()
    {
        // init parent
        Scene::init();

        // objects
        for(int z=-10 ; z<=10 ; z+=3)
            for(int y=-10 ; y<=10 ; y+=3)
                for(int x=-10 ; x<=10 ; x+=3)
                {
                    Object obj = openObject(OBJECT_BOX);
                    obj.setTranslation(Translation3f(x, y, z));
                    obj.setRenderType(1);
                    _objs.push_back(obj);
                }
    }
};

#endif // SCENE_H
