package com.gamepatriot.framework2d.implementation;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;

import com.gamepatriot.androidframework.framework.AndroidAtlas;
import com.gamepatriot.framework2d.R;
import com.gamepatriot.framework2d.implementation.Atlas.SpriteID;

/**
 * The Atlas class loads app-local images and provides function calls to return the images (bitmaps), their {@link AnimationData}, and calls 
 * to instantiate a new {@link Image} based off the resources defined in this class. 
 * 
 * @see AndroidAtlas
 * @author Pete Schmitz, May 8, 2013
 *
 */
public class Atlas implements AndroidAtlas {
	
	/** Flags for instantiating a new Image class through {@link Atlas#createSprite(SpriteID $id, boolean $allowMatrix) createSprite()}, 
	 * or for obtaining references to individual bitmaps and animation data. 
	 */
	public static enum SpriteID{
		EXAMPLE(R.drawable.example);
		
		
		private final int id;
		private Bitmap map;
		private final AnimationData animationData;
		
		private SpriteID(int $id){
			id = $id;
			animationData = null;
		}
		
		private SpriteID(int $id, AnimationData $animationData){
			id = $id;
			animationData = $animationData;
		}
		
		public Bitmap getMap(){
			return map;
		}
		
		public AnimationData getAnimationData(){
			return animationData;
		}
		
		public void load(Main $main){
			if (id == -1) return;
			
			map = BitmapFactory.decodeResource($main.getResources(), id);
		}
		
		public void unload(){
			if (map == null) return;
			
			map.recycle();
		}
		
		public Image getImage(boolean $allowMatrix){
			return getImage(this, $allowMatrix);
		}
		
		/**
		 * Construct a new {@link Image} from a {@link SpriteID}. Automatically assigns the bitmap image and {@link AnimationData} associated with the SpriteID.
		 * @param $id				The {@link SpriteID} of the requested image to return.
		 * @param $allowMatrix		Whether this image will be allowed to handle more expensive draw features (scale and rotation).
		 * @return 					A new {@link Image} of the requested type. It can be added to the display by using {@link Screen#addImage(com.gamepatriot.androidframework.framework.AndroidImage) Screen.addImage()}.
		 */
		public static Image getImage(SpriteID $id, boolean $allowMatrix){
			Image $image = new Image();
			Bitmap $bitmap = $id.getMap();
			AnimationData $adata = $id.getAnimationData();
			if ($adata != null){
				$image.set($bitmap, 0, 0, $adata.frameWidth, $adata.frameHeight, $adata, $allowMatrix);
			} else {
				$image.set($bitmap, 0, 0, $bitmap.getWidth(), $bitmap.getHeight(), null, $allowMatrix);
			}
			
			return $image;
		}
	}
	
	/** Load all resources referenced in the {@link SpriteID} class. This should be called statically (usually in {@link Main}) before any Image requests are made. **/
	public static void load(Main $main){
		for (SpriteID $sprite : SpriteID.values()) $sprite.load($main);
	}
	
	/** Unloads all resources that have been loaded in the {@link SpriteID} class. **/ 
	public static void unload(){
		for (SpriteID $sprite : SpriteID.values()) $sprite.unload();
	}
	
	/** Utility function for rendering a referenced {@link SpriteID} with 4 frames at the corners of the supplied bounds.
	 * 
	 * @param $frame		The SpriteID to render from.
	 * @param $c			The canvas to draw to.
	 * @param $bounds		The bounds to determine where to draw corners at.
	 * @param $spacing		Additional spacing (padding).
	 */
	public static final void renderFrame(SpriteID $frame, Canvas $c, Rect $bounds, int $spacing){
		Image $image = $frame.getImage(false);
		int[] $xreg = {0, 1, 0, 1};
		int[] $yreg = {0, 0, 1, 1};
		int $x;
		int $y;
		int $i;
		Rect $dst = new Rect(0, 0, $image.frameWidth, $image.frameHeight);
		
		for ($i = 0; $i < $xreg.length; $i++){
			$image.frame($i);
			
			$x = $xreg[$i] == 0 ? $spacing + $bounds.left : $bounds.right - $image.frameWidth - $spacing;
			$y = $yreg[$i] == 0 ? $spacing + $bounds.top : $bounds.bottom - $image.frameHeight - $spacing;
			
			$dst.offsetTo($x, $y);
			
			$c.drawBitmap($image.source, $image.srcRect, $dst, null);
		}
		
	}
	
	
}
