import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

// Representation graphique d'un CircuitElement, herite de clip
public class GCircuitElement extends Clip {
	
	// Element represente
	CircuitElement ce;
	
	// Position du texte
	int x_str, y_str;
	
	// Police de caractere
	Font font, font_name;
	
	// Representation graphiques des pins
	ArrayList<GPin> gpins = new ArrayList<GPin>();
	
	// Constructeur
	public GCircuitElement(HWCanvas canvas, CircuitElement ce){
		super(canvas);
		
		this.ce = ce;
		n = ce.pin_in.size();
		n2 = ce.pin_out.size();
		this.ce.addCircuitElementListener(new CircuitElement.CircuitElementListener() {
			public void disposed(CircuitElement circuitElement) {
				Dispose(); // Lorsque le CircuitElement est detruit, on s'auto-detruit		
			}
		});
		
		// Largeur de base a 100px
		width = 100;
		
		// On initialise l'image
		initImg();
	}
	
	// Destructeur
	public void Dispose(){
		if(isDisposed) return;
		super.Dispose();
		gpins.clear();
		ce.Dispose();
		font = font_name = null;
	}
	
	int n = 0; // Nombre de pins d'entrees (nom de variable moyen...)
	int n2 = 0; // Nombre de pins de sorties
	
	// Initialisation de l'image de base, pour eviter de la redessiner a chaque fois (et elle sera utilisee dans la mini-map)
	public void initImg(){
		if(isDisposed) return;
		
		gpins.clear();
		
		height = Math.max(30 *(Math.max(n, n2)+1), 50);
		
		zone = new Rectangle(GPin.DEFAULT_PIN_SIZE, 0, width-GPin.DEFAULT_PIN_SIZE*2, height);
		
		font = new Font("ARIAL", Font.BOLD, 50);
		font_name = new Font("ARIAL", Font.PLAIN, 30);
		
		BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
		Graphics2D gg = (Graphics2D)img.getGraphics();
		gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		
		gg.setColor(new Color(75, 75, 75));
		gg.fillRoundRect(GPin.DEFAULT_PIN_SIZE, 0, width-GPin.DEFAULT_PIN_SIZE*2, height, 40, 40);
		gg.setColor(new Color(250, 250, 250));
		gg.setFont(font);
		
		FontMetrics fm   = gg.getFontMetrics(font);
		Rectangle2D rect = fm.getStringBounds(ce.getCharName(), gg);
		int textHeight = (int)(rect.getHeight()); 
		int textWidth  = (int)(rect.getWidth());
		int panelHeight= height;
		int panelWidth = width;

		x_str = (panelWidth  - textWidth)  / 2;
		y_str = (panelHeight - textHeight) / 2 + fm.getAscent();

		gg.drawString(ce.getCharName(), x_str, y_str);
		
		for(int i=1; i<=n; i++)
			gpins.add(new GPin(this, new Rectangle(0, (height/(n+1))*i -GPin.DEFAULT_PIN_SIZE/2, GPin.DEFAULT_PIN_SIZE, GPin.DEFAULT_PIN_SIZE), ce.pin_in.get(i-1)));
		for(int i=1; i<=n2; i++)
			gpins.add(new GPin(this, new Rectangle(width-GPin.DEFAULT_PIN_SIZE, (height/(n2+1))*i -GPin.DEFAULT_PIN_SIZE/2, GPin.DEFAULT_PIN_SIZE, GPin.DEFAULT_PIN_SIZE), ce.pin_out.get(i-1)));
		
		for(GPin gp : gpins)
			gg.drawImage(gp.getImage(), gp.x, gp.y, null);
		
		gg.dispose();
		
		i_base = img;
	}
	
	// Changement du nom
	boolean update_name = true;
	int name_x = 0, name_y = 0;
	public void setName(String name){
		if(isDisposed) return;
		if(!(ce.getName().equals(name))) ce.setName(name);
		update_name = true; // Il faut recalculer la hauteur/largeur
	}
	
	// Repaint de la representation graphique
	public void repaint(Graphics2D g) {
		if(isDisposed) return;
		try{
			g.drawImage(i_base, x, y, null);
			
			if(gpins != null)
				for(GPin gp : gpins)
					gp.repaint(g);
						
			if(isHover()){
				g.setColor(new Color(255, 255, 255, 75));
				g.fillRoundRect(x+GPin.DEFAULT_PIN_SIZE, y, width-GPin.DEFAULT_PIN_SIZE*2, height, 40, 40);
				g.setColor(Color.pink);
				g.setFont(font_name);
				if(update_name){
					update_name = false;
					FontMetrics fm   = g.getFontMetrics(font_name);
					Rectangle2D rect = fm.getStringBounds(ce.getName(), g);
					name_x = (width-(int)(rect.getWidth()))/2;
					name_y = height+(int)(rect.getHeight())-10;
				}
				g.drawString(ce.getName(), x+name_x, y+name_y);
			}
			
			if(isSelected()){
				g.setColor(new Color(255, 50, 50, 75));
				g.fillRoundRect(x+GPin.DEFAULT_PIN_SIZE, y, width-GPin.DEFAULT_PIN_SIZE*2, height, 40, 40);
			}
		}catch(Exception ex){}
	}
	
	public boolean isSelected(){ return ((CircuitCanvas) canvas).isSelected(this); }
	public void setSelected(boolean sel){
		if(isDisposed) return;
		if(((CircuitCanvas) canvas).selectClip(this, sel))
			Invalidate();
	}

	public boolean isHover(){
		if(isDisposed) return false;
		return (((CircuitCanvas) canvas).getHoverClip() == this);
	}

	// Recuperation de quel element se trouve sous la souris
	public Object getItem(MouseEvent me) {
		if(isDisposed) return null;
		if(gpins != null) // Verification si un des pins du composant est sous la souris
			for(GPin gp : gpins) if(gp.getItem(me)!=null) return gp;
		if(hitTest(me.getPoint().x - x, me.getPoint().y - y)) return this; // Verification si le composant est sous la souris
		return null;
	}

}
