package pikelake;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Rectangle2D;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

import fr.cemagref.observation.gui.Configurable;
import fr.cemagref.observation.gui.Drawable;
import fr.cemagref.observation.kernel.ObservablesHandler;
import fr.cemagref.observation.kernel.ObserverListener;
import fr.cemagref.ohoui.annotations.Description;
import fr.cemagref.ohoui.annotations.NoRecursive;
import fr.cemagref.ohoui.filters.NoTransientField;
import fr.cemagref.ohoui.swing.OhOUI;
import fr.cemagref.ohoui.swing.OhOUIDialog;
import fr.cemagref.simaqualife.kernel.util.TransientParameters;
import fr.cemagref.simaqualife.pilot.Pilot;

@SuppressWarnings("serial")
@NoRecursive
public class GridObserver extends ObserverListener implements Configurable, Drawable, MouseMotionListener {

    private transient JComponent display;
    private transient JLabel label;
    private transient Grid grid;
    
    private String title;
    
    private Color envColor = Color.GREEN;
    private Color preyColor = Color.BLUE;
    private Color pikeColor = Color.RED;
    @Description (name="Background color",tooltip="Background color")
    private Color bgColor = Color.WHITE;
    
    private transient int displayWidthBak,displayHeightBak;
    private transient double cellSizeX, cellSizeY;
    private transient int[] cellsAlpha;
    
    public String getTitle() {
        return title;
    }

    public JComponent getDisplay() {
        return display;
    }
    
    public void valueChanged(ObservablesHandler clObservable, Object instance, long t) {
        display.repaint();
    }
    
    @TransientParameters.InitTransientParameters
    public void init(Pilot pilot) {
    	// init display component
        display = new JPanel(new BorderLayout());
        DisplayComponent displayComponent = new DisplayComponent();
        displayComponent.addMouseMotionListener(this);
        displayComponent.setVisible(true);
        displayComponent.setDoubleBuffered(true);
        label = new JLabel("");
        display.add(displayComponent,BorderLayout.CENTER);
        display.add(label,BorderLayout.PAGE_START);
        grid = (Grid)pilot.getAquaticWorld().getEnvironment();

        // init display variables
        displayWidthBak = 0;
        displayHeightBak = 0;
        // compute HabitatQuality colors
    	double cellsHabitatQualityMin = 0;
        double cellsHabitatQualityMax = 0;
    	cellsAlpha = new int[grid.getCells().length];
    	if (grid.getCells().length > 0) {
	    	cellsHabitatQualityMin = grid.getCells()[0].getHabitatQuality();
	    	cellsHabitatQualityMax = grid.getCells()[0].getHabitatQuality();
	    	for (int i = 1; i < grid.getCells().length; i++) {
	    		if (grid.getCells()[i].getHabitatQuality() < cellsHabitatQualityMin)
	    			cellsHabitatQualityMin = grid.getCells()[i].getHabitatQuality();
	    		else if (grid.getCells()[i].getHabitatQuality() > cellsHabitatQualityMax)
	    			cellsHabitatQualityMax = grid.getCells()[i].getHabitatQuality();
	    	}
    	}
    	if (Double.compare(cellsHabitatQualityMax,cellsHabitatQualityMin) == 0) {
    		for (int i = 0; i < grid.getCells().length; i++) {
	    		cellsAlpha[i] = 255;
	    	}
    	} else {
	    	for (int i = 0; i < grid.getCells().length; i++) {
	    		cellsAlpha[i] = (int)(155 + 100*(grid.getCells()[i].getHabitatQuality() - cellsHabitatQualityMin)/(cellsHabitatQualityMax - cellsHabitatQualityMin));
	    	}
    	}
    	// show the result
        display.repaint();
    }
    
    public void disable() {
        display.setVisible(false);
    }
    
    public static interface AsShapeConvertible {
        public Shape getShape();
    }

    public void configure() {
        OhOUIDialog dialog = OhOUI.getDialog(null,this,new NoTransientField());
        dialog.setSize(new Dimension(500, 600));
        dialog.setVisible(true);
        display.repaint();
    }

    @Override
    public void addObservable(ObservablesHandler classObservable) {
    	// nothing to do
    }

    @Override
    public void init() {
        // nothing to do
    }

    @Override
    public void close() {
        // nothing to do
    }
    
    private class DisplayComponent extends JComponent {
        
        @Override
        protected synchronized void paintComponent(Graphics g) {
            super.paintComponents(g);
            Graphics2D g2d = (Graphics2D)g;
            // determine if generalPath must be rescaled
            if ( (this.getWidth() != displayWidthBak) || (this.getHeight() != displayHeightBak) ) {
                // backup for comparaison in the next loop
                displayWidthBak = this.getWidth();
                displayHeightBak = this.getHeight();
                cellSizeX = displayWidthBak/grid.getGridWidth();
                cellSizeY = displayHeightBak/grid.getGridHeight();
            }
            // Draw Background
            g.setColor(bgColor);
            g2d.setStroke(new BasicStroke(3));
            g.fillRect(0, 0, getWidth(), getHeight());
            Rectangle2D.Double cellRect = null;
            Rectangle2D.Double pikeRect = null;
            double preyDiameterX, preyDiameterY, pikeWidth, pikeHeight;
            // draw each cell
            for (int i = 0; i < grid.getCells().length; i++) {
            	// the bounds of a cell
            	cellRect = new Rectangle2D.Double((int)cellSizeX*(i%grid.getGridWidth()), (int)cellSizeY*(i/grid.getGridHeight()), (int)cellSizeX, (int)cellSizeY);
            	// filling the cell with a color corresponding to the habitat level
            	g.setColor(new Color(envColor.getRed(),envColor.getGreen(),envColor.getBlue(),cellsAlpha[i]));
            	g2d.fill(cellRect);
            	// drawing preys
            	if (grid.getCells()[i].getPreys().size() > 0) {
            	    g.setColor(preyColor);
            	    preyDiameterX = cellRect.width*(double)grid.getCells()[i].getPreys().size()/grid.getCells()[i].getPreyCarryingCapacity();
            	    preyDiameterY = cellRect.height*(double)grid.getCells()[i].getPreys().size()/grid.getCells()[i].getPreyCarryingCapacity();
            	    g.fillOval((int)(cellRect.x + (cellRect.width - preyDiameterX)/2), (int)(cellRect.y + (cellRect.height - preyDiameterY)/2), (int)preyDiameterX, (int)preyDiameterY);
            	    // represention as pie ... not very pretty
            	    /*g2d.fill(new Arc2D.Double(cellRect,90,-360*((double)grid.getCells()[i].getPreys().size()/grid.getCells()[i].getPreyCarryingCapacity()),Arc2D.PIE));
                    g2d.draw(new Arc2D.Double(cellRect,90,360,Arc2D.OPEN));*/
                }
            	// drawing pikes presence
                if (grid.getCells()[i].getPikes().size() > 0) {
                    g.setColor(pikeColor);
                    pikeWidth = cellRect.width / 3;
                    pikeHeight = cellRect.height / 3;
                	pikeRect = new Rectangle2D.Double(cellRect.x + (cellRect.width - pikeWidth)/2, cellRect.y + (cellRect.height - pikeHeight)/2, pikeWidth, pikeHeight);
                	g2d.draw(pikeRect);
                	g2d.drawString(""+grid.getCells()[i].getPikes().size(), (float)(cellRect.x + cellRect.width/2 - 5), (float)pikeRect.y+(float)pikeRect.height-1);
                }
            }
        }
    }
    
    public void mouseDragged(MouseEvent e) {}

    public void mouseMoved(MouseEvent e) {
        int y = (int)(e.getY()/cellSizeY);
        int x = (int)(e.getX()/cellSizeX);
        Cell cell = grid.getCells()[grid.getGridWidth()*Math.min(y,grid.getGridHeight()-1) + Math.min(x,grid.getGridWidth()-1)];
        label.setText("( "+x+" , "+y+" ) : habitat value = "+cell.getHabitatQuality()+" / "+cell.getPreys().size() + " preys ( max = "+cell.getPreyCarryingCapacity()+") and " + cell.getPikes().size()+ " pikes.");
    }

    public static void main (String [] args){
    	System.out.println((new XStream(new DomDriver())).toXML(new GridObserver()));
    }



}