package Division.gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.text.DecimalFormat;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import java.io.File;

import javax.swing.*;
import javax.imageio.ImageIO;

import Division.Claimer;

public class GeneralDivisionDisplayPanel extends JPanel{
	private BufferedImage buffer;
    private ReentrantLock lock;
	/**
	 * 
	 */
	private static final long serialVersionUID = 6360193806497881884L;

	/** the total vessel height of each player */
	private static final int TOTAL_VESSEL_HEIGHT = 250;
	
	/** the width of each vessel */
	private static final int VESSEL_WIDTH = 120;
	
	/** the horizontal space between each vesel */
	private static final int HORIZONTAL_VESSEL_PADDING = 50;
	
	/** the internal padding in the paintable area */
	private static final int INTERNAL_PADDING = 10;
	
	private List<Claimer> claimers;
	
	public GeneralDivisionDisplayPanel(List<Claimer> claimers){
		this.claimers = claimers;
        lock=new ReentrantLock();
		setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder()));
        addMouseListener(new Mouse(this));
	}
	
	@Override
	public Dimension getPreferredSize(){
		return new Dimension((VESSEL_WIDTH + HORIZONTAL_VESSEL_PADDING) * claimers.size(), TOTAL_VESSEL_HEIGHT + INTERNAL_PADDING + 105);
	}
	
	@Override
	public void paintComponent(Graphics g){
        if (lock.isLocked())return;
        lock.lock();
        try{
            // clear the whole area

            if (buffer==null||buffer.getWidth()!=getWidth()||buffer.getHeight()!=getHeight())buffer=new BufferedImage(getWidth(),getHeight(),BufferedImage.TYPE_INT_RGB);
            Graphics g2=buffer.getGraphics();
            super.paintComponent(g2);
            double scale = claimers.get(claimers.size() - 1).getClaimed() / TOTAL_VESSEL_HEIGHT;

            // the relative vessel height for this player
            int vesselHeight = 0;

            // how much the vessel is filled
            int filled = 0;

            for(int i = 0; i < claimers.size(); i++){
                vesselHeight = (int)(claimers.get(i).getClaimed() / scale);
                filled = (int)(claimers.get(i).getReceived() / scale);

                paintVessel(g2, INTERNAL_PADDING + VESSEL_WIDTH*i + HORIZONTAL_VESSEL_PADDING * i, INTERNAL_PADDING, vesselHeight, filled);
                paintPlayerInfo(g2, i, INTERNAL_PADDING + VESSEL_WIDTH * i + HORIZONTAL_VESSEL_PADDING * i, INTERNAL_PADDING + TOTAL_VESSEL_HEIGHT + 20);
            }
            g.drawImage(buffer,0,0,null);
        }
        catch(Exception e){}
        lock.unlock();
	}
	
	/**
	 * Paint the vessels for this player
	 * @param g the graphics to paint on
	 * @param x the x insets
	 * @param y the y insets
	 * @param vesselHeight the height of one half of the vessels
	 * @param filled size in pixels to fill in the vessel
	 */
	private void paintVessel(Graphics g, int x, int y, int vesselHeight, int filled){
        g.setColor(Color.BLACK);
		g.drawRect(x, y + (TOTAL_VESSEL_HEIGHT - vesselHeight), VESSEL_WIDTH, vesselHeight);
		
		// fill the vessels
		g.setColor(new Color(0, 191, 255));
		
		g.fillRect(x + 1, y + (TOTAL_VESSEL_HEIGHT - filled) + 1, VESSEL_WIDTH - 1, filled - 1);
		
		// reset the color to black
		g.setColor(Color.BLACK);
	}
	
	/**
	 * Paint the player information (the claimed and the got)
	 * @param g the graphics to paint on
	 * @param playerId the id of the player
	 * @param x the x insets
	 * @param y the y insets
	 */
	private void paintPlayerInfo(Graphics g, int playerId, int x, int y){
		DecimalFormat df = new DecimalFormat("#.###");
		g.drawString("Player " + playerId + ":", x , y);
		g.drawString("Claimed: " + df.format(claimers.get(playerId).getClaimed()), x, y + 14);
		g.drawString("Received: " + df.format(claimers.get(playerId).getReceived()), x, y + 28);
		g.drawString("Received in %: " + df.format((claimers.get(playerId).getReceived() / claimers.get(playerId).getClaimed()) * 100), x, y + 42);
		g.drawString("Loss: " + df.format(claimers.get(playerId).getClaimed() - claimers.get(playerId).getReceived()), x, y + 56);
		g.drawString("Loss in %: " + df.format(((claimers.get(playerId).getClaimed() - claimers.get(playerId).getReceived()) / claimers.get(playerId).getClaimed()) * 100), x, y + 70);
	}

    class Mouse implements MouseListener {
        private JComponent frame;
        Mouse(JComponent frame) {
            this.frame = frame;
        }
        public void mouseClicked(MouseEvent e) {
            if (e.getButton()==MouseEvent.BUTTON3){
                lock.lock();
                try{
                    final JFileChooser fc = new JFileChooser();
                    fc.setName("Save Graph");
                    int retVal = fc.showSaveDialog(frame);
                    if (retVal==JFileChooser.APPROVE_OPTION){
                        File f=fc.getSelectedFile();
                        if (f.exists()){
                            retVal=JOptionPane.showConfirmDialog(frame,"Overwrite "+f.getName()+"?");
                            if (retVal!=JOptionPane.OK_OPTION)return;
                        }
                        int i=f.getName().lastIndexOf('.');
                        if (i>0){
                            String format=f.getName().substring(i+1);
                            ImageIO.write(buffer,format,f);
                        }
                        else{
                            ImageIO.write(buffer,"bmp",f);
                        }
                    }
                }
                catch(Exception ex){
                    JOptionPane.showMessageDialog(frame,"Could not save Image.");
                }
                lock.unlock();
                repaint();
            }
        }
        public void mousePressed(MouseEvent e){}
        public void mouseReleased(MouseEvent e){}
        public void mouseEntered(MouseEvent e){}
        public void mouseExited(MouseEvent e){}
    }
	
}
