/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package csa.tiletools.tiles;

import csa.Global;
import csa.gui.Scaler;
import csa.gui.TimingTriggerer;
import csa.gui.TriggerCallback;
import csa.gui.bitmapfont.BitmapFont;
import csa.tiletools.graphics.BaseImageData;
import csa.tiletools.graphics.ImageSequenceData;
import csa.tiletools.graphics.ImageSequenceDataPool;
import csa.tiletools.map.MapPanel;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

/** This is the instance of one Tile!
 * (in opposite of the TileData, which contains meta data to instantiate a tile)
 *
 * @author salchr
 */

public class Tile extends Paintable
{
    public int accumulatedProbabilityGrowing = 0; // only used from map
    public int tileInLayer=-1;

    
    public static int TILE_TYPE_RECTANGLE  = 0;
    public static int TILE_TYPE_ISO  = 1;
    public static int TILE_TYPE_HEX  = 2;

    TileData data = null;
 
    public boolean isGrown = false; // volatile - only for growing!
    //private double scale = 1; // in 0 - 1

    public boolean isEmptyTile()
    {
        return false;
    }
    public boolean isShallowTile()
    {
        return false;
    }
    public boolean isCompositeTile()
    {
        return false;
    }
    
    // exact the same tile, with SAME data, images etc
    // only coordinates are different!
    public ShallowTile buildShallowClone()
    {
        ShallowTile newTile = new ShallowTile(this);
        return newTile;
    }
    
    // only for shadows
    protected Tile()
    { }

    public Tile(TileData d)
    {
        this(d, true);
    }
    public Tile(TileData d, boolean doInit)
    {
        if (d==null) return;
        data = d;
        if (doInit)
            init();
    }

    public Tile(TileData d, boolean doVariations, TileDataPool tileDataPool)
    {
        if (d==null) return;
        data = d;
        
        if ((d.mVariantNames.size()>0) && (tileDataPool != null))
        {
            int r = csa.Global.getRand().nextInt(100); // percent
            if (r<d.mVariantPercent)
            {
                int t = csa.Global.getRand().nextInt(d.mVariantNames.size()); // percent
                data = tileDataPool.get(data.mVariantNames.elementAt(t));
            }
        }
        init();
    }

    protected void init()
    {
        String name = "Graphics"+File.separator+data.getImageDataFile()+".xml";
        ImageSequenceDataPool pool = getPool(name);
        ImageSequenceData mData = pool.get(data.getImageDataName());
        if (mData==null) return;

        delay = mData.getDelay();

        if (data.mForceTileSize)
        {
            mBData = BaseImageData.toBasePercent(mData, scalePercent, data.mWidth, data.mHeight);
        }
        else
        {
            mBData = BaseImageData.toBasePercent(mData, scalePercent);
        }
        if (mBData==null) return;

        maxWS=0;
        maxHS=0;
        minWidthScaled=Integer.MAX_VALUE;
        minHeightScaled=Integer.MAX_VALUE;
        
        for (int i = 0; i < mBData.size(); i++)
        {
            BaseImageData baseImageData = mBData.elementAt(i);
            if (baseImageData==null) continue;
            if (baseImageData.image==null) continue;
            
            if (maxWS==0)
                maxWS = baseImageData.image.getWidth(null);
            if (maxHS==0)
                maxHS = baseImageData.image.getHeight(null);
            if (maxWS<baseImageData.image.getWidth(null)+baseImageData.ox)
                maxWS = baseImageData.image.getWidth(null)+baseImageData.ox;
            if (maxHS<baseImageData.image.getHeight(null)+baseImageData.oy)
                maxHS = baseImageData.image.getHeight(null)+baseImageData.oy;

            if (minWidthScaled>baseImageData.image.getWidth(null)+baseImageData.ox) minWidthScaled = baseImageData.image.getWidth(null)+baseImageData.ox;
            if (minHeightScaled>baseImageData.image.getHeight(null)+baseImageData.oy) minHeightScaled = baseImageData.image.getHeight(null)+baseImageData.oy;
        }
        if (scalePercent == 100)
        {
            maxHSReal = maxHS;
            minHeightScaledReal = maxHS;
            if (data.mType == TILE_TYPE_ISO)
            {
                maxHS = data.mISOHeight;
                minHeightScaled = maxHS;
            }
            maxWO=maxWS;
            maxHO=maxHS;
            minWidthUnscaled=minWidthScaled;
            minHeightUnscaled=minHeightScaled;
        }
        else
        {
            if (minWidthUnscaled==Integer.MAX_VALUE)
            {
                Vector <BaseImageData> oBData;

                if (data.mForceTileSize)
                    oBData = BaseImageData.toBase(mData, 1, data.mWidth, data.mHeight);
                else
                    oBData = BaseImageData.toBase(mData, 1);
                if (oBData==null) return;

                minWidthUnscaled=Integer.MAX_VALUE;
                minHeightUnscaled=Integer.MAX_VALUE;
                for (int i = 0; i < oBData.size(); i++)
                {
                    BaseImageData baseImageData = oBData.elementAt(i);

                    if (baseImageData==null) continue;
                    if (baseImageData.image==null) continue;
                    if (minWidthUnscaled==Integer.MAX_VALUE)
                        minWidthUnscaled = baseImageData.image.getWidth(null);
                    if (minHeightUnscaled==Integer.MAX_VALUE)
                        minHeightUnscaled = baseImageData.image.getHeight(null);
                   
                    if (minWidthUnscaled>baseImageData.image.getWidth(null)+baseImageData.ox)
                        minWidthUnscaled = baseImageData.image.getWidth(null)+baseImageData.ox;
                    if (minHeightUnscaled>baseImageData.image.getHeight(null)+baseImageData.oy)
                        minHeightUnscaled = baseImageData.image.getHeight(null)+baseImageData.oy;
                }                
            }
            if (maxWO + maxHO == 0)
            {
                Vector <BaseImageData> oBData;

                if (data.mForceTileSize)
                    oBData = BaseImageData.toBase(mData, 1, data.mWidth, data.mHeight);
                else
                    oBData = BaseImageData.toBase(mData, 1);
                if (oBData==null) return;

                maxWO=0;
                maxHO=0;
                for (int i = 0; i < oBData.size(); i++)
                {
                    BaseImageData baseImageData = oBData.elementAt(i);

                    if (maxWO==0)
                        maxWO = baseImageData.image.getWidth(null);
                    if (maxHO==0)
                        maxHO = baseImageData.image.getHeight(null);
                    if (maxWO<baseImageData.image.getWidth(null)+baseImageData.ox)
                        maxWO = baseImageData.image.getWidth(null)+baseImageData.ox;
                    if (maxHO<baseImageData.image.getHeight(null)+baseImageData.oy)
                        maxHO = baseImageData.image.getHeight(null)+baseImageData.oy;
                }
            }
            maxHSReal = maxHS;
            minHeightScaledReal = minHeightScaled;
            maxHOReal = maxHO;
            minHeightUnscaledReal = minHeightUnscaled;
            if (data.mType == TILE_TYPE_ISO)
            {
                maxHS = Scaler.scalePercentToInt(data.mISOHeight, scalePercent);
                //maxHS = (int)((((double)data.mISOHeight)*(scale*100))/100);
                minHeightScaled = maxHS;
                maxHO = data.mISOHeight;
                minHeightUnscaled = maxHO;
            }
        }
        if (mBData.size()<=1) delay = -1;

        if (isDisplayed)
            if (delay!=-1)
                start();
        randomAnim = mData.getRandomAnimationStart();
        if (randomAnim)
        {
            animCounter =  Global.getRand().nextInt(mBData.size());
        }
        else
            animCounter =  0;
    }

    @Override
    public String toString()
    {
        return data.mName;
    }


    @Override // overwrite for ISO
    public int getPaintYScaled() {
        // image data is scaled in image, not here!
        if (data.mType == TILE_TYPE_ISO)
        {
            int y;
            int baseline = data.mISOBaseline;
            
            //int baselineScale = (int)((((double)data.mISOBaseline)*(scale*100.0))/100);

            int baselineScale = Scaler.scalePercentToInt(data.mISOBaseline, scalePercent);
            
            y = YScaled+((int)(mBData.elementAt(animCounter).oy));
            
            int paintOffsetScaled=maxHSReal-maxHS;
            // baseline?
            
            y -= paintOffsetScaled; 
            
            //int offsetYScaled = (int)((((double)data.mISOHeightOffset)*(scale*100.0))/100);
            int offsetYScaled = Scaler.scalePercentToInt(data.mISOHeightOffset, scalePercent);
            
            
            y += offsetYScaled;
            return y;
        }
        return YScaled+((int)(mBData.elementAt(animCounter).oy));
    }    
    
    
    public TileData getData()
    {
        return data;
    }
    public boolean noTile()
    {
        return data == null;
    }



    public static TileData cloneTileData(TileData orgTile)
    {
        if (orgTile == null) return null;
        TileData newTile = new TileData();

	newTile.mClass = orgTile.mClass;
	newTile.mName = orgTile.mName;
	newTile.mWidth = orgTile.mWidth;
	newTile.mHeight = orgTile.mHeight;
	newTile.mType = orgTile.mType;
	newTile.mID = orgTile.mID;
	newTile.mDescription = orgTile.mDescription;
	newTile.mImageDataFile = orgTile.mImageDataFile;
	newTile.mImageDataName = orgTile.mImageDataName;
	newTile.mForceTileSize = orgTile.mForceTileSize;
	newTile.mTileActionLoop = orgTile.mTileActionLoop;
	newTile.mTileActionCanBeBroken = orgTile.mTileActionCanBeBroken;
	newTile.mTileActionSound = orgTile.mTileActionSound;
	newTile.mTileSetFileName = orgTile.mTileSetFileName;
	newTile.mVariantPercent = orgTile.mVariantPercent;

	newTile.mIsTransitionSource = orgTile.mIsTransitionSource;
	newTile.mTransitionPriority = orgTile.mTransitionPriority;
	newTile.mTransitionType = orgTile.mTransitionType;

	newTile.mIsCompositeTile = orgTile.mIsCompositeTile;
	newTile.mCompositeName = orgTile.mCompositeName;
	newTile.mCompositeClass = orgTile.mCompositeClass;
	newTile.mCompositeFile = orgTile.mCompositeFile;

	newTile.mISOBaseline = orgTile.mISOBaseline;
	newTile.mISOHeight = orgTile.mISOHeight;
	newTile.mISOHeightOffset = orgTile.mISOHeightOffset;

        
        
	newTile.mTransitionChildrenNames=new Vector<String>();
        if (orgTile.mTransitionChildrenNames != null)
        {
            for (int i=0; i< orgTile.mTransitionChildrenNames.size(); i++)
                newTile.mTransitionChildrenNames.addElement(orgTile.mTransitionChildrenNames.elementAt(i));
        }

	newTile.mVariantNames=new Vector<String>();
        if (orgTile.mVariantNames != null)
        {
            for (int i=0; i< orgTile.mVariantNames.size(); i++)
                newTile.mVariantNames.addElement(orgTile.mVariantNames.elementAt(i));
        }

        newTile.mAtrributeName=new Vector<String>();
        for (int i=0; i< orgTile.mAtrributeName.size(); i++)
            newTile.mAtrributeName.addElement(orgTile.mAtrributeName.elementAt(i));

	newTile.mAttributeType=new Vector<String>();
        for (int i=0; i< orgTile.mAttributeType.size(); i++)
            newTile.mAttributeType.addElement(orgTile.mAttributeType.elementAt(i));

        newTile.mAttributeValue=new Vector<String>();
        for (int i=0; i< orgTile.mAttributeValue.size(); i++)
            newTile.mAttributeValue.addElement(orgTile.mAttributeValue.elementAt(i));

        newTile.mTileActionIDs=new Vector<String>();
        for (int i=0; i< orgTile.mTileActionIDs.size(); i++)
            newTile.mTileActionIDs.addElement(orgTile.mTileActionIDs.elementAt(i));

        newTile.mTileActionTiles=new Vector<String>();
        for (int i=0; i< orgTile.mTileActionTiles.size(); i++)
            newTile.mTileActionTiles.addElement(orgTile.mTileActionTiles.elementAt(i));
        return newTile;
    }

    // returns -1 if attribute is not available
    public int getAttributeNo(String key)
    {
        for (int i=0; i<data.mAtrributeName.size(); i++)
        {
            String aName =  data.mAtrributeName.elementAt(i);
            if (key.equalsIgnoreCase(aName))
                return i;
        }
        return -1;
    }
    // return null if attribute is not available
    public String[] getAttributes(String key)
    {
        int no = getAttributeNo(key);
        if (no==-1) return null;
        String attributes =data.mAttributeValue.elementAt(no);
        
        String[] ret = attributes.split(",");
        
        for (int i=0; i< ret.length; i++)
        {
            ret[i]=ret[i].trim();
        }
        
        return ret;
    }
    // return null if attribute is not available
    public String getAttribute(String key)
    {
        int no = getAttributeNo(key);
        if (no==-1) return null;
        return data.mAttributeValue.elementAt(no);
    }
    // return null if attribute is not available
    public String getAttributeType(String key)
    {
        int no = getAttributeNo(key);
        if (no==-1) return null;
        return data.mAttributeType.elementAt(no);
    }

    // returns 0 if attribute is not available!
    public int getAttributeInt(String key)
    {
        return csa.util.UtilityString.Int0(getAttribute(key));
    }
    // return null if attribute is not available
    public String getAttributeString(String key)
    {
        return getAttribute(key);
    }
    // true on true, false otherwise (also on no attribute!)
    public boolean getAttributeBool(String key)
    {
        return "TRUE".equalsIgnoreCase(getAttribute(key));
    }
    public boolean hasAttribute(String key)
    {
        return getAttributeNo(key)!=-1;
    }
    

    
    // builds a bitmap fonr from a tileset
    // tiles must have an Attribut "Letter" with the value of the letter of the corresponding font character
    public static BitmapFont buildBitmapFont(String filename, String tileClass)
    {
        BitmapFont bmf = new BitmapFont();
        TileDataPool mTileDataPool = new TileDataPool("Tile"+File.separator+filename+".xml");
        HashMap<String, TileData> tiles = mTileDataPool.getMapForKlasse(tileClass);
        
        Set entries = tiles.entrySet();
        Iterator it = entries.iterator();
        while (it.hasNext())
        {
            Map.Entry entry = (Map.Entry) it.next();
            TileData value = (TileData) entry.getValue();
            Tile tile = new Tile(value);
            String attr = tile.getAttributeString("Letter");
            if (attr == null) continue;
            bmf.addChar(attr, tile.getImage(), 0);
        }
        return bmf;
    }

}
