package de.saxms.test.getallsubclasses;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.imageio.ImageIO;

import org.apache.commons.lang3.time.StopWatch;

public class Test {

	private static Map<String, BufferedImage> databuffers = new HashMap<>();

	public static void main(String[] args) throws IOException {

		// test(0);

		List<String> originfiles = new ArrayList<>(listFilesUsingJavaIO("C:/Temp"));

		// removeWater(originfiles);

		// Set<String> donefiles = listFilesUsingJavaIO("C:/Temp/done");
		// int k = donefiles.size();

		doParallel(originfiles, 100, (ParallelFunction<List<String>, List<String>>) resources -> {
			Set<String> files = null;
			for (String originfile : resources) {

				try {

					if (!originfile.endsWith(".png")) {
						continue;
					}

					File original = new File(originfile);
					BufferedImage image = ImageIO.read(original);
					System.out.println("start testing: " + originfile);

					StopWatch sw = new StopWatch();
					sw.start();

					for (int i = 0; i <= 749; i += 15) {
						int startX = i;
						int endX = 14;

						for (int j = 0; j <= 749; j += 15) {

							int startY = j;
							int endY = 14;

							// System.out.println("sX:" + startX + " eX:" + endX + " sY:" + startY + " eY" +
							// endY);

							BufferedImage img = image.getSubimage(startX, startY, endX, endY); // fill in the corners of the desired crop location here
							BufferedImage copyOfImage = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
							Graphics g = copyOfImage.createGraphics();
							g.drawImage(img, 0, 0, null);

							File outputfileTmp = new File("C:/Temp/extrahiert/tmp/image_" + UUID.randomUUID() + "_" + i + "_" + j + ".png");
							ImageIO.write(copyOfImage, "png", outputfileTmp);

							if (files == null) {
								files = listFilesUsingJavaIO("C:/Temp/extrahiert");
							}

							boolean found = false;
							for (String string : files) {
								if (compareImage(outputfileTmp, new File(string))) {
									outputfileTmp.delete();
									found = true;
									break;
								}
							}
							if (found) {
								continue;
							}
							outputfileTmp.delete();
							File outputfile = new File("C:/Temp/extrahiert/image_" + UUID.randomUUID().toString() + "_" + i + "_" + j + ".png");
							ImageIO.write(copyOfImage, "png", outputfile);
							files = listFilesUsingJavaIO("C:/Temp/extrahiert");

						}
					}

					sw.stop();
					System.err.println(original.getName() + " took: " + sw.getTime() + " ms");

					original.renameTo(new File("C:/Temp/done/" + original.getName()));
				} catch (Exception e) {
					// TODO: handle exception
				}
			}

			return resources;
		});

		// for (String originfile : originfiles) {
		//
		// if(!originfile.endsWith(".png")) {
		// continue;
		// }
		//
		// File original = new File(originfile);
		// BufferedImage image = ImageIO.read(original);
		// System.out.println("start testing: " + originfile);
		//
		// StopWatch sw = new StopWatch();
		// sw.start();
		//
		// for (int i = 0; i <= 749; i += 15) {
		// int startX = i;
		// int endX = 14;
		//
		// for (int j = 0; j <= 749; j += 15) {
		//
		// int startY = j;
		// int endY = 14;
		//
		// // System.out.println("sX:" + startX + " eX:" + endX + " sY:" + startY + "
		// eY" +
		// // endY);
		//
		// BufferedImage img = image.getSubimage(startX, startY, endX, endY); // fill in
		// the corners of the desired crop location here
		// BufferedImage copyOfImage = new BufferedImage(img.getWidth(),
		// img.getHeight(), BufferedImage.TYPE_INT_RGB);
		// Graphics g = copyOfImage.createGraphics();
		// g.drawImage(img, 0, 0, null);
		//
		// File outputfileTmp = new File("C:/Temp/extrahiert/tmp/image_" + i + "_" + j +
		// ".png");
		// ImageIO.write(copyOfImage, "png", outputfileTmp);
		//
		// if (files == null) {
		// files = listFilesUsingJavaIO("C:/Temp/extrahiert");
		// }
		//
		// boolean found = false;
		// for (String string : files) {
		// if (compareImage(outputfileTmp, new File(string))) {
		// outputfileTmp.delete();
		// found = true;
		// break;
		// }
		// }
		// if (found) {
		// continue;
		// }
		// outputfileTmp.delete();
		// File outputfile = new File("C:/Temp/extrahiert/image_" + k + "_" + i + "_" +
		// j + ".png");
		// ImageIO.write(copyOfImage, "png", outputfile);
		// files = listFilesUsingJavaIO("C:/Temp/extrahiert");
		//
		// }
		// }
		//
		// sw.stop();
		// System.err.println(original.getName() + " took: " + sw.getTime() + " ms");
		//
		// k++;
		//
		// original.renameTo(new File("C:/Temp/done/" + original.getName()));
		// }

	}

	private static void removeWater(Set<String> originfiles) throws IOException {

		File original = new File("C:/Temp/done/detail_3000_-850.png");

		BufferedImage image = ImageIO.read(original);
		// TODO Auto-generated method stub
		for (String string : originfiles) {
			File img2 = new File(string);
			BufferedImage biB = ImageIO.read(img2);
			if (biB == null) {
				System.out.println("" + string);
				continue;
			}
			double difference = getSimularity(image, biB, 749, 749);
			if (difference <= 1) {
				System.out.println(difference + " image -> " + string);
				img2.renameTo(new File("C:/Temp/done/" + img2.getName()));
				System.out.println("");
			}
		}
	}

	private static void test(int i) throws IOException {
		Set<String> files = null;
		files = listFilesUsingJavaIO("C:/Temp/extrahiert");

		List<String> filesList = new ArrayList<>(files);
		filesList.sort(Comparator.naturalOrder());

		try {
			File original = new File(filesList.get(i));
			filesList.remove(i);
			BufferedImage image = ImageIO.read(original);

			for (String string : filesList) {
				File img2 = new File(string);
				BufferedImage biB = ImageIO.read(img2);
				double difference = getSimularity(image, biB, 14, 14);
				if (difference <= 5) {
					System.out.println(getSimularity(image, biB, 14, 14) + " image -> " + string);
					img2.delete();
				}
			}
			i = i + 1;
			test(i);
		} catch (Exception e) {
			System.out.println("end");
		}

	}

	private static Double getSimularity(BufferedImage imgA, BufferedImage imgB, int height1, int width1) {
		long difference = 0;

		// treating images likely 2D matrix

		// Outer loop for rows(height)
		for (int y = 0; y < height1; y++) {

			// Inner loop for columns(width)
			for (int x = 0; x < width1; x++) {

				int rgbA = imgA.getRGB(x, y);
				int rgbB = imgB.getRGB(x, y);
				int redA = (rgbA >> 16) & 0xff;
				int greenA = (rgbA >> 8) & 0xff;
				int blueA = (rgbA) & 0xff;
				int redB = (rgbB >> 16) & 0xff;
				int greenB = (rgbB >> 8) & 0xff;
				int blueB = (rgbB) & 0xff;

				difference += Math.abs(redA - redB);
				difference += Math.abs(greenA - greenB);
				difference += Math.abs(blueA - blueB);
			}
		}

		// Total number of red pixels = width * height
		// Total number of blue pixels = width * height
		// Total number of green pixels = width * height
		// So total number of pixels = width * height *
		// 3
		double total_pixels = width1 * height1 * 3;

		// Normalizing the value of different pixels
		// for accuracy

		// Note: Average pixels per color component
		double avg_different_pixels = difference / total_pixels;

		// There are 255 values of pixels in total
		double percentage = (avg_different_pixels / 255) * 100;

		return percentage;
	}

	public static <T extends String> List<T> doParallel(List<T> resources, int batchSize, ParallelFunction<List<T>, List<T>> function) {

		List<List<T>> parts = chopped(resources, batchSize);

		Map<String, List<T>> result = parts.parallelStream().collect(Collectors.toMap(k -> UUID.randomUUID().toString(), function::apply));

		return result.values().stream().flatMap(List::stream).collect(Collectors.toList());
	}

	public static <T> List<List<T>> chopped(List<T> list, final int L) {
		List<List<T>> parts = new ArrayList<List<T>>();
		final int N = list.size();
		for (int i = 0; i < N; i += L) {
			parts.add(new ArrayList<T>(list.subList(i, Math.min(N, i + L))));
		}
		return parts;
	}

	public static Set<String> listFilesUsingJavaIO(String dir) {
		return Stream.of(new File(dir).listFiles()).filter(file -> !file.isDirectory()).map(File::getAbsolutePath).collect(Collectors.toSet());
	}

	public static boolean compareImage(File fileA, File fileB) {
		try {
			// take buffer data from botm image files //
			BufferedImage biA = ImageIO.read(fileA);

			BufferedImage biB = null;
			if (databuffers.containsKey(fileB.getAbsolutePath())) {
				biB = databuffers.get(fileB.getAbsolutePath());
			} else {
				biB = ImageIO.read(fileB);

				databuffers.put(fileB.getAbsolutePath(), biB);
			}

			double difference = getSimularity(biA, biB, 14, 14);
			if (difference <= 5) {
				return true;
			} else {
				return false;
			}
		} catch (Exception e) {
			System.out.println("Failed to compare image files ...");
			return false;
		}
	}

	public interface ParallelFunction<T, R> {

		/**
		 * Applies this function to the given argument.
		 *
		 * @param t
		 *            the function argument
		 * @return the function result
		 */
		R apply(T t);
	}

}
