import { EventBus } from '../event-bus';
import Vec3 from '../math/vec3';
import { Broadphase } from './broadphase';
import { CollisionMatrix } from './collision';
import { CollisionDiff } from './collision/diff';
import { Narrowphase } from './narrowphase';
import { Octree } from './octree';
export class World extends EventBus {
    constructor(dimensions, octreeOptions) {
        super();
        if (!octreeOptions) {
            this.octreeOptions = {
                position: new Vec3([0, 0, 0]),
                dimensions: this.dimensions,
                maxLevels: 50,
                maxObjects: 50
            };
        }
        else {
            this.octreeOptions = octreeOptions;
        }
        this.dimensions = dimensions;
        this.objects = [];
        this.octree = new Octree(this.octreeOptions.dimensions, this.octreeOptions.maxObjects, this.octreeOptions.maxLevels);
        this.narrowphase = new Narrowphase(this);
        this.broadphase = new Broadphase(this);
        this.collisionMatrix = new CollisionMatrix(this);
        this.collisionDiff = new CollisionDiff(this);
        this.processors = [];
    }
    addProcessor(processor) {
        this.processors.push(processor);
    }
    setGravity(grav) {
        this.gravity = grav;
    }
    addObject(obj) {
        this.objects.push(obj);
        this.octree.insert(obj);
    }
    removeObject(obj) {
        this.objects = this.objects.filter((val) => val !== obj);
        this.octree.remove(obj);
    }
    step(dt) {
        const objects = this.objects;
        this.deltaTime = dt;
        for (let i = 0; i < objects.length; i++) {
            const obj = objects[i];
            if (obj.isDirty) {
                this.octree.remove(obj);
                this.octree.insert(obj);
                obj.isDirty = false;
            }
            const velocity = obj.velocity.copy();
            velocity.multiply(new Vec3([dt, dt, dt]));
            const gravity = this.gravity.copy();
            gravity.multiply(new Vec3([dt, dt, dt]));
            if (obj.affectedByGravity) {
                obj.velocity.add(gravity);
            }
            obj.boundingBox.position.add(velocity);
            if (obj.velocity.length() != 0) {
                obj.isDirty = true;
            }
            this.checkCollisions(obj, dt);
        }
    }
    checkCollisions(obj, dt) {
        this.collisionMatrix = new CollisionMatrix(this);
        const candidates = this.broadphase.execute();
        this.narrowphase.perform(candidates);
        this.collisionDiff.currMatrix = this.collisionMatrix;
        this.collisionDiff.perform();
    }
}
