import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;

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


public class GeneticImagePanel extends JPanel
{ //image_buf is an off screen buffer. All drawing is done to this buffer.
  //Then this entire buffer is painted at once on repaint();
  private BufferedImage image_buf;
  public Graphics2D graphics_buf;  //public so that other classes can write to the buffer.
  public Color background;
  private int imageWidth, imageHeight;
  private Insets inset;
    
  public GeneticImagePanel()
  { this.setBorder(ControlPanel.RAISEDBORDER);
    inset = ControlPanel.RAISEDBORDER.getBorderInsets(this);
    this.setSize(100, 100);
    this.setVisible(true);
  }
  
  public int getImageWidth() {return imageWidth;}
  public int getImageHeight() {return imageHeight;}
  
  public void setImageSize(int width, int height)
  { imageWidth = width;
    imageHeight = height;
    setBufferedImage
    ( new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB)
    );
  }
  
  public void setBufferedImage(BufferedImage image_buf)
  { this.image_buf = image_buf;   
    imageWidth = image_buf.getWidth();
    imageHeight = image_buf.getHeight();
    
    int panelWidth = image_buf.getWidth() + inset.left + inset.right;
    int panelHeight = image_buf.getHeight() + inset.top + inset.bottom;
    this.setSize(panelWidth, panelHeight);
    if (graphics_buf != null) graphics_buf.dispose();
    graphics_buf = image_buf.createGraphics();
  }
  
  public BufferedImage getBufferedImage() {return image_buf;}
  
  public void setBacground(Color background)
  { super.setBackground(background);
    this.background = background;
    clear();
  }
  
  
  public void clear()
  { graphics_buf.setColor(background);
    graphics_buf.fillRect(0,0,imageWidth,imageHeight);
  }
  
  public static BufferedImage loadImage(String filename, Component component)
  { MediaTracker tracker = new MediaTracker(component);
    BufferedImage loadedImage = null;
    
    String path = "Resources/" + filename;
  
    try
    { loadedImage = ImageIO.read(component.getClass().getResource(path)); 
      tracker.addImage(loadedImage, 0);
      
      tracker.waitForAll();
    } 
    catch (Exception ex) 
    { System.out.println("Error::loadImage() Cannot open " + path);
      ex.printStackTrace();
      return null;
    }
    
    System.out.println("Done loading image: "+ path);
    return loadedImage;
  }
  
  public static Color getModeColor(BufferedImage image)
  { int[] reds = new int[256];
    int[] greens = new int[256];
    int[] blues = new int[256];
    
    int width = image.getWidth();
    int height = image.getHeight();

    for (int i = 0; i < width; i++)
    { for (int j = 0; j < height; j++)
      {
        //This is slow - avoid new inside a large loops.
        Color c1 = new Color (image.getRGB(i,j));
      
        //rgb = original.getRGB(i, j);

        reds[c1.getRed()]++;
        greens[c1.getGreen()]++;
        blues[c1.getBlue()]++;
      }
    }
    int modeRed = 0, countRed = 0;
    int modeGreen = 0, countGreen = 0;
    int modeBlue = 0, countBlue = 0;
    
    for (int i = 0; i < 256; i++)
    { if (reds[i] > countRed) {countRed = reds[i]; modeRed = i;}
      if (greens[i] > countGreen) {countGreen = greens[i]; modeGreen = i;}
      if (blues[i] > countBlue) {countBlue = blues[i]; modeBlue = i;}
    }
    return new Color(modeRed, modeGreen, modeBlue);
  }
  
  
  
  
  public static double calculateFitness (BufferedImage original, BufferedImage created)
  {
    double fitness = 0.0;
    double pixelFitness = 0.0;
    
    int width = original.getWidth();
    int height = original.getHeight();

    for (int i = 0; i < width; i++)
    { for (int j = 0; j < height; j++)
      {
        //This is slow - avoid new inside a large loops.
        Color c1 = new Color (original.getRGB(i,j));
        Color c2 = new Color(created.getRGB(i,j));
      
        //rgb = original.getRGB(i, j);

        double deltaRed = c1.getRed() - c2.getRed();
        double deltaGreen = c1.getGreen() - c2.getGreen();
        double deltaBlue = c1.getBlue() - c2.getBlue();
        
        //System.out.println("["+deltaRed+", "+deltaGreen+", "+deltaBlue+"]");

        pixelFitness = deltaRed*deltaRed + deltaGreen*deltaGreen + deltaBlue*deltaBlue;
        fitness += pixelFitness;
      }
    }
   
    double pixelCount =  width * height;
    fitness = fitness/pixelCount;
    //System.out.println("fitness="+fitness);
    return fitness;
  }
  
    
  public void paintComponent (Graphics g) 
  { super.paintComponent(g);
    g.drawImage(image_buf,inset.left,inset.top,null);
  }
}
