package electrosphere.entity.state;

import electrosphere.collision.dispatch.CollisionObject;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.collidable.Impulse;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.game.collision.PhysicsUtils;
import electrosphere.game.collision.collidable.Collidable;
import electrosphere.main.Globals;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.renderer.Actor;
import java.util.concurrent.CopyOnWriteArrayList;
import org.joml.Quaternionf;
import org.joml.Vector3d;
import org.joml.Vector3f;

/**
 *
 * @author amaterasu
 */
public class GravityTree {
    
    public static enum GravityTreeState {
        ACTIVE,
        NOT_ACTIVE,
    }
    
    GravityTreeState state;
    
    Entity parent;
    
    float gravityVelocity = 0;
    float gravityAccel = 0.0002f;
    
    CollisionObject body;
    Collidable collidable;
    
    CopyOnWriteArrayList<EntityMessage> networkMessageQueue = new CopyOnWriteArrayList();
    
    public GravityTree(Entity e, Collidable collidable, CollisionObject body){
        state = GravityTreeState.ACTIVE;
        parent = e;
        this.body = body;
        this.collidable = collidable;
    }
    
//    public void setCollisionObject(CollisionObject body, Collidable collidable){
//        this.body = body;
//        this.collidable = collidable;
//    }
    
    public GravityTreeState getState(){
        return state;
    }
    
    public void start(){
        //TODO: check if can start moving
        state = GravityTreeState.ACTIVE;
    }
    
    public void interrupt(){
        state = GravityTreeState.NOT_ACTIVE;
    }
    
    public void stop(){
        state = GravityTreeState.NOT_ACTIVE;
    }
    
    static final float gravityConstant = 0.2f;
    static final float linearDamping = 0.1f;
    
    public void simulate(float deltaTime){
//        float velocity = CreatureUtils.getVelocity(parent);
//        float acceleration = CreatureUtils.getAcceleration(parent);
//        float maxNaturalVelocity = CreatureUtils.getMaxNaturalVelocity(parent);
//        Actor entityActor = EntityUtils.getActor(parent);
        Vector3d position = EntityUtils.getPosition(parent);
//        Vector3f movementVector = CreatureUtils.getMovementVector(parent);
        Quaternionf rotation = EntityUtils.getRotation(parent);
        Vector3f newPosition;
        javax.vecmath.Matrix4f bodyTransformMatrix;
        
        //parse attached network messages
//        for(EntityMessage message : networkMessageQueue){
//            networkMessageQueue.remove(message);
////            System.out.println("MOVE to " + message.getX() + " " + message.getY() + " " + message.getZ());
//            switch(message.getMessageSubtype()){
//                case ATTACKUPDATE:
//                    switch(message.gettreeState()){
//                     case 0:
//                            state = IdleTreeState.IDLE;
//                            break;
//                        case 1:
//                            state = IdleTreeState.NOT_IDLE;
//                            break;
//                    }
//                    EntityUtils.getPosition(parent).set(message.getpositionX(),message.getpositionY(),message.getpositionZ());
//                    CreatureUtils.setMovementVector(parent, new Vector3f(message.getrotationX(),message.getrotationY(),message.getrotationZ()));
//                    break;
//            }
//        }
        
        //state machine
        switch(state){
            case ACTIVE:
                if(hadGroundCollision()){
                    state = GravityTreeState.NOT_ACTIVE;
                    if(!hadStructureCollision()){
//                        position.set(new Vector3d(position.x,Globals.commonWorldData.getElevationAtPoint(position) + 0.0001f,position.z));
                    }
                    gravityVelocity = 0;
                } else {
                    if(gravityVelocity < gravityConstant){
                        gravityVelocity = gravityVelocity + gravityAccel;
                    }
                    if(gravityVelocity > gravityConstant){
                        gravityVelocity = gravityConstant;
                    }
                    float gravityDif = gravityVelocity * (float)Math.pow(1.0f - linearDamping,deltaTime * 2);
                    Vector3d newGravityPos = new Vector3d(position.x,position.y - gravityDif,position.z);
                    float hitFraction = Globals.collisionEngine.sweepTest(body, new Vector3f((float)position.x,(float)position.y,(float)position.z), new Vector3f((float)newGravityPos.x,(float)newGravityPos.y,(float)newGravityPos.z));
//                    if(hitFraction >= 0){
//                        collidable.addImpulse(new Impulse(new Vector3d(0,-1,0),gravityDif * hitFraction,"gravity"));
//                        position.set(new Vector3d(position.x,position.y - gravityDif * hitFraction,position.z));
//                    } else {
//                        position.set(new Vector3d(position.x,position.y - gravityDif,position.z));
//                    }
                    if(hitFraction < 0){
                        hitFraction = 1;
                    }
                    collidable.addImpulse(new Impulse(new Vector3d(0,-1,0),gravityDif * hitFraction,"gravity"));
//                    System.out.println(hitFraction);
//                    bodyTransformMatrix = new javax.vecmath.Matrix4f(PhysicsUtils.jomlToVecmathQuaternionf(rotation),PhysicsUtils.jomlToVecmathVector3f(new Vector3f((float)position.x,(float)position.y,(float)position.z)),1.0f);
//                    body.setWorldTransform(new electrosphere.linearmath.Transform(bodyTransformMatrix));
                }
                break;
            case NOT_ACTIVE:
                if(hadEntityCollision()){
                    start();
                }
                //nothing here atm
                //eventually want to check if need to re-activate somehow
                break;
        }
    }

    public void addNetworkMessage(EntityMessage networkMessage) {
        networkMessageQueue.add(networkMessage);
    }
    
    public boolean hadStructureCollision(){
        boolean rVal = false;
        for(Impulse impulse : collidable.getImpulses()){
            if(impulse.getType().equals(Collidable.TYPE_STRUCTURE)){
                rVal = true;
                break;
            }
        }
        return rVal;
    }
    
    public boolean hadGroundCollision(){
        boolean rVal = false;
        for(Impulse impulse : collidable.getImpulses()){
            if(impulse.getType().equals(Collidable.TYPE_TERRAIN)){
                rVal = true;
                break;
            } else if(
                    impulse.getType().equals(Collidable.TYPE_STRUCTURE) &&
                    new Vector3d(impulse.getDirection()).normalize().y > 0.7
                    ){
                rVal = true;
            }
        }
        return rVal;
    }
    
    public boolean hadEntityCollision(){
        boolean rVal = false;
        for(Impulse impulse : collidable.getImpulses()){
            if(impulse.getType().equals(Collidable.TYPE_CREATURE)){
                rVal = true;
                break;
            }
        }
        return rVal;
    }
    
}
