package electrosphere.entity.types.attach;

import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.main.Globals;
import electrosphere.renderer.Actor;
import electrosphere.renderer.Model;
import java.util.LinkedList;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Vector3d;
import org.joml.Vector3f;

/**
 *
 * @author amaterasu
 */
public class AttachUtils {
    
    
    public static void attachEntityToEntityAtBone(Entity parent, Entity toAttach, String boneName){
        Globals.entityManager.registerBoneAttachedEntity(toAttach);
        toAttach.putData(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED, true);
        toAttach.putData(EntityDataStrings.ATTACH_PARENT, parent);
        toAttach.putData(EntityDataStrings.ATTACH_TARGET_BONE, boneName);
        if(parent.getDataKeys().contains(EntityDataStrings.ATTACH_CHILDREN_LIST)){
            getChildrenList(parent).add(toAttach);
        } else {
            LinkedList<Entity> childrenEntities = new LinkedList();
            childrenEntities.add(toAttach);
            parent.putData(EntityDataStrings.ATTACH_CHILDREN_LIST, childrenEntities);
        }
    }
    
    public static void updateAttachedEntityPositions(){
        for(Entity currentEntity : Globals.entityManager.getBoneAttachedEntities()){
            Entity parent;
            if((parent = (Entity)currentEntity.getData(EntityDataStrings.ATTACH_PARENT))!=null){
                String targetBone;
                if((targetBone = (String)currentEntity.getData(EntityDataStrings.ATTACH_TARGET_BONE))!=null){
                    Actor parentActor = EntityUtils.getActor(parent);
                    //transform bone space
                    Vector3d position = new Vector3d(parentActor.getBonePosition(targetBone));
                    position = position.mul(((Vector3f)EntityUtils.getScale(parent)));
                    Quaternionf rotation = EntityUtils.getRotation(parent);
                    position = position.rotate(new Quaterniond(rotation.x,rotation.y,rotation.z,rotation.w));
                    //transform worldspace
                    position.add(new Vector3d(EntityUtils.getPosition(parent)));
                    //set
                    EntityUtils.getPosition(currentEntity).set(position);
                    //set rotation
//                    Quaternionf rotation = parentActor.getBoneRotation(targetBone);
//                    EntityUtils.getRotation(currentEntity).set(rotation).normalize();
                    Vector3f facingAngle = CreatureUtils.getMovementVector(parent);
                    EntityUtils.getRotation(currentEntity).rotationTo(new Vector3f(0,0,1), facingAngle).mul(parentActor.getBoneRotation(targetBone)).normalize();
                }
            }
        }
    }
    
    public static boolean isAttached(Entity e){
        return e.getDataKeys().contains(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED);
    }
    
    public static String getTargetBone(Entity e){
        return (String)e.getData(EntityDataStrings.ATTACH_TARGET_BONE);
    }
    
    public static Entity getParent(Entity e){
        return (Entity)e.getData(EntityDataStrings.ATTACH_PARENT);
    }
    
    public static boolean hasChildren(Entity e){
        return e.getDataKeys().contains(EntityDataStrings.ATTACH_CHILDREN_LIST) && !getChildrenList(e).isEmpty();
    }
    
    public static LinkedList<Entity> getChildrenList(Entity e){
        return (LinkedList<Entity>)e.getData(EntityDataStrings.ATTACH_CHILDREN_LIST);
    }
    
    public static void attachEntityToEntity(Entity parent, Entity child){
        child.putData(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED, true);
        child.putData(EntityDataStrings.ATTACH_PARENT, parent);
        if(parent.getDataKeys().contains(EntityDataStrings.ATTACH_CHILDREN_LIST)){
            getChildrenList(parent).add(child);
        } else {
            LinkedList<Entity> childrenEntities = new LinkedList();
            childrenEntities.add(child);
            parent.putData(EntityDataStrings.ATTACH_CHILDREN_LIST, childrenEntities);
        }
    }
}
