package electrosphere.entity.state.inventory;

import java.util.concurrent.CopyOnWriteArrayList;

import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.equip.ClientEquipState;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.menu.WindowUtils;
import electrosphere.net.parser.net.message.InventoryMessage;
import electrosphere.net.server.protocol.InventoryProtocol;

/**
 * Principally used to handle network messages related to inventory and thread synchronization
 */
public class ClientInventoryState implements BehaviorTree {

    CopyOnWriteArrayList<InventoryMessage> networkMessageQueue = new CopyOnWriteArrayList<InventoryMessage>();

    Entity parent;

    ClientInventoryState() {

    }

    public static ClientInventoryState clientCreateInventoryState(Entity parent){
        ClientInventoryState rVal = new ClientInventoryState();
        rVal.parent = parent;
        Globals.clientSceneWrapper.getScene().registerBehaviorTree(rVal);
        return rVal;
    }

    @Override
    public void simulate(float deltaTime) {
        for(InventoryMessage message : networkMessageQueue){
            networkMessageQueue.remove(message);
            switch(message.getMessageSubtype()){
                case ADDITEMTOINVENTORY: {
                    //the ID we get is of the in-inventory item
                    Entity inInventorySpawnedItem = InventoryUtils.clientConstructInInventoryItem(parent,message.getitemTemplate());
                    //map id
                    if(inInventorySpawnedItem != null){
                        Globals.clientSceneWrapper.mapIdToId(inInventorySpawnedItem.getId(), message.getentityId());
                    }
                    //attempt re-render ui
                    WindowUtils.attemptRedrawInventoryWindows();
                } break;
                case REMOVEITEMFROMINVENTORY: {
                    InventoryUtils.removeItemFromInventories(parent, Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId()));
                    //attempt re-render ui
                    WindowUtils.attemptRedrawInventoryWindows();
                } break;
                case SERVERCOMMANDMOVEITEMCONTAINER: {
                    //this is a command to switch an item from one inventory to another (ie equip->natural or vice-versa)
                    switch(message.getcontainerType()){
                        case InventoryProtocol.INVENTORY_TYPE_EQUIP: {
                            Entity target = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId());
                            boolean isInventoryItem = ItemUtils.itemIsInInventory(target);
                            boolean parentHasNaturalInventory = InventoryUtils.hasNaturalInventory(parent);
                            boolean parentHasEquipInventory = InventoryUtils.hasEquipInventory(parent);
                            String equipPointId = message.getequipPointId();
                            //check that we can do the transform
                            if(isInventoryItem && parentHasEquipInventory && parentHasNaturalInventory){
                                //switch containers
                                UnrelationalInventoryState naturalInventory = InventoryUtils.getNaturalInventory(parent);
                                RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(parent);
                                naturalInventory.removeItem(target);
                                equipInventory.addItem(equipPointId, target);
                            }
                        } break;
                        case InventoryProtocol.INVENTORY_TYPE_NATURAL: {
                            Entity target = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId());
                            boolean isInventoryItem = ItemUtils.itemIsInInventory(target);
                            boolean parentHasNaturalInventory = InventoryUtils.hasNaturalInventory(parent);
                            boolean parentHasEquipInventory = InventoryUtils.hasEquipInventory(parent);
                            String equipPointId = message.getequipPointId();
                            //check that we can do the transform
                            if(isInventoryItem && parentHasEquipInventory && parentHasNaturalInventory){
                                //switch containers
                                UnrelationalInventoryState naturalInventory = InventoryUtils.getNaturalInventory(parent);
                                RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(parent);
                                naturalInventory.addItem(target);
                                equipInventory.removeItemSlot(equipPointId);
                            }
                        } break;
                    }
                    //once we've switched the items around, redraw the inventory to reflect the updated contents
                    WindowUtils.attemptRedrawInventoryWindows();
                } break;
                case SERVERCOMMANDUNEQUIPITEM: {
                    if(Globals.playerEntity != null && ClientEquipState.hasEquipState(Globals.playerEntity)){
                        //unequip the item
                        ClientEquipState equipState = ClientEquipState.getEquipState(Globals.playerEntity);
                        Entity entityInSlot = equipState.getEquippedItemAtPoint(message.getequipPointId());
                        equipState.clientTransformUnequipPoint(message.getequipPointId());
                        //destroy the in-world manifestation of said item
                        EntityUtils.cleanUpEntity(entityInSlot);
                    }
                } break;
                case CLIENTREQUESTEQUIPITEM:
                case CLIENTREQUESTUNEQUIPITEM:
                case CLIENTREQUESTPERFORMITEMACTION:
                case SERVERCOMMANDEQUIPITEM:
                break;
            }
        }
    }

    public void addNetworkMessage(InventoryMessage networkMessage) {
        networkMessageQueue.add(networkMessage);
    }
    
}
