package electrosphere.game.data.item;

import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import electrosphere.controls.PlayerCursor;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.game.data.block.BlockType;
import electrosphere.game.data.common.CommonEntityType;
import electrosphere.game.data.common.item.SpawnItemDescription;
import electrosphere.game.data.graphics.GraphicsTemplate;
import electrosphere.game.data.graphics.NonproceduralModel;
import electrosphere.renderer.RenderUtils;

/**
 * Data on a given item
 */
public class Item extends CommonEntityType {

    /**
     * The default item icon path
     */
    static final String DEFAULT_ITEM_ICON_PATH = "Textures/icons/itemIconItemGeneric.png";

    /**
     * The array of default tokens for all items
     */
    static final String[] DEFAULT_TOKENS = new String[]{
        "GRAVITY",
        "TARGETABLE",
    };

    /**
     * The idle animation for the item
     */
    String idleAnim;

    /**
     * The path for the icon texture for this item
     */
    String iconPath;

    /**
     * Weapon data for this item if it is an item
     */
    WeaponData weaponData;

    /**
     * The data defining how this item is equipped
     */
    EquipData equipData;

    /**
     * The audio data for the item
     */
    ItemAudio itemAudio;

    /**
     * A hook that should fire client-side when the player uses this as their primary item
     */
    String clientSidePrimary;

    /**
     * A hook that should fire client-side when the player uses this as their primary item
     */
    String clientSideSecondary;

    /**
     * The usage logic for a secondary usage of this item
     */
    ItemUsage secondaryUsage;
    
    /**
     * Creates item data from a spawn item description
     * @param description The spawn item description
     * @return The item data
     */
    public static Item createSpawnItem(CommonEntityType objectData){
        SpawnItemDescription description = objectData.getSpawnItem();


        Item rVal = new Item();
        rVal.setId(objectData.getId());


        if(description.getItemIcon() != null){
            rVal.iconPath = description.getItemIcon();
        } else {
            rVal.iconPath = Item.DEFAULT_ITEM_ICON_PATH;
        }
        if(description.getGraphicsTemplate() != null){
            rVal.setGraphicsTemplate(description.getGraphicsTemplate());
        } else {
            throw new Error("Need to implement handling for when no graphics template is provided!");
        }


        //set usage
        ItemUsage usage = new ItemUsage();
        usage.setSpawnEntityId(objectData.getId());
        rVal.setSecondaryUsage(usage);

        
        //attach common tokens
        rVal.setTokens(Arrays.asList(DEFAULT_TOKENS));

        return rVal;
    }

    /**
     * Creates item data from a block type
     * @param description The block type
     * @return The item data
     */
    public static Item createBlockItem(BlockType blockType){
        Item rVal = new Item();
        rVal.setId(blockType.getName());


        if(blockType.getTexture() != null){
            rVal.iconPath = blockType.getTexture();
        } else {
            rVal.iconPath = Item.DEFAULT_ITEM_ICON_PATH;
        }


        NonproceduralModel modelData = new NonproceduralModel();
        modelData.setPath(AssetDataStrings.MODEL_BLOCK_SINGLE);
        GraphicsTemplate blockItemGraphicsTemplate = new GraphicsTemplate();
        blockItemGraphicsTemplate.setModel(modelData);
        rVal.setGraphicsTemplate(blockItemGraphicsTemplate);

        //set uniforms for the model
        Map<String,Map<String,Object>> meshUniformMap = new HashMap<String,Map<String,Object>>();
        Map<String,Object> uniforms = new HashMap<String,Object>();
        uniforms.put("blockAtlasIndex",Globals.blockTextureAtlas.getVoxelTypeOffset(blockType.getId()));
        meshUniformMap.put(RenderUtils.MESH_NAME_BLOCK_SINGLE,uniforms);
        modelData.setUniforms(meshUniformMap);

        //set item class
        rVal.equipData = new EquipData();
        rVal.equipData.equipClass = "tool";


        //set usage
        ItemUsage usage = new ItemUsage();
        usage.setBlockId(blockType.getId());
        rVal.setSecondaryUsage(usage);

        
        //attach common tokens
        List<String> tokens = new LinkedList<String>(Arrays.asList(DEFAULT_TOKENS));
        tokens.add(PlayerCursor.CURSOR_BLOCK_TOKEN);
        rVal.setTokens(tokens);

        return rVal;
    }

    /**
     * the idle animation for the item
     * @return
     */
    public String getIdleAnim(){
        return idleAnim;
    }
    
    /**
     * the path for the icon texture for this item
     * @return
     */
    public String getIconPath(){
        return iconPath;
    }

    /**
     * weapon data for this item if it is an item
     * @return
     */
    public WeaponData getWeaponData(){
        return weaponData;
    }

    /**
     * Gets the equip data for the item type
     * @return The equip data
     */
    public EquipData getEquipData(){
        return equipData;
    }

    /**
     * Gets the item audio data
     * @return The audio data if specified, null otherwise
     */
    public ItemAudio getItemAudio(){
        return itemAudio;
    }
    
    /**
     * Gets the client side primary hook to fire
     * @return The hook
     */
    public String getClientSidePrimary(){
        return clientSidePrimary;
    }

    /**
     * Gets the client side secondary hook to fire
     * @return The hook
     */
    public String getClientSideSecondary(){
        return clientSideSecondary;
    }
    /**
     * Gets the secondary usage logic of this item
     * @return The secondary usage logic
     */
    public ItemUsage getSecondaryUsage(){
        return secondaryUsage;
    }

    /**
     * Sets the secondary usage logic of this item
     * @param secondaryUsage The secondary usage logic
     */
    public void setSecondaryUsage(ItemUsage secondaryUsage){
        this.secondaryUsage = secondaryUsage;
    }

}
