package graphics.sprite;

import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;

import br.ufsc.inf.leobr.cliente.Jogada;
import system.character.Ally;
import system.character.BaseCharacter;
import system.character.Enemy;

public class TileSprite extends JLabel implements Jogada {
	/**
	 * Serve pra não dar merda na serialização de objetos.
	 */
	private static final long serialVersionUID = 6163766969462544959L;

	
	/**
	 * A imagem padrão deste Sprite
	 * */
	private BufferedImage floor;
	
	private BufferedImage attack;
	private BufferedImage move;
	private BufferedImage radius;
	
	private BufferedImage heroSprite;
	private BufferedImage enemySprite;
	
	ImageIcon tile;
	
	/**
	 * Cria um sprite para representar o chão de um tile.
	 * @param x posição x na tela
	 * @param y posição y na tela
	 */
	public TileSprite(int x, int y) {
		// Procedimento padrão = changeTile()
		setLocation(x, y);
	}
	
	/**
	 * Muda o tile para representar os diferentes estados que ele pode se encontrar.<br>
	 * Use este método toda vez que quiser alterar a imagem do tile ou simplesmente mostrá-lo<br>
	 * Valores válidos: floor, movement, attack, radius
	 * @param name algum valor válido
	 */
	public void changeTile(String name, BaseCharacter baseChar) {
		BufferedImage aux = new BufferedImage(floor.getWidth(), floor.getHeight(), BufferedImage.TYPE_INT_ARGB);
		
		if (name.equalsIgnoreCase("Floor")) {
			tile = new ImageIcon(floor);
			aux = floor;
			setIcon(tile);
			setSize(tile.getIconWidth(), tile.getIconHeight());
		}
		
		if (name.equalsIgnoreCase("Movement")) {
			tile = new ImageIcon(move);
			aux = move;
			setIcon(tile);
			setSize(tile.getIconWidth(), tile.getIconHeight());
		}
		
		if (name.equalsIgnoreCase("Attack")) {
			tile = new ImageIcon(attack);
			aux = attack;
			setIcon(tile);
			setSize(tile.getIconWidth(), tile.getIconHeight());
		}
		
		if (name.equalsIgnoreCase("Radius")) {
			tile = new ImageIcon(radius);
			aux = radius;
			setIcon(tile);
			setSize(tile.getIconWidth(), tile.getIconHeight());
		}
		
		if (baseChar != null) {
			if (baseChar.getClass() == Ally.class) {
				double scale = 1.5;
				BufferedImage shit = new BufferedImage((int) (heroSprite.getWidth() * scale), (int) (heroSprite.getHeight() * scale), BufferedImage.TYPE_INT_ARGB);
				BufferedImage shitAux = new BufferedImage(shit.getWidth(), shit.getHeight(), BufferedImage.TYPE_INT_ARGB);
				
				rescale(heroSprite, shitAux, scale, scale);
	
				Graphics2D graphics = shit.createGraphics();
				graphics.drawImage(aux, null, 0, 0);
				graphics.drawImage(shitAux, null, 0, 0);
				graphics.dispose();
				
				tile = new ImageIcon(shit);
				setIcon(tile);
				setSize(tile.getIconWidth(), tile.getIconHeight());
			}
			
			if (baseChar.getClass() == Enemy.class) {
				double scale = 1.5;
				BufferedImage shit = new BufferedImage((int) (enemySprite.getWidth() * scale), (int) (enemySprite.getHeight() * scale), BufferedImage.TYPE_INT_ARGB);
				BufferedImage shitAux = new BufferedImage(shit.getWidth(), shit.getHeight(), BufferedImage.TYPE_INT_ARGB);
				rescale(enemySprite, shitAux, scale, scale);
	
				Graphics2D graphics = shit.createGraphics();
				graphics.drawImage(aux, null, 0, 0);
				graphics.drawImage(shitAux, null, 0, 0);
				graphics.dispose();
				
				tile = new ImageIcon(shit);
				setIcon(tile);
				setSize(tile.getIconWidth(), tile.getIconHeight());
			}
		}
	}
	
	/**
	 * Carrega um sprite do arquivo file
	 * @param file o nome do arquivo
	 * @return uma BufferedImage contendo a imagem que se deseja
	 */
     public static BufferedImage loadSprite(String file) {
        BufferedImage sprite = null;

        try {
            sprite = ImageIO.read(new File( file ));
        } catch (IOException e) {
            e.printStackTrace();
        }

        return sprite;
    }
    
	/**
	 * Reescala uma imagem com o AffineTransform pelas proporções horizontalRatio e verticalRatio
	 * @param source a imagem que será reescalada
	 * @param destination a imagem que servirá como recipiente da gerada (DICA: ESSA PORRA NÃO PODE SER IGUAL A source DE JEITO MANEIRA)
	 * @param horizontalRatio a proporção horizontal da escala
	 * @param verticalRatio a proporção vertical da escala
	 * @return source escalada conforme as ratios
	 */
	public BufferedImage rescale(BufferedImage source, BufferedImage destination, double horizontalRatio, double verticalRatio) {
		AffineTransform affine = new AffineTransform();
		affine.scale(horizontalRatio, verticalRatio);
		
		AffineTransformOp scale = new AffineTransformOp(affine, AffineTransformOp.TYPE_BILINEAR);
		return scale.filter(source, destination);
	}
	

	public void setFloor(BufferedImage floor) {
		this.floor = floor;
	}

	public void setAttack(BufferedImage attack) {
		this.attack = attack;
	}

	public void setMove(BufferedImage move) {
		this.move = move;
	}

	public void setRadius(BufferedImage radius) {
		this.radius = radius;
	}

	public void setHero(BufferedImage hero) {
		this.heroSprite = hero;
	}

	public void setEnemySprite(BufferedImage enemySprite) {
		this.enemySprite = enemySprite;
	}
}
