package creation;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import java.util.UUID;

import javax.imageio.ImageIO;

public class Creator {
	public static void main(String[] args) {
		Random r = new Random(1);

		String basedir = "outputdir/data";
		String[] names = NameCreator.generateNames(r);

		try {
			FileOutputStream collectionOutput = new FileOutputStream(basedir + "/collection.json");
			PrintWriter collectionWriter = new PrintWriter(collectionOutput);
			collectionWriter.write("{\n  \"textures\": [\n    ");
			boolean first = true;
			int i=1;
			for (String name : names) {
				if (first) {
					first = false;
				} else {
					collectionWriter.write(",\n    ");
				}
				System.out.println("Creating " + name + " (texture " + i + " of " + names.length + ")");
				storeImage(name, basedir, r, collectionWriter);
				i++;
			}
			collectionWriter.write("\n  ]\n}\n");
			collectionWriter.close();
			collectionOutput.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static boolean randBool(Random r, double probability) {
		return r.nextDouble() < probability;
	}

	private static void storeImage(String name, String outputdir, Random r, PrintWriter collectionWriter)
			throws IOException {
		int size = 256 * (1 << r.nextInt(6));
		NamedColor[] shuffling = Dictionary.colors.clone();
		NamedColor[] mycolors = new NamedColor[3];
		for (int i = 0; i < 3; i++) {
			int otherPos = r.nextInt(7 - i) + i;
			mycolors[i] = shuffling[otherPos];
			shuffling[otherPos] = shuffling[i];
		}
		MyDate date = randomDate(r);

		boolean grey = randBool(r, 0.01);
		boolean border = randBool(r, 0.1);
		boolean bold = randBool(r, 0.03);
		boolean italic = randBool(r, 0.07);
		BufferedImage img = createImage(size, name, mycolors, date, grey, border, bold, italic);

		File tmpLocation = new File(outputdir + "/tempimage");
		ImageIO.write(img, name.substring(name.length() - 3), tmpLocation);
		String hash = hashFile(tmpLocation);
		String ending = name.substring(name.length() - 3);
		if (ending.equals("jpg")) {
			ending = "jpeg";
		}
		tmpLocation.renameTo(new File(outputdir + "/textures/" + hash));
		String tags = mycolors[0].name + "\", \"" + mycolors[1].name + "\", \"" + mycolors[2].name;
		if (grey) {
			tags += "\", \"grey";
		}
		if (border) {
			tags += "\", \"border";
		}
		if (bold) {
			tags += "\", \"bold";
		}
		if (italic) {
			tags += "\", \"italic";
		}
		collectionWriter.write("{\n");
		collectionWriter.write("      \"id\": \"" + UUID.randomUUID() + "\",\n");
		collectionWriter.write("      \"name\": \"" + name + "\",\n");
		collectionWriter.write("      \"tags\": [\"" + tags + "\"],\n");
		collectionWriter.write("      \"format\": \"" + ending + "\",\n");
		collectionWriter.write("      \"resolution\": [" + size + ", " + size + "],\n");
		collectionWriter.write("      \"added_on\": " + date.asJsonArray() + ",\n");
		collectionWriter.write("      \"texture_hash\": \"" + hash + "\"\n");
		collectionWriter.write("    }");
	}

	private static MyDate randomDate(Random r) {
		int back = (int) (-300 * Math.log(r.nextDouble()));
		return new MyDate(3, 6, 2019).ago(back);
	}

	private final static char[] hexArray = "0123456789ABCDEF".toCharArray();

	public static String bytesToHex(byte[] bytes) {
		char[] hexChars = new char[bytes.length * 2];
		for (int j = 0; j < bytes.length; j++) {
			int v = bytes[j] & 0xFF;
			hexChars[j * 2] = hexArray[v >>> 4];
			hexChars[j * 2 + 1] = hexArray[v & 0x0F];
		}
		return new String(hexChars);
	}

	private static String hashFile(File f) throws IOException {
		byte[] data = Files.readAllBytes(f.toPath());
		try {
			MessageDigest hash = MessageDigest.getInstance("SHA-256");
			byte[] hashval = hash.digest(data);
			return bytesToHex(hashval);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			return null;
		}
	}

	private static BufferedImage createImage(int size, String name, NamedColor[] colors, MyDate date, boolean grey,
			boolean border, boolean bold, boolean italic) {
		BufferedImage img = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
		Graphics g = img.getGraphics();

		// background
		if (grey) {
			g.setColor(Color.LIGHT_GRAY);
		} else {
			g.setColor(Color.WHITE);
		}
		g.fillRect(0, 0, size, size);

		// border
		if (border) {
			int w = size / 40;
			int l = size - 2*w;
			g.setColor(Color.BLACK);
			g.fillRect(w, w, l, w);
			g.fillRect(w, w, w, l);
			g.fillRect(w, l, l, w);
			g.fillRect(l, w, w, l);
		}

		// text
		int fontstyle = Font.PLAIN;
		if (bold) {
			fontstyle |= Font.BOLD;
		}
		if (italic) {
			fontstyle |= Font.ITALIC;
		}
		Font f = new Font("Arial", fontstyle, size / 10);
		g.setFont(f);
		g.setColor(Color.BLACK);
		int width = g.getFontMetrics().stringWidth(name);
		int basey = size / 2 + g.getFontMetrics().getAscent();
		int textheight = g.getFontMetrics().getHeight();
		g.drawString(name, (size - width) / 2, basey);
		g.drawString(size + " x " + size, (size - width) / 2, basey + textheight);
		g.drawString(date.asReadableString(), (size - width) / 2, basey + 2 * textheight);

		// color dots
		for (int i = 0; i < 3; i++) {
			NamedColor current = colors[i];
			g.setColor(current.color);
			g.fillOval((1 + 3 * i) * size / 10, size * 3 / 10, size / 5, size / 5);
		}

		return img;
	}
}
