package electrosphere.entity.state.inventory;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import electrosphere.client.ui.menu.WindowUtils;
import electrosphere.engine.Globals;
import electrosphere.entity.ClientEntityUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.equip.ClientEquipState;
import electrosphere.entity.state.equip.ClientToolbarState;
import electrosphere.game.data.creature.type.equip.EquipPoint;
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) {
        List<InventoryMessage> bouncedMessages = new LinkedList<InventoryMessage>();
        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());
                            String equipPointId = message.getequipPointId();
                            if(InventoryUtils.hasNaturalInventory(parent)){
                                UnrelationalInventoryState naturalInventory = InventoryUtils.getNaturalInventory(parent);
                                naturalInventory.removeItem(target);
                            }
                            if(InventoryUtils.hasEquipInventory(parent)){
                                RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(parent);
                                equipInventory.tryRemoveItem(target);
                                equipInventory.addItem(equipPointId, target);
                            }
                            if(ClientEquipState.getClientEquipState(parent) != null){
                                ClientEquipState clientEquipState = ClientEquipState.getClientEquipState(parent);
                                clientEquipState.attemptEquip(target, clientEquipState.getEquipPoint(equipPointId));
                            }
                            if(InventoryUtils.hasToolbarInventory(parent)){
                                RelationalInventoryState toolbarInventory = InventoryUtils.getToolbarInventory(parent);
                                toolbarInventory.tryRemoveItem(target);
                            }
                        } break;
                        case InventoryProtocol.INVENTORY_TYPE_NATURAL: {
                            Entity target = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId());
                            if(InventoryUtils.hasNaturalInventory(parent)){
                                UnrelationalInventoryState naturalInventory = InventoryUtils.getNaturalInventory(parent);
                                naturalInventory.removeItem(target);
                                naturalInventory.addItem(target);
                            }
                            if(InventoryUtils.hasEquipInventory(parent)){
                                RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(parent);
                                if(ClientEquipState.getClientEquipState(parent) != null){
                                    ClientEquipState clientEquipState = ClientEquipState.getClientEquipState(parent);
                                    clientEquipState.clientTransformUnequipPoint(equipInventory.getItemSlot(target));
                                }
                                equipInventory.tryRemoveItem(target);
                            }
                            if(InventoryUtils.hasToolbarInventory(parent)){
                                RelationalInventoryState toolbarInventory = InventoryUtils.getToolbarInventory(parent);
                                toolbarInventory.tryRemoveItem(target);
                            }
                        } break;
                        case InventoryProtocol.INVENTORY_TYPE_TOOLBAR: {
                            Entity target = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId());
                            if(InventoryUtils.hasNaturalInventory(parent)){
                                UnrelationalInventoryState naturalInventory = InventoryUtils.getNaturalInventory(parent);
                                naturalInventory.removeItem(target);
                            }
                            if(InventoryUtils.hasEquipInventory(parent)){
                                RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(parent);
                                if(ClientEquipState.getClientEquipState(parent) != null){
                                    ClientEquipState clientEquipState = ClientEquipState.getClientEquipState(parent);
                                    clientEquipState.clientTransformUnequipPoint(equipInventory.getItemSlot(target));
                                }
                                equipInventory.tryRemoveItem(target);
                            }
                            if(InventoryUtils.hasToolbarInventory(parent)){
                                RelationalInventoryState toolbarInventory = InventoryUtils.getToolbarInventory(parent);
                                toolbarInventory.tryRemoveItem(target);
                                toolbarInventory.addItem("" + message.getequipPointId(), target);
                            }
                        }
                    }
                    //once we've switched the items around, redraw the inventory to reflect the updated contents
                    WindowUtils.attemptRedrawInventoryWindows();
                } break;
                case SERVERCOMMANDUNEQUIPITEM: {
                    switch(message.getcontainerType()){
                        case InventoryProtocol.INVENTORY_TYPE_NATURAL: {
                            throw new UnsupportedOperationException("unsupported!");
                        }
                        case InventoryProtocol.INVENTORY_TYPE_EQUIP: {
                            if(ClientEquipState.hasEquipState(parent)){
                                //unequip the item
                                ClientEquipState equipState = ClientEquipState.getEquipState(parent);
                                Entity entityInSlot = equipState.getEquippedItemAtPoint(message.getequipPointId());
                                equipState.clientTransformUnequipPoint(message.getequipPointId());
                                //destroy the in-world manifestation of said item
                                ClientEntityUtils.destroyEntity(entityInSlot);
                            }
                        } break;
                        case InventoryProtocol.INVENTORY_TYPE_TOOLBAR: {
                            if(ClientToolbarState.getClientToolbarState(parent) != null){
                                ClientToolbarState clientToolbarState = ClientToolbarState.getClientToolbarState(parent);
                                clientToolbarState.unequip(message.getequipPointId());
                            }
                        } break;
                    }
                } break;
                case SERVERCOMMANDEQUIPITEM: {
                    //translate equipper id
                    Entity equipper = Globals.clientSceneWrapper.getEntityFromServerId(message.getequipperId());
                    //spawn in world id
                    Entity inWorldEntity = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId());
                    if(inWorldEntity != null){
                        //translate id
                        Globals.clientSceneWrapper.mapIdToId(inWorldEntity.getId(), message.getentityId());
                        switch(message.getcontainerType()){
                            case InventoryProtocol.INVENTORY_TYPE_NATURAL: {
                                throw new UnsupportedOperationException("unsupported!");
                            }
                            case InventoryProtocol.INVENTORY_TYPE_EQUIP: {
                                //grab equip state
                                ClientEquipState equipState = ClientEquipState.getEquipState(equipper);
                                //create entity from template in message
                                //get equippoint
                                String equipPointName = message.getequipPointId();
                                EquipPoint equipPoint = equipState.getEquipPoint(equipPointName);
                                //attach
                                equipState.attemptEquip(inWorldEntity, equipPoint);
                            } break;
                            case InventoryProtocol.INVENTORY_TYPE_TOOLBAR: {
                                //grab toolbar state
                                ClientToolbarState toolbarState = ClientToolbarState.getClientToolbarState(equipper);
                                //attach
                                toolbarState.attemptEquip(inWorldEntity);
                            } break;
                        }
                    } else {
                        bouncedMessages.add(message);
                        // throw new UnsupportedOperationException("TODO: in world item is null");
                    }
                } break;
                case CLIENTREQUESTCRAFT:
                case CLIENTUPDATETOOLBAR:
                case CLIENTREQUESTADDNATURAL:
                case CLIENTREQUESTADDTOOLBAR:
                case CLIENTREQUESTEQUIPITEM:
                case CLIENTREQUESTUNEQUIPITEM:
                case CLIENTREQUESTPERFORMITEMACTION:
                break;
            }
        }
        this.networkMessageQueue.addAll(bouncedMessages);
    }

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