/*
 * TrackPieceFactory.cpp
 *
 *  Created on: Aug 27, 2020
 *      Author: fredrick
 */

#include "TrackPieceFactory.h"

namespace JamSpook {

TrackPieceFactory::TrackPieceFactory(weak_ptr<AssetSystem>    assetSystem,
                                     weak_ptr<GraphicsSystem> graphicsSystem,
                                     weak_ptr<PhysicsSystem>  physicsSystem,
                                     weak_ptr<RenderLayer>    renderLayer):
        mAssetSystem(assetSystem),
        mGraphicsSystem(graphicsSystem),
        mPhysicsSystem(physicsSystem),
        mRenderLayer(renderLayer)
{}

TrackPieceFactory::~TrackPieceFactory()
{}

/// Compose a road entity
shared_ptr<Entity> TrackPieceFactory::createRoad()
{
    // Create instance
    shared_ptr<Entity> entity = make_shared<Entity>();
    entity->setEntityTag("road");
    SceneGraph::addEntity(entity);

    // Create transform
    mat4 transform = mat4(1);

    // Add physics component
    ColliderFactory* colliderFactory = new ColliderFactory(mPhysicsSystem, mAssetSystem);
    shared_ptr<TrackPiecePhysicsComponent> physicsComponent =
            make_shared<TrackPiecePhysicsComponent>(
                    transform,
                    entity,
                    getShared(mPhysicsSystem),
                    getShared(mPhysicsSystem),
                    getShared(mPhysicsSystem),
                    colliderFactory->createConvexHullCollider(vec3(0),
                                                              quat_cast(mat4(1)),
                                                              "road.bcosp", // filePath
                                                              "road-shape", // name
                                                              100.0f, // mass
                                                              entity,
                                                              entity->getEntityTag()));
    delete colliderFactory;
    // Note: Editing of rigid body params, maybe only has effect is it has been added to the world.
    physicsComponent->getCollider()->getRigidBody()->setLinearFactor(btVector3(0, 0, 0));  // deny positional movement movement in any axis
    physicsComponent->getCollider()->getRigidBody()->setAngularFactor(btVector3(0, 0, 0)); // deny rotational movement movement in any axis
    physicsComponent->getCollider()->getRigidBody()->setRestitution(1);
    entity->addComponent(physicsComponent);

    // Add graphics component
    shared_ptr<GraphicsComponent> graphicsComponent = make_shared<GraphicsComponent>(transform,
                                                                                     entity,
                                                                                     getShared(mGraphicsSystem),
                                                                                     mRenderLayer);
    entity->addComponent(graphicsComponent);

    // Add the ModelRenderable of a ball
    ModelRenderableFactory* modelFactory = new ModelRenderableFactory(mAssetSystem);
    shared_ptr<ModelRenderable> modelRenderable = modelFactory->createModel("road.bcosm",
                                                                            "road-diffuse.png",
                                                                            "road-model");
    delete modelFactory;
    graphicsComponent->addRenderable(modelRenderable);

    // Return instance
    return entity;
}

/// Compose a tunnel entity
shared_ptr<Entity> TrackPieceFactory::createTunnel()
{
    // Create instance
    shared_ptr<Entity> entity = make_shared<Entity>();
    entity->setEntityTag("tunnel");
    SceneGraph::addEntity(entity);

    // Create transform
    mat4 transform = mat4(1);

    // Add physics component
    ColliderFactory* colliderFactory = new ColliderFactory(mPhysicsSystem, mAssetSystem);
    shared_ptr<TrackPiecePhysicsComponent> physicsComponent =
            make_shared<TrackPiecePhysicsComponent>(
                    transform,
                    entity,
                    getShared(mPhysicsSystem),
                    getShared(mPhysicsSystem),
                    getShared(mPhysicsSystem),
                    colliderFactory->createConvexHullCollider(vec3(0),
                                                              quat_cast(mat4(1)),
                                                              "tunnel.bcosp", // filePath
                                                              "tunnel-shape", // name
                                                              100.0f, // mass
                                                              entity,
                                                              entity->getEntityTag()));
    delete colliderFactory;
    // Note: Editing of rigid body params, maybe only has effect is it has been added to the world.
    physicsComponent->getCollider()->getRigidBody()->setLinearFactor(btVector3(0, 0, 0));  // deny positional movement movement in any axis
    physicsComponent->getCollider()->getRigidBody()->setAngularFactor(btVector3(0, 0, 0)); // deny rotational movement movement in any axis
    physicsComponent->getCollider()->getRigidBody()->setRestitution(1);
    entity->addComponent(physicsComponent);

    // Add graphics component
    shared_ptr<GraphicsComponent> graphicsComponent = make_shared<GraphicsComponent>(transform,
                                                                                     entity,
                                                                                     getShared(mGraphicsSystem),
                                                                                     mRenderLayer);
    entity->addComponent(graphicsComponent);

    // Add the ModelRenderable of a ball
    ModelRenderableFactory* modelFactory = new ModelRenderableFactory(mAssetSystem);
    shared_ptr<ModelRenderable> modelRenderable = modelFactory->createModel("tunnel.bcosm",
                                                                            "tunnel-diffuse.png",
                                                                            "tunnel-model");
    delete modelFactory;
    graphicsComponent->addRenderable(modelRenderable);

    // Return instance
    return entity;
}

/// Compose a mountain entity
shared_ptr<Entity> TrackPieceFactory::createMountain()
{
    // Create instance
    shared_ptr<Entity> entity = make_shared<Entity>();
    entity->setEntityTag("mountain");
    SceneGraph::addEntity(entity);

    // Create transform
    mat4 transform = mat4(1);

//    // Add physics component
//    ColliderFactory* colliderFactory = new ColliderFactory(mPhysicsSystem, mAssetSystem);
//    shared_ptr<TrackPiecePhysicsComponent> physicsComponent =
//            make_shared<TrackPiecePhysicsComponent>(
//                    transform,
//                    entity,
//                    getShared(mPhysicsSystem),
//                    getShared(mPhysicsSystem),
//                    getShared(mPhysicsSystem),
//                    colliderFactory->createConvexHullCollider(vec3(0),
//                                                              quat_cast(mat4(1)),
//                                                              "mountain.bcosp", // filePath
//                                                              "mountain-shape", // name
//                                                              100.0f, // mass
//                                                              entity,
//                                                              entity->getEntityTag()));
//    delete colliderFactory;
//    // Note: Editing of rigid body params, maybe only has effect is it has been added to the world.
//    physicsComponent->getCollider()->getRigidBody()->setLinearFactor(btVector3(0, 0, 0));  // deny positional movement movement in any axis
//    physicsComponent->getCollider()->getRigidBody()->setAngularFactor(btVector3(0, 0, 0)); // deny rotational movement movement in any axis
//    physicsComponent->getCollider()->getRigidBody()->setRestitution(1);
//    entity->addComponent(physicsComponent);

    // Add graphics component
    shared_ptr<GraphicsComponent> graphicsComponent = make_shared<GraphicsComponent>(transform,
                                                                                     entity,
                                                                                     getShared(mGraphicsSystem),
                                                                                     mRenderLayer);
    entity->addComponent(graphicsComponent);

    // Add the ModelRenderable of a ball
    ModelRenderableFactory* modelFactory = new ModelRenderableFactory(mAssetSystem);
    shared_ptr<ModelRenderable> modelRenderable = modelFactory->createModel("mountain.bcosm",
                                                                            "mountain-diffuse.png",
                                                                            "mountain-model");
    delete modelFactory;
    graphicsComponent->addRenderable(modelRenderable);

    // Return instance
    return entity;
}

shared_ptr<Entity> TrackPieceFactory::createSign(
        const string name,
        const string diffuseTextureFilePath,
        vec3 position,
        quat orientation)
{
    // Create instance
    shared_ptr<Entity> entity = make_shared<Entity>();
    entity->setEntityTag(name + "_sign");
    SceneGraph::addEntity(entity);

    // Create transform
    mat4 rotation = glm::toMat4(orientation);

    mat4 translation = translate(mat4(1.0f), position);

    mat4 transform = translation * rotation;// * rotateToCenter;

    // Add graphics component
    shared_ptr<GraphicsComponent> graphicsComponent = make_shared<GraphicsComponent>(transform,
                                                                                     entity,
                                                                                     getShared(mGraphicsSystem),
                                                                                     mRenderLayer);
    entity->addComponent(graphicsComponent);

    // Add the ModelRenderable of a ball
    ModelRenderableFactory* modelFactory = new ModelRenderableFactory(mAssetSystem);
    shared_ptr<ModelRenderable> modelRenderable = modelFactory->createModel("sign.bcosm",
                                                                            diffuseTextureFilePath,
                                                                            "sign-model");
    delete modelFactory;
    graphicsComponent->addRenderable(modelRenderable);

    // Return instance
    return entity;
}

shared_ptr<Entity> TrackPieceFactory::createGhost(
        const string name,
        const string diffuseTextureFilePath,
        vec3 position,
        quat orientation,
        float scaling)
{
    // Create instance
    shared_ptr<Entity> entity = make_shared<Entity>();
    entity->setEntityTag(name + "_ghost");
    SceneGraph::addEntity(entity);

    // Create transform
    mat4 translationMatrix = translate(mat4(1.0f), position);
    mat4 rotationMatrix = glm::toMat4(orientation);
    mat4 scalingMatrix = glm::scale(mat4(1), vec3(scaling));


    mat4 transform = translationMatrix * rotationMatrix * scalingMatrix;// * rotateToCenter;

    // Add graphics component
    shared_ptr<GraphicsComponent> graphicsComponent = make_shared<GraphicsComponent>(transform,
                                                                                     entity,
                                                                                     getShared(mGraphicsSystem),
                                                                                     mRenderLayer);
    entity->addComponent(graphicsComponent);

    // Add the ModelRenderable
    ModelRenderableFactory* modelFactory = new ModelRenderableFactory(mAssetSystem);
    shared_ptr<ModelRenderable> modelRenderable = modelFactory->createModel("ghost.bcosm",
                                                                            diffuseTextureFilePath,
                                                                            name + "-model");
    delete modelFactory;
    graphicsComponent->addRenderable(modelRenderable);

    // Return instance
    return entity;
}

shared_ptr<Entity> TrackPieceFactory::createStaticPlatform()
{
    // Create instance
    shared_ptr<Entity> entity = make_shared<Entity>();
    entity->setEntityTag("staticPlatform");
    SceneGraph::addEntity(entity);

    // Create transform
    mat4 transform = mat4(1);

    // Add physics component
    ColliderFactory* colliderFactory = new ColliderFactory(mPhysicsSystem, mAssetSystem);
    shared_ptr<TrackPiecePhysicsComponent> physicsComponent =
            make_shared<TrackPiecePhysicsComponent>(
                    transform,
                    entity,
                    getShared(mPhysicsSystem),
                    getShared(mPhysicsSystem),
                    getShared(mPhysicsSystem),
                    colliderFactory->createStaticMeshCollider(vec3(0),
                                                              quat_cast(mat4(1)),
                                                              "static-platform.bcosps", // filePath
                                                              "static-platform-shape",  // name
                                                              100.0f, // mass
                                                              entity,
                                                              entity->getEntityTag()));
    delete colliderFactory;
    // Note: Editing of rigid body params, maybe only has effect is it has been added to the world.
    physicsComponent->getCollider()->getRigidBody()->setLinearFactor(btVector3(0, 0, 0));  // deny positional movement movement in any axis
    physicsComponent->getCollider()->getRigidBody()->setAngularFactor(btVector3(0, 0, 0)); // deny rotational movement movement in any axis
    physicsComponent->getCollider()->getRigidBody()->setRestitution(1);
    entity->addComponent(physicsComponent);

    // Add graphics component
    shared_ptr<GraphicsComponent> graphicsComponent = make_shared<GraphicsComponent>(transform,
                                                                                     entity,
                                                                                     getShared(mGraphicsSystem),
                                                                                     mRenderLayer);
    entity->addComponent(graphicsComponent);

    // Add the ModelRenderable of a ball
    ModelRenderableFactory* modelFactory = new ModelRenderableFactory(mAssetSystem);
    shared_ptr<ModelRenderable> modelRenderable = modelFactory->createModel("static-platform.bcosm",
                                                                            "static-platform-diffuse.png",
                                                                            "static-platform-model");
    delete modelFactory;
    graphicsComponent->addRenderable(modelRenderable);

    // Return instance
    return entity;
}

} // namespace JamSpook
