package com.kangacult.octogone;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.loaders.ModelLoader;
import com.badlogic.gdx.assets.loaders.ModelLoader.ModelParameters;
import com.badlogic.gdx.graphics.GL20;
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.BlendingAttribute;
import com.badlogic.gdx.graphics.g3d.attributes.DepthTestAttribute;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.math.collision.BoundingBox;
import com.badlogic.gdx.physics.bullet.collision.Collision;
import com.badlogic.gdx.physics.bullet.collision.btBoxShape;
import com.badlogic.gdx.physics.bullet.collision.btCollisionObject;
import com.badlogic.gdx.physics.bullet.collision.btCompoundShape;
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;
import com.kangacult.octogone.Enemies.State;

public class Wave {
    public static final float LIFETIME = 3f;
    public static final float HALF_LIFE = LIFETIME / 2f;

    public Model modelDef;
    public btCompoundShape shape;

    public btRigidBody body;
    public MotionState motion;
    public ModelInstance model;
    public Vector3 position = new Vector3();
    public Vector3 velocity = new Vector3();
    public float scale = 1f;
    public float lifetime;
    public float speed = 8f;
    public float yaw = 0f;
    public long id = 0;
    private PairCallback callback;
    
    public void init(ModelLoader<ModelParameters> loader, btDynamicsWorld world) {
        modelDef = loader.loadModel(Gdx.files.internal("Wave.g3db"));
	    for (Material m: modelDef.materials) {
            DepthTestAttribute depth = new DepthTestAttribute();
            depth.depthMask = false;
            m.set(depth);
            
            BlendingAttribute blend = new BlendingAttribute();
            blend.sourceFunction = GL20.GL_SRC_ALPHA;
            blend.destFunction = GL20.GL_ONE_MINUS_SRC_ALPHA;
            m.set(blend);
	    }
        model = new ModelInstance(modelDef);
        motion = new MotionState(model.transform);
        
        BoundingBox box = new BoundingBox();
        modelDef.calculateBoundingBox(box);
        btBoxShape bs = new btBoxShape(new Vector3(
                box.getWidth()/2f, box.getHeight()/2f, box.getDepth()/2f));
        Matrix4 offset = new Matrix4();
        offset.translate(0f, 1f, 0f);
        shape = new btCompoundShape(false, 1);
        shape.addChildShape(offset, bs);

		btRigidBodyConstructionInfo info = 
				new btRigidBodyConstructionInfo(0f, motion, shape, Vector3.Zero);
		body = new btRigidBody(info);
		info.dispose();
		body.setCollisionFlags(body.getCollisionFlags() | 
				btCollisionObject.CollisionFlags.CF_KINEMATIC_OBJECT);
		body.setActivationState(Collision.DISABLE_DEACTIVATION);
		world.addRigidBody(body, (short) 0, (short) 0);

		callback = new PairCallback();
		reset();
    }
    
    public void reset() {
        lifetime = 0f;
        position.set(0f, 0f, -1000f);
        id = 0;
    }
    
    public void dispose(btDynamicsWorld world) {
        world.removeRigidBody(body);
        modelDef.dispose();
    }
    
    public void update(float deltaTime, btDynamicsWorld world, Enemies enemies, Camera camera, Audio audio) {
        lifetime -= deltaTime;
        
        if (lifetime > 0f) {
            position.mulAdd(velocity, deltaTime);
            if (lifetime > HALF_LIFE) {
                scale = HALF_LIFE - (lifetime - HALF_LIFE);
                scale /= HALF_LIFE;
            } else {
                scale = lifetime / HALF_LIFE;
            }

            //Compare against enemies
            for (int i = 0; i < Enemies.MAX_ENEMIES; i++) {
                if (enemies.state[i] == State.FREE) continue;

                callback.hasHit = false;
                world.contactPairTest(enemies.body[i], body, callback);
                if (callback.hasHit) {
                    enemies.hitWave(i, world, id, camera, audio);
                }
            }
        } else {
            position.set(0f, 0f, -1000f);
        }

        //Update motion state
        motion.transform.setToTranslation(position);
        motion.transform.rotate(Vector3.Z, yaw);
        motion.transform.scale(1f, scale/2f + 0.5f, scale);
    }
    
    public void render(ModelBatch batch) {
        if (lifetime > 0f) {
            batch.render(model);
        }
    }
    
    public void spawn(Vector3 position, float yaw) {
        lifetime = LIFETIME;
        scale = 0f;
        this.position.set(position);
        this.yaw = yaw;
        velocity.set(0f, speed, 0f);
        velocity.rotate(Vector3.Z, yaw);
        id++;
    }
}