import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;

/**
 * 
 * PROPERTY OF AVECIRA SOLUTIONS - PROPERTY OF AVECIRA SOLUTIONS - PROPERTY OF AVECIRA SOLUTIONS - PROPERTY OF AVECIRA SOLUTIONS
 * 
 * Generates a picture of a face ingeniously using only 100 ellipses.
 * 
 * @author - Face modeling department, Group A
 *
 */

public class FaceModeling {
	
	private static final int ITERATION_COUNT = 50000;
	private static final int ELLIPSE_COUNT = 100;
	
	private Random r;
	private BufferedImage correctImg;
	private int imageW, imageH;
	private Ellipse[] ellipses;

	public FaceModeling(String input){
		createImage(input);
	}
		
	private void initEllipses(){
		ellipses = new Ellipse[ELLIPSE_COUNT];
		int maxW = imageW/5;
		int maxH = imageH/5;
		for (int i=0; i < ellipses.length; i++){
			int colorValue = r.nextInt(255);
			int alphaValue = r.nextInt(255);
			Color color = new Color(colorValue, colorValue, colorValue, alphaValue);
			ellipses[i] = new Ellipse(r.nextInt(imageW), r.nextInt(imageH), r.nextInt(maxW), r.nextInt(maxH), color);
		}
	}
	
	private void createImage(String input){
		r = new Random();
		correctImg = null;
		try {
			correctImg = ImageIO.read(new File(input));
		} catch (IOException e) {
			e.printStackTrace();
		}
		imageW = correctImg.getWidth();
		imageH = correctImg.getHeight();
		initEllipses();
		int count = 0;
		double bestDifference = Double.MAX_VALUE;
		
		while (count < ITERATION_COUNT){
			
			// Group B:
			// pick one ellipse randomly
			// modify it
			// create new image
			// check if the new image is better than the previous best one
			// if not, return to the previous stage
			
		}
		
		writeEllipsesToFile("ellipses.txt");
		BufferedImage bestImage = generateImageFromEllipses();
		writeImageToFile(bestImage, "final-image.png");
	}
	
	private void modifyEllipses(int ind){
		
		// Group B
		
	}
	
	private void writeEllipsesToFile(String filename){
		String result = "";
		for (int i=0; i < ellipses.length; i++){
			Ellipse s = ellipses[i];
			int x = s.getX();
			int y = s.getY();
			int w = s.getW();
			int h = s.getH();
			
			// to center
			x = x+(w/2);
			y = y+(h/2);
			
			int col = getBlackValue(s.getColor());
			int alpha = s.getColor().getAlpha();
			String row = x + ":" + y + ":" + w + ":" + h + ":" + col + ":" + alpha;
			result += row + "\n";
		}
		writeToFile(filename, result);
	}
	
	public static void writeToFile(String filename, String content){
	    try{
	        FileWriter fstream = new FileWriter(filename);
            BufferedWriter out = new BufferedWriter(fstream);
	        out.write(content);
	        out.close();
	    }catch (Exception e){
	        System.err.println("Error: " + e.getMessage());
	    }
	}
	
	private void writeImageToFile(BufferedImage bi, String filename){
		try {
		    File outputfile = new File(filename);
		    ImageIO.write(bi, "png", outputfile);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private BufferedImage generateImageFromEllipses(){
		BufferedImage img = new BufferedImage(imageW, imageH, BufferedImage.TYPE_INT_ARGB);
		Graphics g = img.getGraphics();
		g.setColor(Color.white);
		g.fillRect(0, 0, imageW, imageH);
		for (int i=0; i < ellipses.length; i++){
			Ellipse s = ellipses[i];
			g.setColor(s.getColor());
			g.fillOval(s.getX(), s.getY(), s.getW(), s.getH());
		}
		return img;
	}
	

	private double getDifference(BufferedImage img1, BufferedImage img2){
		double sum = 0;
		for (int i=0; i < imageH; i++){
			for (int j=0; j < imageW; j++){
				int rgb1 = img1.getRGB(j, i);
				int rgb2 = img2.getRGB(j, i);
				double diff = getBlackWhiteDifference(rgb1, rgb2);
				sum += diff;
			}
		}
		return sum;
	}
	
	private int getBlackWhiteDifference(int color1, int color2){
		int v1 = (color1 >> 16) & 0xFF;
		int v2 = (color2 >> 16) & 0xFF;
		
		int diff = Math.abs(v1-v2);
		return diff;
	}
	
	private int getBlackValue(Color c){
		return c.getRed();
	}
	
	public static void main(String[] args) {
		new FaceModeling("richard-model-face.png");
	}

}
