package electrosphere.server.content.serialization;

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

import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.equip.ServerEquipState;
import electrosphere.entity.state.inventory.InventoryUtils;
import electrosphere.entity.types.creature.CreatureEquipData.EquippedItem;
import electrosphere.entity.types.creature.CreatureTemplate;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.foliage.FoliageUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.entity.types.object.ObjectUtils;
import electrosphere.entity.types.structure.StructureUtils;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.datacell.utils.EntityLookupUtils;
import electrosphere.util.Utilities;

/**
 * Contains all content for a given cell
 */
public class ContentSerialization {


    //The entities, serialized
    List<EntitySerialization> serializedEntities = new LinkedList<EntitySerialization>();

    /**
     * Constructs a content serialization of a given list of entities
     * @param entities The entities
     * @return The content serialization
     */
    public static ContentSerialization constructContentSerialization(List<Entity> entities){
        ContentSerialization rVal = new ContentSerialization();
        for(Entity entity : entities){
            if(!CreatureUtils.hasControllerPlayerId(entity)){
                if(CreatureUtils.isCreature(entity)){
                    EntitySerialization serializedEntity = new EntitySerialization();
                    serializedEntity.setPosition(EntityUtils.getPosition(entity));
                    serializedEntity.setRotation(EntityUtils.getRotation(entity));
                    serializedEntity.setType(CreatureUtils.ENTITY_TYPE_CREATURE);
                    serializedEntity.setSubtype(CreatureUtils.getType(entity));
                    if(CreatureUtils.getCreatureTemplate(entity) != null){
                        serializedEntity.setTemplate(Utilities.stringify(CreatureUtils.getCreatureTemplate(entity)));
                    }
                    rVal.serializedEntities.add(serializedEntity);
                }
                if(ItemUtils.isItem(entity) && ItemUtils.itemShouldBeSerialized(entity)){
                    EntitySerialization serializedEntity = new EntitySerialization();
                    serializedEntity.setPosition(EntityUtils.getPosition(entity));
                    serializedEntity.setRotation(EntityUtils.getRotation(entity));
                    serializedEntity.setType(ItemUtils.ENTITY_TYPE_ITEM);
                    serializedEntity.setSubtype(ItemUtils.getType(entity));
                    rVal.serializedEntities.add(serializedEntity);
                }
                if(ObjectUtils.isObject(entity)){
                    EntitySerialization serializedEntity = new EntitySerialization();
                    serializedEntity.setPosition(EntityUtils.getPosition(entity));
                    serializedEntity.setRotation(EntityUtils.getRotation(entity));
                    serializedEntity.setType(ObjectUtils.ENTITY_TYPE_OBJECT);
                    serializedEntity.setSubtype(ObjectUtils.getType(entity));
                    rVal.serializedEntities.add(serializedEntity);
                }
                if(StructureUtils.isStructure(entity)){
                    throw new UnsupportedOperationException("Not implemented");
                }
                if(FoliageUtils.isFoliage(entity)){
                    if(FoliageUtils.hasSeed(entity)){
                        EntitySerialization serializedEntity = new EntitySerialization();
                        serializedEntity.setPosition(EntityUtils.getPosition(entity));
                        serializedEntity.setRotation(EntityUtils.getRotation(entity));
                        serializedEntity.setType(FoliageUtils.ENTITY_TYPE_FOLIAGE);
                        serializedEntity.setSubtype(FoliageUtils.getFoliageType(entity).getName());
                        serializedEntity.setTemplate(FoliageUtils.getFoliageSeed(entity) + "");
                        rVal.serializedEntities.add(serializedEntity);
                    } else {
                        throw new UnsupportedOperationException("Not implemented");
                    }
                }
            }
        }
        return rVal;
    }

    /**
     * Actually creates the entities from a content serialization
     * @param contentRaw The content serialization
     */
    public void hydrateRawContent(Realm realm, ServerDataCell serverDataCell){
        List<EntitySerialization> serializedEntities = this.getSerializedEntities();
        for(EntitySerialization serializedEntity : serializedEntities){
            switch(serializedEntity.getType()){
                case CreatureUtils.ENTITY_TYPE_CREATURE: {
                    CreatureTemplate template = null;
                    if(serializedEntity.getTemplate() != null){
                        template = Utilities.deserialize(serializedEntity.getTemplate(), CreatureTemplate.class);
                    }

                    //
                    //Spawn the creature itself
                    Entity creature = CreatureUtils.serverSpawnBasicCreature(realm, serializedEntity.getPosition(), serializedEntity.getSubtype(), template);
                    EntityUtils.getRotation(creature).set(serializedEntity.getRotation());

                    //
                    //now that creature has been spawned, need to create all attached items
                    if(template != null && template.getCreatureEquipData() != null && template.getCreatureEquipData().getSlots() != null){
                        for(String equipSlotId : template.getCreatureEquipData().getSlots()){

                            //spawn the item in the world
                            EquippedItem itemDefinition = template.getCreatureEquipData().getSlotItem(equipSlotId);
                            Entity itemInWorld = ItemUtils.serverSpawnBasicItem(realm, serializedEntity.getPosition(), itemDefinition.getItemType());

                            //add the item to the creature's inventory
                            Entity itemInInventory = InventoryUtils.serverAttemptStoreItem(creature, EntityLookupUtils.getEntityById(itemInWorld.getId()));

                            //equip the item to the slot defined in the template
                            ServerEquipState serverEquipState = ServerEquipState.getEquipState(creature);
                            serverEquipState.commandAttemptEquip(itemInInventory,serverEquipState.getEquipPoint(equipSlotId));
                        }
                    }
                } break;
                case ItemUtils.ENTITY_TYPE_ITEM: {
                    Entity item = ItemUtils.serverSpawnBasicItem(realm, serializedEntity.getPosition(), serializedEntity.getSubtype());
                    EntityUtils.getRotation(item).set(serializedEntity.getRotation());
                } break;
                case ObjectUtils.ENTITY_TYPE_OBJECT: {
                    Entity object = ObjectUtils.serverSpawnBasicObject(realm, serializedEntity.getPosition(), serializedEntity.getSubtype());
                    EntityUtils.getRotation(object).set(serializedEntity.getRotation());
                } break;
                case FoliageUtils.ENTITY_TYPE_FOLIAGE: {
                    long seed = Long.parseLong(serializedEntity.getTemplate());
                    Entity foliage = FoliageUtils.serverSpawnTreeFoliage(realm, serializedEntity.getPosition(), serializedEntity.getSubtype(), seed);
                    EntityUtils.getRotation(foliage).set(serializedEntity.getRotation());
                } break;
            }
        }
    }

    /**
     * Gets all serialized entities
     * @return the list of serialized entities
     */
    public List<EntitySerialization> getSerializedEntities(){
        return serializedEntities;
    }
    
}
