package com.kangacult.octogone;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g3d.Material;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.bullet.collision.Collision;
import com.badlogic.gdx.physics.bullet.collision.btCollisionObject;
import com.badlogic.gdx.physics.bullet.collision.btSphereShape;
import com.badlogic.gdx.physics.bullet.dynamics.btDynamicsWorld;
import com.badlogic.gdx.physics.bullet.dynamics.btRigidBody;
import com.badlogic.gdx.physics.bullet.dynamics.btRigidBody.btRigidBodyConstructionInfo;

public class Projectiles {
    
    public static final int MAX_PROJECTILES = 1024;
    public Animation anim;
    public btSphereShape shape;
    public PairCallback callback;

    public int head = 0;
    public boolean[] active = new boolean[MAX_PROJECTILES];
    public btRigidBody body[] = new btRigidBody[MAX_PROJECTILES];
    public MotionState motion[] = new MotionState[MAX_PROJECTILES];
    public ModelInstance model[] = new ModelInstance[MAX_PROJECTILES];
    public Vector3 position[] = new Vector3[MAX_PROJECTILES];
    public Vector3 velocity[] = new Vector3[MAX_PROJECTILES];
    public float animTime[] = new float[MAX_PROJECTILES];
    public Texture frame[] = new Texture[MAX_PROJECTILES];
    public float lifetime[] = new float[MAX_PROJECTILES];
    
    public void init(Model quadModel) {
        {//Idle
            Texture[] textures = new Texture[] {
                    new Texture(Gdx.files.internal("Enemy/Fireball/Untitled-100.png")),
                    new Texture(Gdx.files.internal("Enemy/Fireball/Untitled-101.png")),
                    new Texture(Gdx.files.internal("Enemy/Fireball/Untitled-102.png")),
                    new Texture(Gdx.files.internal("Enemy/Fireball/Untitled-103.png")),
                    new Texture(Gdx.files.internal("Enemy/Fireball/Untitled-104.png")),
                    new Texture(Gdx.files.internal("Enemy/Fireball/Untitled-105.png")),
                    new Texture(Gdx.files.internal("Enemy/Fireball/Untitled-106.png")),
                    new Texture(Gdx.files.internal("Enemy/Fireball/Untitled-107.png")),
                    new Texture(Gdx.files.internal("Enemy/Fireball/Untitled-108.png")),
                    new Texture(Gdx.files.internal("Enemy/Fireball/Untitled-109.png")),
                    new Texture(Gdx.files.internal("Enemy/Fireball/Untitled-110.png")),
                    new Texture(Gdx.files.internal("Enemy/Fireball/Untitled-111.png")),
                    new Texture(Gdx.files.internal("Enemy/Fireball/Untitled-112.png")),
            };
            float[] frames = new float[] {
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
            };
            anim = new Animation(textures, frames);
        }

        shape = new btSphereShape(0.25f);
        callback = new PairCallback();
        
        for (int i = 0; i < MAX_PROJECTILES; i++) {
            position[i] = new Vector3();
            velocity[i] = new Vector3();
            model[i] = new ModelInstance(quadModel);
            motion[i] = new MotionState(model[i].transform);
            animTime[i] = MathUtils.random();
            frame[i] = anim.textures[0];
            lifetime[i] = 0f;
            
            btRigidBodyConstructionInfo info =
                    new btRigidBodyConstructionInfo(0f, motion[i], shape, new Vector3());
            body[i] = new btRigidBody(info);
            info.dispose();
            body[i].setCollisionFlags(body[i].getCollisionFlags() | 
                    btCollisionObject.CollisionFlags.CF_KINEMATIC_OBJECT);
            body[i].setActivationState(Collision.DISABLE_DEACTIVATION);
        }
    }
    
    public void reset(btDynamicsWorld world) {
        for (int i = 0; i < MAX_PROJECTILES; i++) {
            recycle(i, world);
            
            model[i].transform.setToTranslation(0f, 0f, -1000f);
            motion[i].transform.setToTranslation(0f, 0f, -1000f);
            body[i].setWorldTransform(motion[i].transform);
        }
    }
    
    public void dispose() {
        shape.dispose();
    }
    
    public void spawn(btDynamicsWorld world, Vector3 position, Vector3 direction) {
        int i = -1;
        for (int j = 0; j < MAX_PROJECTILES; j++) {
            if (! active[(j + head) % MAX_PROJECTILES]) {
                i = head;
                head++;
                head %= MAX_PROJECTILES;
                break;
            }
        }
        if (i < 0) return; //Quietly fail

        active[i] = true;
        lifetime[i] = 6f;
        velocity[i].set(direction);
        velocity[i].rotate(Vector3.Z, MathUtils.random(-15f, 15f));
        velocity[i].nor();
        velocity[i].scl(MathUtils.random(8f, 10f));
        this.position[i].set(position);
        model[i].transform.setToTranslation(this.position[i]);
        motion[i].transform.setToTranslation(this.position[i]);
        body[i].setWorldTransform(motion[i].transform);
		world.addRigidBody(body[i], (short) 0, (short) 0);
    }
    
    public void recycle(int i, btDynamicsWorld world) {
        if (! active[i]) return;
        active[i] = false;
        world.removeRigidBody(body[i]);
    }
    
    public void update(float deltaTime, btDynamicsWorld world, Player player, Camera camera, Audio audio) {
        for (int i = 0; i < MAX_PROJECTILES; i++) {
            if (! active[i]) continue;
            
            if (lifetime[i] <= 0f) {
                recycle(i, world);
            }
            lifetime[i] -= deltaTime;

            position[i].mulAdd(velocity[i], deltaTime);
            motion[i].transform.setToTranslation(position[i]);
            callback.hasHit = false;
            world.contactPairTest(player.body, body[i], callback);
            if (callback.hasHit) {
                player.hit(audio);
                recycle(i, world);
            }
            world.contactPairTest(player.wave.body, body[i], callback);
            if (callback.hasHit) {
                recycle(i, world);
            }
            
            model[i].transform.setToTranslation(position[i]);
            model[i].transform.rotate(Vector3.Z, camera.yaw);
            animTime[i] += deltaTime;
            animTime[i] %= anim.totalTime;
            frame[i] = anim.getFrame(animTime[i]);
            for (Material m: model[i].materials) {
                TextureAttribute t = (TextureAttribute) m.get(TextureAttribute.Diffuse);
                t.textureDescription.texture = frame[i];
                m.set(t);
            }
        }
    }
    
    public void render(ModelBatch batch) {
        for (int i = 0; i < MAX_PROJECTILES; i++) {
            if (! active[i]) continue;
            batch.render(model[i]);
        }
    }
}
