#include <pch.hpp>

#include <ref_scope.hpp>
#include <physics.hpp>

#include <Jolt/Physics/Body/BodyInterface.h>
#include <Jolt/Core/JobSystemThreadPool.h>
#include <Jolt/Core/Memory.h>
#include <Jolt/Physics/PhysicsSystem.h>
#include <Jolt/Physics/PhysicsUpdateContext.h>

bool ObjectLayerPairFilterImpl::ShouldCollide(ObjectLayer object1, ObjectLayer object2) const
{
    switch (object1)
    {
        case Layers::NON_MOVING:
            return object2 == Layers::MOVING; // Non moving only collides with moving
        case Layers::MOVING:
            return true; // Moving collides with everything
        default:
            JPH_ASSERT(false);
            return false;
    }
}

namespace OpenEngine {

    PhysicsEngine::PhysicsEngine()
    {
        RegisterDefaultAllocator();

        Trace = TraceImpl;
        JPH_IF_ENABLE_ASSERTS(AssertFailed = AssertFailedImpl);

        Factory::sInstance = new Factory();

        RegisterTypes();

        tmp_allocator = CreateRef<TempAllocatorImpl>(10 * 1024 * 1024);

        job_system = CreateRef<JobSystemThreadPool>(cMaxPhysicsJobs,
                cMaxPhysicsBarriers,
                thread::hardware_concurrency() - 1);

        physics_system.Init(
                1024,
                0,
                1024,
                1024,
                broad_phase_layer_interface,
                object_vs_broadphase_layer_filter,
                object_vs_object_layer_filter);

        //physics_system.SetBodyActivationListener(&body_activation_listener);
        //physics_system.SetContactListener(&contact_listener);

        // TODO: Check the comment on Jolt's example
        physics_system.OptimizeBroadPhase();
    }

    PhysicsEngine::~PhysicsEngine() {
        UnregisterTypes();

        // Destroy the factory
        delete Factory::sInstance;
        Factory::sInstance = nullptr;
    };

    void PhysicsEngine::Update(float delta_time, int collision_steps)
    {
        physics_system.Update(delta_time, collision_steps, &*tmp_allocator, &*job_system);
    }
}
