import java.awt.*;
import java.awt.event.*;												//Event handling interfaces etc
import java.awt.image.*;												//Image handling stuff
import java.util.*;

/*================================================*
 *												  *
 *	Custom canvas object for GFX operations.	  *
 *												  *
 *	Used as a source canvas for holding the tile  * 
 *	images, and as a destination canvas to hold	  *
 *	the map being drawn.						  *
 *												  *
 *================================================*/
	
public class BlockCanvas extends Canvas
{
	
	private int currentSize;						//Current size of the block
	private int selectorXPos, selectorYPos;			//
	
	private PixelGrabber currentTile;				//Class which holds a subset of pixels 
	private int tileImage[];						//Array to hold grabbed pixels
		
	private Image bImage;							//Block image - the n*n pixel block
	
	Vector mapBlocks;

	Color col;
	
	private BlockContainer[][] mapComponents;		//Array of map components
	private BlockContainer current_bc;				//Current map component
	private int[][] mapdata;						//Array of block ID's
	
	private int mapWidth;
	private int mapHeight;
	
	
/*===============================================*
 * Constructor class for block canvas 				 *
 *===============================================*/
	
	public BlockCanvas()
	{
		bImage=null;
		selectorXPos=0;
		selectorYPos=0;
		currentSize=4;								//1<<4=16
		currentTile=null;
		tileImage=new int[(1<<currentSize)*(1<<currentSize)];
		col=null;
			
		mapWidth=20;
		mapHeight=16;
	
		mapComponents=new BlockContainer[20][16];	
		mapdata=new int[20][16];
		
		for(int y=0;y<mapHeight;y++)
		{
			for(int x=0;x<mapWidth;x++)
			{
				mapdata[x][y]=0xffff;
			}
		}
	}	
		
	
/*===============================================*  
 *  Set size of the block to grab				 *
 *-----------------------------------------------*
 *  When the block size is changed, we also need
 *	to change the size of the destination array 
 *	that holds the raw pixel data from a grab.
 *-----------------------------------------------*/
	
	public void setBlockSize(int size)
	{
		currentSize=size;
		tileImage=new int[(1<<currentSize)*(1<<currentSize)];		
	}

	
	
/*
	update mouse position info
*/
	
	public void setSelectorXPos(int xpos)
	{
		selectorXPos=xpos;
	}
	

	public void setSelectorYPos(int ypos)
	{
		selectorYPos=ypos;
	}

		
	public void loadImage(Image img)
	{
		bImage=img;
		this.repaint();
	}
		
		
/*=====================================================*
 * Routine: Grab a tile from the source image		   *
 *-----------------------------------------------------*
 *	in: xpos, ypos:  top lh corner of block			   *
 *	out:  raw image data							   *
 *													   *
 *	This routine selects an area of the canvas to 	   *
 *	an integral number of blocks, then copies the      *
 *	raw pixel data to an array, which is returned.     *
 *=====================================================*/
		
	public Object getTile(int xPos,int yPos)
	{
		
		currentTile=new PixelGrabber(bImage,xPos,yPos,(1<<currentSize),(1<<currentSize),tileImage,0,(1<<currentSize));
		
		try
		{
			currentTile.grabPixels();
		}
		
		catch(InterruptedException e)
		{
			System.out.println("pixel grabber operation interrupted");
		}
			
		return((Object)tileImage);	
	}
		
		
/**
 *
 *	Return the BlockContainer array
 *
 **/

	public Object getMapData()
	{
		return((Object)mapComponents);
	}
	
	public Object getRawMapData()
	{
		return((Object)mapdata);
	}
		
		
	public void changeMapSize(int xsize,int ysize)
	{
		mapComponents=new BlockContainer[xsize][ysize];
		mapdata=new int[xsize][ysize];
		
		for(int y=0;y<ysize;y++)				//fill raw data with 0xffff to indicate
		{										//  blank block
			for(int x=0;x<xsize;x++)
			{
				mapdata[x][y]=0xffff;
			}
		}
		
		mapWidth=xsize;
		mapHeight=ysize;
	}
		
/**
 *
 *	Put the currently selected block in the map component array
 *	for display later on
 *
 **/
	
	public void putTile(BlockContainer bc,boolean delete)
	{
	//	current_bc=bc;
		
		int xt=bc.xPos>>currentSize;
		int yt=bc.yPos>>currentSize;

	/*
		Add/remove blocks from the array - if the block in the
		position in the array is the same as the one being inserted,
		then remove it to make a gap.  Or else put the block in there.
	 */		
		
		try
		{
			if(delete)									//i.e. if control held down
			{
				bc=null;
				getGraphics().clearRect(xt<<currentSize,yt<<currentSize,(1<<currentSize),(1<<currentSize));		
			}
			
			if(bc==null) 
			{										
				mapdata[xt][yt]=0xffff;			//set number to 0xffff if null, or else leave alone
			}
			else
			{
				mapdata[xt][yt]=bc.blockNumber;
			}
			
			mapComponents[xt][yt]=bc;				
			
			repaint(xt<<currentSize,yt<<currentSize,(1<<currentSize),(1<<currentSize));
		}
			
		catch(ArrayIndexOutOfBoundsException e)
		{
				// do nothing, just stop the horrible looking exception message from appearing
		}
	}
	

	
/**
 *	Update() method for the canvas
 *	
 *	This is similar to the paint() method in operation,
 *	except it doesn't clear the screen first, eliminating
 *	that proper hanging flicker
 *	
 **/
	
	public void update(Graphics g)
	{
		for(int y=0;y<mapHeight;y++)
		{
			for(int x=0;x<mapWidth;x++)
			{
				if(mapComponents[x][y]!=null)
				{
					g.drawImage(mapComponents[x][y].blockImage,mapComponents[x][y].xPos,mapComponents[x][y].yPos,this);
				}	
			}
		}
	}
	

/**
 *
 *	Put map data into array (used when loading maps)
 *
 **/

	public void putMapData(Object mapdata)
	{
		mapComponents=(BlockContainer[][])mapdata;
		repaint();
	}

	
/**
 *	
 *	Paint method
 *		
 *	Clears the screen, then draws it again
 *	
 **/
		
	public void paintAll(Graphics g)
	{
		for(int y=0;y<mapHeight;y++)
		{
			for(int x=0;x<mapWidth;x++)
			{
				if(mapComponents[x][y]!=null)
				{
					g.drawImage(mapComponents[x][y].blockImage,mapComponents[x][y].xPos,mapComponents[x][y].yPos,this);
				}
			}
		}
	}

}
