package sim;

import java.awt.*;

public abstract class RotatableFlippableWrapperPainted extends WrapperPainted
{
/* ==================================================================
	Rotation abd Flipping Part
	================================================================= */
	public boolean canRotate()
	{
		return true;
	}
	
	public boolean canFlip()
	{
		return true;
	}
	
	public void flipHorizontal()
	{
		this.isFlipped = !this.isFlipped;
		this.angle = (this.angle + 180) % 360;
		this.adjustToChanges();
	}
	
	public void flipVertical()
	{
		this.isFlipped = !this.isFlipped;
		this.adjustToChanges();
	}
	
	public void setFlipped(boolean newFlip)
	{
		this.isFlipped = newFlip;
		this.adjustToChanges();
	}
	
	public void setAngle(int newAngle)
	{
		this.angle = newAngle;
		
		if((this.angle == 90) && this.isFlipped)
			this.angle = 270;
		else if((this.angle == 270) && this.isFlipped)
			this.angle = 90;
		
		this.adjustToChanges();
	}
	
	public void rotateLeft()
	{
		if(this.isFlipped)
			this.angle = (this.angle + 270) % 360;
		else
			this.angle = (this.angle + 90) % 360;
		
		this.adjustToChanges();
	}
	
	public void rotateRight()
	{
		if(this.isFlipped)
			this.angle = (this.angle + 90) % 360;
		else
			this.angle = (this.angle + 270) % 360;
		
		this.adjustToChanges();
	}
	
	public void restoreAngleFlipped(int oldAngle, boolean oldFlip)
	{
		this.angle = oldAngle;
		this.isFlipped = oldFlip;
		
		this.adjustToChanges();
	}
	
	protected abstract void adjustToChanges();
	
	public void paint(Graphics g)
	{
		if(this.isVisible())
		{
			if(this.isFlipped)
			{
				if(this.angle == 0)
					this.paintFlipped_0(g);
				else if(this.angle == 90)
					this.paintFlipped_90(g);
				else if(this.angle == 180)
					this.paintFlipped_180(g);
				else
					this.paintFlipped_270(g);
			}
			else
			{
				if(this.angle == 0)
					this.paintNormal_0(g);
				else if(this.angle == 90)
					this.paintNormal_90(g);
				else if(this.angle == 180)
					this.paintNormal_180(g);
				else
					this.paintNormal_270(g);
			}
			
		}
	}
	
	protected abstract void paintNormal_0(Graphics g);
	protected abstract void paintNormal_90(Graphics g);
	protected abstract void paintNormal_180(Graphics g);
	protected abstract void paintNormal_270(Graphics g);
	protected abstract void paintFlipped_0(Graphics g);
	protected abstract void paintFlipped_90(Graphics g);
	protected abstract void paintFlipped_180(Graphics g);
	protected abstract void paintFlipped_270(Graphics g);
	
	public boolean canDrop()
	{
		boolean result;
		
		if(this.isFlipped)
		{
			if(this.angle == 0)
				result = this.canDropFlipped_0();
			else if(this.angle == 90)
				result = this.canDropFlipped_90();
			else if(this.angle == 180)
				result = this.canDropFlipped_180();
			else
				result = this.canDropFlipped_270();
		}
		else
		{
			if(this.angle == 0)
				result = this.canDropNormal_0();
			else if(this.angle == 90)
				result = this.canDropNormal_90();
			else if(this.angle == 180)
				result = this.canDropNormal_180();
			else
				result = this.canDropNormal_270();
		}
		
		return result;
	}
	
	protected abstract boolean canDropNormal_0();
	protected abstract boolean canDropNormal_90();
	protected abstract boolean canDropNormal_180();
	protected abstract boolean canDropNormal_270();
	protected abstract boolean canDropFlipped_0();
	protected abstract boolean canDropFlipped_90();
	protected abstract boolean canDropFlipped_180();
	protected abstract boolean canDropFlipped_270();
	
	public void droped()
	{
		if(this.isFlipped)
		{
			if(this.angle == 0)
				this.dropedFlipped_0();
			else if(this.angle == 90)
				this.dropedFlipped_90();
			else if(this.angle == 180)
				this.dropedFlipped_180();
			else
				this.dropedFlipped_270();
		}
		else
		{
			if(this.angle == 0)
				this.dropedNormal_0();
			else if(this.angle == 90)
				this.dropedNormal_90();
			else if(this.angle == 180)
				this.dropedNormal_180();
			else
				this.dropedNormal_270();
		}
	}
	
	protected abstract void dropedNormal_0();
	protected abstract void dropedNormal_90();
	protected abstract void dropedNormal_180();
	protected abstract void dropedNormal_270();
	protected abstract void dropedFlipped_0();
	protected abstract void dropedFlipped_90();
	protected abstract void dropedFlipped_180();
	protected abstract void dropedFlipped_270();
	
/* ==================================================================
	Storage Part
	================================================================= */
	public String getParameters()
	{
		String result;
		
		// Wrapper Basic
		result = Integer.toString(this.gridSize.width) + Wrapper.SEPARATOR + Integer.toString(this.gridSize.height) + Wrapper.SEPARATOR;
		result = result + Integer.toString(this.gridLocation.x) + Wrapper.SEPARATOR + Integer.toString(this.gridLocation.y) + Wrapper.SEPARATOR;
		result = result + Integer.toString(this.angle) + Wrapper.SEPARATOR + this.isFlipped + Wrapper.SEPARATOR;
		
		// Wrapper Specifics
		result = result + this.getSpecificParameters();
		
		return result;
	}
	
	public int getNumberOfBasicParameters()
	{
		return 6;
	}
	
	public void initialiseWrapper(String[] basicParameters, String[] specificParameters) throws SimException
	{
		if(basicParameters.length == this.getNumberOfBasicParameters())
		{
			try
			{
				this.setGridSize(Integer.valueOf(basicParameters[0]).intValue(), Integer.valueOf(basicParameters[1]).intValue());
				this.setGridLocation(Integer.valueOf(basicParameters[2]).intValue(), Integer.valueOf(basicParameters[3]).intValue());
				this.angle = Integer.valueOf(basicParameters[4]).intValue();
				this.isFlipped = Boolean.valueOf(basicParameters[5]).booleanValue();
				this.loadWrapper(specificParameters);
			}
			catch(NumberFormatException e)
			{
				throw (new SimException("incorrect parameter type"));
			}
		}
		else
			throw (new SimException("incorrect number of parameters"));
	}
	
}