package electrosphere.menu.debug;

import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.joml.Quaterniond;
import org.joml.Vector3d;
import org.ode4j.ode.DBody;

import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.client.firstPerson.FirstPersonTree;
import electrosphere.entity.state.equip.ClientEquipState;
import electrosphere.entity.state.server.ServerPlayerViewDirTree;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.debug.DebugVisualizerUtils;
import electrosphere.entity.types.foliage.FoliageUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.game.data.creature.type.equip.EquipPoint;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.actor.ActorAnimationMask;
import electrosphere.renderer.actor.ActorMeshMask;
import electrosphere.renderer.anim.AnimChannel;
import electrosphere.renderer.anim.Animation;
import electrosphere.renderer.model.Bone;
import electrosphere.renderer.model.Mesh;
import electrosphere.renderer.model.Model;
import electrosphere.renderer.ui.imgui.ImGuiWindow;
import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback;
import electrosphere.server.datacell.utils.EntityLookupUtils;
import electrosphere.server.poseactor.PoseActor;
import electrosphere.server.poseactor.PoseModel;
import imgui.ImGui;

/**
 * Macros for creating imgui windows relating to entity debugging
 */
public class ImGuiEntityMacros {
    
    //window for selecting entities to view
    protected static ImGuiWindow clientEntityListWindow;
    private static boolean filterToCreatures = true; //filters the entity list to just creatures

    //window for viewing details about an entity
    protected static ImGuiWindow clientEntityDetailWindow;
    private static Entity detailViewEntity = null;

    //tree node values
    private static boolean showActorTab = false; //show the actor tab
    private static boolean showPoseActorTab = false; //show the pose actor tab
    private static boolean showEquipStateTab = false; //actor details
    private static boolean showFirstPersonTab = false; //first person tab
    private static boolean showLinkedEntitiesTab = false;//show linked entities
    private static boolean showServerViewDirTab = false; //show server view dir
    private static boolean showPhysicsTab = false; //show physics values

    /**
     * Creates the windows in this file
     */
    protected static void createClientEntityWindows(){
        createClientEntityDetailWindow();
        createClientEntitySelectionWindow();
    }

    /**
     * Client scene entity view
     */
    protected static void createClientEntitySelectionWindow(){
        clientEntityListWindow = new ImGuiWindow("Client Entities");
        clientEntityListWindow.setCallback(new ImGuiWindowCallback() {
            @Override
            public void exec() {
                //audio engine details
                ImGui.text("Client Entities");
                if(ImGui.checkbox("Filter to Creatures", filterToCreatures)){
                    filterToCreatures = !filterToCreatures;
                }
                for(Entity entity : Globals.clientSceneWrapper.getScene().getEntityList()){
                    //filters
                    if(filterToCreatures && !CreatureUtils.isCreature(entity)){
                        continue;
                    }
                    ImGui.beginGroup();
                    ImGui.pushID(entity.getId());
                    ImGui.text("Id: " + entity.getId() + " (" + getEntityName(entity) + ")");
                    if(ImGui.button("Details")){
                        showEntity(entity);
                    }
                    ImGui.popID();
                    ImGui.endGroup();
                }
            }
        });
        clientEntityListWindow.setOpen(false);
        Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(clientEntityListWindow);
    }

    /**
     * View details about a client entity
     */
    protected static void createClientEntityDetailWindow(){
        clientEntityDetailWindow = new ImGuiWindow("Entity Data");

        clientEntityDetailWindow.setCallback(new ImGuiWindowCallback() {
            @Override
            public void exec() {
                ImGui.text("Current ID: " + detailViewEntity.getId());
                if(ImGui.treeNode("Views")){
                    if(EntityUtils.getActor(detailViewEntity) != null && ImGui.checkbox("Actor Details", showActorTab)){
                        showActorTab = !showActorTab;
                    }
                    if(EntityUtils.getPoseActor(detailViewEntity) != null && ImGui.checkbox("Pose Actor Details", showPoseActorTab)){
                        showPoseActorTab = !showPoseActorTab;
                    }
                    if(ClientEquipState.hasEquipState(detailViewEntity) && ImGui.checkbox("Equip State", showEquipStateTab)){
                        showEquipStateTab = !showEquipStateTab;
                    }
                    if(FirstPersonTree.hasTree(detailViewEntity) && ImGui.checkbox("First Person", showFirstPersonTab)){
                        showFirstPersonTab = !showFirstPersonTab;
                    }
                    if(
                        (AttachUtils.hasChildren(detailViewEntity) || AttachUtils.getParent(detailViewEntity) != null || detailViewEntity == Globals.firstPersonEntity || detailViewEntity == Globals.playerEntity) &&
                        ImGui.checkbox("Linked entities`", showLinkedEntitiesTab)
                    ){
                        showLinkedEntitiesTab = !showLinkedEntitiesTab;
                    }
                    if(ServerPlayerViewDirTree.hasTree(detailViewEntity) && ImGui.checkbox("Server View Dir", showServerViewDirTab)){
                        showServerViewDirTab = !showServerViewDirTab;
                    }
                    if(PhysicsEntityUtils.getDBody(detailViewEntity) != null && ImGui.checkbox("Physics", showPhysicsTab)){
                        showPhysicsTab = !showPhysicsTab;
                    }
                    ImGui.treePop();
                }
                ImGui.nextColumn();
                drawActorView();
                drawPoseActor();
                drawEquipState();
                drawFirstPersonView();
                drawLinkedEntities();
                drawServerViewDir();
                drawPhysicsDetails();
            }
        });
        clientEntityDetailWindow.setOpen(false);
        Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(clientEntityDetailWindow);
    }

    /**
     * Shows the entity window for a specific entity
     * @param entity The entity
     */
    protected static void showEntity(Entity entity){
        detailViewEntity = entity;
        clientEntityDetailWindow.setOpen(true);
    }

    /**
     * Client scene entity view
     */
    protected static void drawActorView(){
        if(showActorTab && ImGui.collapsingHeader("Actor Details")){
            ImGui.indent();
            if(detailViewEntity != null && EntityUtils.getActor(detailViewEntity) != null){
                Actor actor = EntityUtils.getActor(detailViewEntity);
    
                //mesh mask
                if(ImGui.collapsingHeader("Mesh Mask")){
                    ActorMeshMask meshMask = actor.getMeshMask();
                    ImGui.text("To Draw Meshes:");
                    for(Mesh mesh : meshMask.getToDrawMeshes()){
                        ImGui.text(mesh.getMeshName());
                    }
                    ImGui.text("Blocked Meshes:");
                    for(String blocked : meshMask.getBlockedMeshes()){
                        ImGui.text(blocked);
                    }
                }

                //animation queue
                if(ImGui.collapsingHeader("Animation Queue")){
                    Set<ActorAnimationMask> animationQueue = actor.getAnimationQueue();
                    for(ActorAnimationMask mask : animationQueue){
                        ImGui.text(mask.getAnimationName() + " -  " + mask.getPriority());
                        ImGui.text(mask.getDuration() + " " + mask.getTime());
                    }
                }

                //bone values
                if(ImGui.collapsingHeader("Bone Values")){
                    for(Bone bone : actor.getBoneValues()){
                        ImGui.text(bone.boneID);
                        ImGui.text("Position: " + actor.getBonePosition(bone.boneID));
                        ImGui.text("Rotation: " + actor.getBoneRotation(bone.boneID));
                        ImGui.text(bone.getFinalTransform() + "");
                    }
                }

                //Draws all the bones in the world
                if(ImGui.button("Draw Bones")){
                    Globals.renderingEngine.getDebugContentPipeline().getDebugBonesPipeline().setEntity(detailViewEntity);
                }
    
                //Browsable list of all animations with their data
                if(ImGui.collapsingHeader("Animation Channel Data")){
                    Model model = Globals.assetManager.fetchModel(actor.getModelPath());
                    ImGui.indent();
                    for(Animation animation : model.getAnimations()){
                        if(ImGui.collapsingHeader(animation.name)){
                            for(AnimChannel channel : animation.channels){
                                ImGui.pushID(channel.getNodeID());
                                if(ImGui.button("Fully describe")){
                                    channel.fullDescribeChannel();
                                }
                                ImGui.text("=" + channel.getNodeID() + "=");
                                ImGui.text("" + channel.getCurrentPosition());
                                ImGui.text("" + channel.getCurrentRotation());
                                ImGui.text("" + channel.getCurrentScale());
                                ImGui.popID();
                            }
                        }
                    }
                    ImGui.unindent();
                }

                //print data macros
                if(ImGui.collapsingHeader("Print Data")){
                    //print bone values
                    if(ImGui.button("Print current bone values")){
                        for(Bone bone : actor.getBoneValues()){
                            LoggerInterface.loggerRenderer.DEBUG(bone.boneID);
                            LoggerInterface.loggerRenderer.DEBUG("" + bone.getFinalTransform());
                        }
                    }
        
                    //print animation keys
                    if(ImGui.button("Print animation keys")){
                        Model model = Globals.assetManager.fetchModel(actor.getModelPath());
                        model.describeAllAnimations();
                    }
                }
            }
            ImGui.unindent();
        }
    }

    /**
     * Draws pose actor 
     */
    protected static void drawPoseActor(){
        if(showPoseActorTab && ImGui.collapsingHeader("Pose Actor Details")){
            ImGui.indent();
            if(detailViewEntity != null && EntityUtils.getPoseActor(detailViewEntity) != null){
                PoseActor poseActor = EntityUtils.getPoseActor(detailViewEntity);

                //animation queue
                if(ImGui.collapsingHeader("Animation Queue")){
                    Set<ActorAnimationMask> animationQueue = poseActor.getAnimationQueue();
                    for(ActorAnimationMask mask : animationQueue){
                        ImGui.text(mask.getAnimationName() + " -  " + mask.getPriority());
                        ImGui.text(mask.getDuration() + " " + mask.getTime());
                    }
                }

                //bone values
                if(ImGui.collapsingHeader("Bone Values")){
                    for(Bone bone : poseActor.getBoneValues()){
                        ImGui.text(bone.boneID);
                        ImGui.text("Position: " + poseActor.getBonePosition(bone.boneID));
                        ImGui.text("Rotation: " + poseActor.getBoneRotation(bone.boneID));
                        ImGui.text(bone.getFinalTransform() + "");
                    }
                }

                //Draws all the bones in the world
                if(ImGui.button("Draw Bones")){
                    Globals.renderingEngine.getDebugContentPipeline().getDebugBonesPipeline().setEntity(detailViewEntity);
                }
    
                //Browsable list of all animations with their data
                if(ImGui.collapsingHeader("Animation Channel Data")){
                    Model model = Globals.assetManager.fetchModel(poseActor.getModelPath());
                    ImGui.indent();
                    for(Animation animation : model.getAnimations()){
                        if(ImGui.collapsingHeader(animation.name)){
                            for(AnimChannel channel : animation.channels){
                                ImGui.pushID(channel.getNodeID());
                                if(ImGui.button("Fully describe")){
                                    channel.fullDescribeChannel();
                                }
                                ImGui.text("=" + channel.getNodeID() + "=");
                                ImGui.text("" + channel.getCurrentPosition());
                                ImGui.text("" + channel.getCurrentRotation());
                                ImGui.text("" + channel.getCurrentScale());
                                ImGui.popID();
                            }
                        }
                    }
                    ImGui.unindent();
                }

                //print data macros
                if(ImGui.collapsingHeader("Print Data")){
                    //print bone values
                    if(ImGui.button("Print current bone values")){
                        for(Bone bone : poseActor.getBoneValues()){
                            LoggerInterface.loggerRenderer.DEBUG(bone.boneID);
                            LoggerInterface.loggerRenderer.DEBUG("" + bone.getFinalTransform());
                        }
                    }
        
                    //print animation keys
                    if(ImGui.button("Print animation keys")){
                        PoseModel model = Globals.assetManager.fetchPoseModel(poseActor.getModelPath());
                        model.describeAllAnimations();
                    }
                }
            }
            ImGui.unindent();
        }
    }

    /**
     * First person data
     */
    protected static void drawFirstPersonView(){
        if(showFirstPersonTab && ImGui.collapsingHeader("First Person Tree")){
            ImGui.indent();
            // FirstPersonTree firstPersonTree = FirstPersonTree.getTree(detailViewEntity);
            if(ImGui.button("Visualize facing vectors")){
                DebugVisualizerUtils.clientSpawnVectorVisualizer((Entity vector) -> {
                    EntityUtils.getPosition(vector).set(EntityUtils.getPosition(Globals.firstPersonEntity));
                    EntityUtils.getRotation(vector).set(EntityUtils.getRotation(Globals.firstPersonEntity));
                });
                DebugVisualizerUtils.clientSpawnVectorVisualizer((Entity vector) -> {
                    EntityUtils.getPosition(vector).set(EntityUtils.getPosition(Globals.playerEntity));
                    EntityUtils.getRotation(vector).set(EntityUtils.getRotation(Globals.playerEntity));
                });
                DebugVisualizerUtils.clientSpawnVectorVisualizer((Entity vector) -> {
                    int serverIdForClientEntity = Globals.clientSceneWrapper.mapClientToServerId(Globals.playerEntity.getId());
                    Entity serverPlayerEntity = EntityLookupUtils.getEntityById(serverIdForClientEntity);
                    EntityUtils.getPosition(vector).set(EntityUtils.getPosition(serverPlayerEntity));
                    EntityUtils.getRotation(vector).set(EntityUtils.getRotation(serverPlayerEntity));
                });
            }
            ImGui.unindent();
        }
    }


    //stores the edited rotation values
    private static float[] rotationValuesFirstPerson = new float[]{
        0,0,0
    };
    private static float[] rotationValuesThirdPerson = new float[]{
        0,0,0
    };
    private static float[] vectorValuesFirstPerson = new float[]{
        0,0,0
    };
    private static float[] vectorValuesThirdPerson = new float[]{
        0,0,0
    };

    //constraints for vector offset
    private static final float MAXIMUM_OFFSET = 1;
    private static final float MINIMUM_OFFSET = -MAXIMUM_OFFSET;

    /**
     * Client scene equip state view
     */
    protected static void drawEquipState(){
        if(showEquipStateTab && ImGui.collapsingHeader("Equip State Details")){
            ImGui.indent();
            if(detailViewEntity != null && ClientEquipState.getClientEquipState(detailViewEntity) != null){
                ClientEquipState clientEquipState = ClientEquipState.getClientEquipState(detailViewEntity);
                if(ImGui.collapsingHeader("All Equip Points")){
                    for(EquipPoint point : clientEquipState.getAllEquipPoints()){
                        if(ImGui.collapsingHeader(point.getEquipPointId())){
                            ImGui.text("Has item equipped: " + (clientEquipState.getEquippedItemAtPoint(point.getEquipPointId()) != null));
                            ImGui.text("Bone (Third Person): " + point.getBone());
                            ImGui.text("Bone (First Person): " + point.getFirstPersonBone());

                            //offsets
                            ImGui.text("[Third Person] Offset: " + AttachUtils.getEquipPointVectorOffset(point.getOffsetVectorThirdPerson()));
                            if(ImGui.sliderFloat3("[Third Person] Offset", vectorValuesThirdPerson, MINIMUM_OFFSET, MAXIMUM_OFFSET)){
                                Vector3d offset = new Vector3d(vectorValuesThirdPerson[0],vectorValuesThirdPerson[1],vectorValuesThirdPerson[2]);
                                List<Float> newValues = new LinkedList<Float>();
                                newValues.add((float)offset.x);
                                newValues.add((float)offset.y);
                                newValues.add((float)offset.z);
                                point.setOffsetVectorThirdPerson(newValues);
                                Entity equippedEntity = clientEquipState.getEquippedItemAtPoint(point.getEquipPointId());
                                if(equippedEntity != null){
                                    AttachUtils.setVectorOffset(equippedEntity, AttachUtils.getEquipPointVectorOffset(point.getOffsetVectorThirdPerson()));
                                }
                            }
                            ImGui.text("[First Person] Offset: " + AttachUtils.getEquipPointVectorOffset(point.getOffsetVectorFirstPerson()));
                            if(ImGui.sliderFloat3("[First Person] Offset", vectorValuesFirstPerson, MINIMUM_OFFSET, MAXIMUM_OFFSET)){
                                Vector3d offset = new Vector3d(vectorValuesFirstPerson[0],vectorValuesFirstPerson[1],vectorValuesFirstPerson[2]);
                                List<Float> newValues = new LinkedList<Float>();
                                newValues.add((float)offset.x);
                                newValues.add((float)offset.y);
                                newValues.add((float)offset.z);
                                point.setOffsetVectorFirstPerson(newValues);
                                Entity equippedEntity = clientEquipState.getEquippedItemAtPoint(point.getEquipPointId());
                                if(equippedEntity != null){
                                    AttachUtils.setVectorOffset(equippedEntity, AttachUtils.getEquipPointVectorOffset(point.getOffsetVectorFirstPerson()));
                                }
                            }

                            //rotations
                            ImGui.text("[Third Person] Rotation: " + AttachUtils.getEquipPointRotationOffset(point.getOffsetRotationThirdPerson()));
                            if(ImGui.sliderFloat3("[Third Person] Rotation (In Euler along x,y,z)", rotationValuesThirdPerson, 0, (float)(Math.PI * 2))){
                                Quaterniond rotation = new Quaterniond().rotateXYZ(rotationValuesThirdPerson[0], rotationValuesThirdPerson[1], rotationValuesThirdPerson[2]);
                                List<Float> newValues = new LinkedList<Float>();
                                newValues.add((float)rotation.x);
                                newValues.add((float)rotation.y);
                                newValues.add((float)rotation.z);
                                newValues.add((float)rotation.w);
                                point.setOffsetRotationThirdPerson(newValues);
                                Entity equippedEntity = clientEquipState.getEquippedItemAtPoint(point.getEquipPointId());
                                if(equippedEntity != null){
                                    AttachUtils.setRotationOffset(equippedEntity, AttachUtils.getEquipPointRotationOffset(point.getOffsetRotationThirdPerson()));
                                }
                            }
                            ImGui.text("[First Person] Rotation: " + AttachUtils.getEquipPointRotationOffset(point.getOffsetRotationFirstPerson()));
                            if(ImGui.sliderFloat3("[First Person] Rotation (In Euler along x,y,z)", rotationValuesFirstPerson, 0, (float)(Math.PI * 2))){
                                Quaterniond rotation = new Quaterniond().rotateXYZ(rotationValuesFirstPerson[0], rotationValuesFirstPerson[1], rotationValuesFirstPerson[2]);
                                List<Float> newValues = new LinkedList<Float>();
                                newValues.add((float)rotation.x);
                                newValues.add((float)rotation.y);
                                newValues.add((float)rotation.z);
                                newValues.add((float)rotation.w);
                                point.setOffsetRotationFirstPerson(newValues);
                                Entity equippedEntity = clientEquipState.getEquippedItemAtPoint(point.getEquipPointId());
                                if(equippedEntity != null){
                                    AttachUtils.setRotationOffset(equippedEntity, AttachUtils.getEquipPointRotationOffset(point.getOffsetRotationFirstPerson()));
                                }
                            }
                            if(ImGui.button("Print transforms")){
                                LoggerInterface.loggerEngine.WARNING("Third person Offset: " + AttachUtils.getEquipPointVectorOffset(point.getOffsetVectorThirdPerson()));
                                LoggerInterface.loggerEngine.WARNING("First person Offset: " + AttachUtils.getEquipPointVectorOffset(point.getOffsetVectorFirstPerson()));
                                LoggerInterface.loggerEngine.WARNING("Third person Rotation: " + AttachUtils.getEquipPointRotationOffset(point.getOffsetRotationThirdPerson()));
                                LoggerInterface.loggerEngine.WARNING("First person Rotation: " + AttachUtils.getEquipPointRotationOffset(point.getOffsetRotationFirstPerson()));
                            }
                        }
                    }
                }
                
            }
            ImGui.unindent();
        }
    }

    /**
     * Client scene equip state view
     */
    protected static void drawLinkedEntities(){
        if(showLinkedEntitiesTab && ImGui.collapsingHeader("Linked entities")){
            ImGui.indent();
            if(detailViewEntity == Globals.playerEntity && ImGui.button("View Model")){
                showEntity(Globals.firstPersonEntity);
            }
            if(detailViewEntity == Globals.firstPersonEntity && ImGui.button("3rd Person Model")){
                showEntity(Globals.playerEntity);
            }
            if(AttachUtils.getParent(detailViewEntity) != null && ImGui.button("Parent")){
                showEntity(AttachUtils.getParent(detailViewEntity));
            }
            if(AttachUtils.hasChildren(detailViewEntity) && ImGui.collapsingHeader("Children")){
                for(Entity child : AttachUtils.getChildrenList(detailViewEntity)){
                    if(ImGui.button("Child " + child.getId())){
                        showEntity(child);
                    }
                }
            }
            if(ClientEquipState.hasEquipState(detailViewEntity) && ImGui.collapsingHeader("Equipped")){
                ClientEquipState clientEquipState = ClientEquipState.getClientEquipState(detailViewEntity);
                for(String equippedPoint : clientEquipState.getEquippedPoints()){
                    Entity entity = clientEquipState.getEquippedItemAtPoint(equippedPoint);
                    if(ImGui.button("Slot: " + equippedPoint)){
                        showEntity(entity);
                    }
                }
            }
            if(Globals.clientSceneWrapper.clientToServerMapContainsId(detailViewEntity.getId())){
                //detailViewEntity is a client entity
                //get server entity
                int serverIdForClientEntity = Globals.clientSceneWrapper.mapClientToServerId(detailViewEntity.getId());
                Entity serverEntity = EntityLookupUtils.getEntityById(serverIdForClientEntity);
                if(serverEntity != null && ImGui.button("Server Entity")){
                    showEntity(serverEntity);
                }
            } else if(Globals.clientSceneWrapper.containsServerId(detailViewEntity.getId())){
                //detailViewEntity is a server entity
                //get client entity
                int clientId = Globals.clientSceneWrapper.mapServerToClientId(detailViewEntity.getId());
                Entity clientEntity = Globals.clientSceneWrapper.getScene().getEntityFromId(clientId);
                if(clientEntity != null && ImGui.button("Client Entity")){
                    showEntity(clientEntity);
                }
            }
            ImGui.unindent();
        }
    }

    /**
     * Server view dir
     */
    protected static void drawServerViewDir(){
        if(showServerViewDirTab && ImGui.collapsingHeader("Server View Dir")){
            ImGui.indent();
            if(ServerPlayerViewDirTree.hasTree(detailViewEntity)){
                ServerPlayerViewDirTree viewDirTree = ServerPlayerViewDirTree.getTree(detailViewEntity);
                ImGui.text("Yaw: " + viewDirTree.getYaw());
                ImGui.text("Pitch: " + viewDirTree.getPitch());
            }
            ImGui.unindent();
        }
    }

    /**
     * Physics details
     */
    protected static void drawPhysicsDetails(){
        if(showPhysicsTab && ImGui.collapsingHeader("Physics")){
            ImGui.indent();
            if(PhysicsEntityUtils.getDBody(detailViewEntity) != null){
                DBody physicsBody = PhysicsEntityUtils.getDBody(detailViewEntity);
                if(physicsBody != null){
                    ImGui.text("Position: " + EntityUtils.getPosition(detailViewEntity));
                    ImGui.text("Rotation: " + EntityUtils.getRotation(detailViewEntity));
                    ImGui.text("Velocity: " + physicsBody.getLinearVel());
                    ImGui.text("Force: " + physicsBody.getForce());
                    ImGui.text("Angular Velocity: " + physicsBody.getAngularVel());
                    ImGui.text("Torque: " + physicsBody.getTorque());
                    ImGui.text("Move Vector: " + CreatureUtils.getFacingVector(detailViewEntity));
                    ImGui.text("Velocity: " + CreatureUtils.getVelocity(detailViewEntity));
                }
                //synchronized data
                if(Globals.clientSceneWrapper.getScene().getEntityFromId(detailViewEntity.getId()) != null){
                    //detailViewEntity is a client entity
                    //get server entity
                    int serverIdForClientEntity = Globals .clientSceneWrapper.mapClientToServerId(detailViewEntity.getId());
                    Entity serverEntity = EntityLookupUtils.getEntityById(serverIdForClientEntity);
                    DBody serverPhysicsBody = PhysicsEntityUtils.getDBody(serverEntity);
                    if(serverPhysicsBody != null){
                        ImGui.newLine();
                        ImGui.text("Linked server entity:");
                        ImGui.text("Position (Server): " + EntityUtils.getPosition(serverEntity));
                        ImGui.text("Rotation (Server): " + EntityUtils.getRotation(serverEntity));
                        ImGui.text("Velocity (Server): " + serverPhysicsBody.getLinearVel());
                        ImGui.text("Force (Server): " + serverPhysicsBody.getForce());
                        ImGui.text("Angular Velocity: " + serverPhysicsBody.getAngularVel());
                        ImGui.text("Torque: " + serverPhysicsBody.getTorque());
                        ImGui.text("Move Vector (Server): "+ CreatureUtils.getFacingVector(serverEntity));
                        ImGui.text("Velocity (Server): " + CreatureUtils.getVelocity(serverEntity));
                    }
                } else if(Globals.clientSceneWrapper.containsServerId(detailViewEntity.getId())){
                    //detailViewEntity is a server entity
                    //get client entity
                    int clientId = Globals.clientSceneWrapper.mapServerToClientId(detailViewEntity.getId());
                    Entity clientEntity = Globals.clientSceneWrapper.getScene().getEntityFromId(clientId);
                    DBody clientPhysicsBody = PhysicsEntityUtils.getDBody(clientEntity);
                    if(clientPhysicsBody != null){
                        ImGui.newLine();
                        ImGui.text("Linked client entity:");
                        ImGui.text("Position (Client): " + EntityUtils.getPosition(clientEntity));
                        ImGui.text("Rotation (Client): " + EntityUtils.getRotation(clientEntity));
                        ImGui.text("Velocity (Client): " + clientPhysicsBody.getLinearVel());
                        ImGui.text("Force (Client): " + clientPhysicsBody.getForce());
                        ImGui.text("Angular Velocity: " + clientPhysicsBody.getAngularVel());
                        ImGui.text("Torque: " + clientPhysicsBody.getTorque());
                        ImGui.text("Move Vector (Client): " + CreatureUtils.getFacingVector(clientEntity));
                        ImGui.text("Velocity (Client): " + CreatureUtils.getVelocity(clientEntity));
                    }
                }
            }
            ImGui.unindent();
        }
    }

    /**
     * Gets the displayed name of an entity (ie creature type, foliage type, terrain, etc)
     * @param entity
     * @return
     */
    private static String getEntityName(Entity entity){
        if(CreatureUtils.isCreature(entity)){
            return CreatureUtils.getType(entity);
        }
        if(ItemUtils.isItem(entity)){
            return ItemUtils.getType(entity);
        }
        if(FoliageUtils.isFoliage(entity)){
            return FoliageUtils.getFoliageType(entity).getName();
        }
        return "Entity";
    }

}
