package client.util;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import common.log.Log;

public abstract class SkinConverter {
	private static BufferedImage convertSkin(BufferedImage image) {
		BufferedImage img = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
		Graphics graphics = img.getGraphics();
		graphics.drawImage(image, 0, 0, null);
		graphics.drawImage(img, 24, 48, 20, 52, 4, 16, 8, 20, null);
		graphics.drawImage(img, 28, 48, 24, 52, 8, 16, 12, 20, null);
		graphics.drawImage(img, 20, 52, 16, 64, 8, 20, 12, 32, null);
		graphics.drawImage(img, 24, 52, 20, 64, 4, 20, 8, 32, null);
		graphics.drawImage(img, 28, 52, 24, 64, 0, 20, 4, 32, null);
		graphics.drawImage(img, 32, 52, 28, 64, 12, 20, 16, 32, null);
		graphics.drawImage(img, 40, 48, 36, 52, 44, 16, 48, 20, null);
		graphics.drawImage(img, 44, 48, 40, 52, 48, 16, 52, 20, null);
		graphics.drawImage(img, 36, 52, 32, 64, 48, 20, 52, 32, null);
		graphics.drawImage(img, 40, 52, 36, 64, 44, 20, 48, 32, null);
		graphics.drawImage(img, 44, 52, 40, 64, 40, 20, 44, 32, null);
		graphics.drawImage(img, 48, 52, 44, 64, 52, 20, 56, 32, null);
		graphics.dispose();
		return img;
	}
	
	private static BufferedImage convertSlim(BufferedImage image) {
		BufferedImage img = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
		Graphics2D graphics = img.createGraphics();
		graphics.drawImage(image, 0, 0, null);
		graphics.setBackground(new Color(0xffffffff, true));
		graphics.clearRect(47, 16, 9, 16);
		graphics.clearRect(37, 48, 11, 16);
		graphics.setBackground(new Color(0x00000000, true));
		graphics.clearRect(47, 32, 9, 16);
		graphics.clearRect(53, 48, 11, 16);
		
		graphics.drawImage(image, 47, 16, 48, 20, 46, 16, 47, 20, null); //
		graphics.drawImage(image, 48, 16, 51, 20, 47, 16, 50, 20, null);
		graphics.drawImage(image, 51, 16, 52, 20, 49, 16, 50, 20, null); //
		graphics.drawImage(image, 47, 20, 48, 32, 46, 20, 47, 32, null); //
		graphics.drawImage(image, 48, 20, 52, 32, 47, 20, 51, 32, null);
		graphics.drawImage(image, 53, 20, 56, 32, 51, 20, 54, 32, null);
		graphics.drawImage(image, 52, 20, 53, 32, 51, 20, 52, 32, null); //
		
		graphics.drawImage(image, 47, 32, 48, 36, 46, 32, 47, 36, null); //
		graphics.drawImage(image, 48, 32, 51, 36, 47, 32, 50, 36, null);
		graphics.drawImage(image, 51, 32, 52, 36, 49, 32, 50, 36, null); //
		graphics.drawImage(image, 47, 36, 48, 48, 46, 36, 47, 48, null); //
		graphics.drawImage(image, 48, 36, 52, 48, 47, 36, 51, 48, null);
		graphics.drawImage(image, 53, 36, 56, 48, 51, 36, 54, 48, null);
		graphics.drawImage(image, 52, 36, 53, 48, 51, 36, 52, 48, null); //
		
		graphics.drawImage(image, 37, 48, 40, 52, 36, 48, 39, 52, null);
		graphics.drawImage(image, 41, 48, 44, 52, 39, 48, 42, 52, null);
		graphics.drawImage(image, 40, 48, 41, 52, 39, 48, 40, 52, null); //
		graphics.drawImage(image, 37, 52, 40, 64, 36, 52, 39, 64, null);
		graphics.drawImage(image, 40, 52, 44, 64, 39, 52, 43, 64, null);
		graphics.drawImage(image, 44, 52, 47, 64, 43, 52, 46, 64, null);
		graphics.drawImage(image, 47, 52, 48, 64, 45, 52, 46, 64, null); //
		
		graphics.drawImage(image, 53, 48, 56, 52, 52, 48, 55, 52, null);
		graphics.drawImage(image, 57, 48, 60, 52, 55, 48, 58, 52, null);
		graphics.drawImage(image, 56, 48, 57, 52, 55, 48, 56, 52, null); //
		graphics.drawImage(image, 53, 52, 56, 64, 52, 52, 55, 64, null);
		graphics.drawImage(image, 56, 52, 60, 64, 55, 52, 59, 64, null);
		graphics.drawImage(image, 60, 52, 63, 64, 59, 52, 62, 64, null);
		graphics.drawImage(image, 63, 52, 64, 64, 61, 52, 62, 64, null); //
		
		graphics.dispose();
		return img;
	}

	private static void copyData(int[] img1, int[] img2, int xo, int yo, int w, int h, boolean blank, boolean alpha) {
		for(int y = yo; y < h+yo; y++) {
			for(int x = xo; x < w+xo; x++) {
	    		img2[y*64+x] = blank ? 0x00000000 : (img1[y*64+x] | (alpha ? 0x00000000 : 0xff000000));
	    	}
		}
	}

	private static void copyData(int[] img1, int[] img2, int xo, int yo, int w, int h, int xd, int yd) {
		for(int y = 0; y < h; y++) {
			for(int x = 0; x < w; x++) {
	    		img2[(yd+y)*64+xd+x] = img1[(yo+y)*64+xo+x];
	    	}
		}
	}

	private static int[] filterImage(int[] img1, int[] img2) {
		copyData(img1, img2,  0,  0,  8,  8,  true, true);
		copyData(img1, img2,  8,  0, 16,  8, false, false);
		copyData(img1, img2, 24,  0,  8,  8,  true, true);
		copyData(img1, img2,  0,  8, 32,  8, false, false);
		copyData(img1, img2, 32,  0,  8,  8,  true, true);
		copyData(img1, img2, 40,  0, 16,  8, false, true);
		copyData(img1, img2, 56,  0,  8,  8,  true, true);
		copyData(img1, img2, 32,  8, 32,  8, false, true);

		copyData(img1, img2,  0, 16,  4,  4,  true, true);
		copyData(img1, img2,  4, 16,  8,  4, false, false);
		copyData(img1, img2, 12, 16,  8,  4,  true, true);
		copyData(img1, img2, 20, 16, 16,  4, false, false);
		copyData(img1, img2, 36, 16,  8,  4,  true, true);
		copyData(img1, img2, 44, 16,  8,  4, false, false);
		copyData(img1, img2, 52, 16,  4,  4,  true, true);
		copyData(img1, img2,  0, 20, 56, 12, false, false);
		copyData(img1, img2, 56, 16,  8, 32,  true, true);

		copyData(img1, img2,  0, 32,  4,  4,  true, true);
		copyData(img1, img2,  4, 32,  8,  4, false, true);
		copyData(img1, img2, 12, 32,  8,  4,  true, true);
		copyData(img1, img2, 20, 32, 16,  4, false, true);
		copyData(img1, img2, 36, 32,  8,  4,  true, true);
		copyData(img1, img2, 44, 32,  8,  4, false, true);
		copyData(img1, img2, 52, 32,  4,  4,  true, true);
		copyData(img1, img2,  0, 36, 56, 12, false, true);

		copyData(img1, img2,  0, 48,  4,  4,  true, true);
		copyData(img1, img2,  4, 48,  8,  4, false, true);
		copyData(img1, img2, 12, 48,  4,  4,  true, true);
		copyData(img1, img2,  0, 52, 16, 12, false, true);
		copyData(img1, img2, 16, 48,  4,  4,  true, true);
		copyData(img1, img2, 20, 48,  8,  4, false, false);
		copyData(img1, img2, 28, 48,  8,  4,  true, true);
		copyData(img1, img2, 36, 48,  8,  4, false, false);
		copyData(img1, img2, 44, 48,  4,  4,  true, true);
		copyData(img1, img2, 16, 52, 32, 12, false, false);
		copyData(img1, img2, 48, 48,  4,  4,  true, true);
		copyData(img1, img2, 52, 48,  8,  4, false, true);
		copyData(img1, img2, 60, 48,  4,  4,  true, true);
		copyData(img1, img2, 48, 52, 16, 12, false, true);
		
		return img2;
	}

	private static void relocateIntermediary(int[] img1, int[] img2) {
		copyData(img1, img2,  0,  0, 64, 64,  0,  0);
		
		copyData(img1, img2,  4, 16,  8,  4, 20, 48);
		copyData(img1, img2, 44, 16,  8,  4,  4, 16);
		copyData(img1, img2,  0, 20, 16, 12, 16, 52);
		copyData(img1, img2, 40, 20, 16, 12,  0, 20);
		
		copyData(img1, img2,  4, 32,  8,  4,  4, 48);
		copyData(img1, img2, 44, 32,  8,  4,  4, 32);
		copyData(img1, img2,  0, 36, 16, 12,  0, 52);
		copyData(img1, img2, 40, 36, 16, 12,  0, 36);

		copyData(img1, img2,  4, 48,  8,  4, 52, 48);
		copyData(img1, img2, 20, 48,  8,  4, 36, 48);
		copyData(img1, img2, 36, 48,  8,  4, 44, 16);
		copyData(img1, img2, 52, 48,  8,  4, 44, 32);
		copyData(img1, img2,  0, 52, 16, 12, 48, 52);
		copyData(img1, img2, 16, 52, 16, 12, 32, 52);
		copyData(img1, img2, 32, 52, 16, 12, 40, 20);
		copyData(img1, img2, 48, 52, 16, 12, 40, 36);
	}

	public static boolean convertSkin(File source, File dir, boolean slim) {
		BufferedImage img;
		try {
			img = ImageIO.read(source);
		}
		catch(IOException e) {
			Log.IO.error(e, "Konnte kein Bild von " + source + " laden");
			return false;
		}
		if(img == null) {
			Log.IO.warn("Konnte kein Bild von " + source + " laden");
			return false;
		}
		Log.IO.info("Bild von " + source + " geladen");
		if(img.getWidth() == 64 && img.getHeight() == 32) {
			img = convertSkin(img);
			Log.IO.info("Skin " + source + " konvertiert");
		}
		else if(img.getWidth() != 64 || img.getHeight() != 64) {
			Log.IO.warn("Falsche Bildgröße von " + source + ": " + img.getWidth() + "x" + img.getHeight());
			return false;
		}
		String name = source.getName();
		int ext = name.lastIndexOf('.');
		if(ext >= 0)
			name = name.substring(0, ext);
		if(name.isEmpty())
			name = "skin";
		if(slim) {
			img = convertSlim(img);
			Log.IO.info("Skin " + source + " von 'Slim' konvertiert");
			if(!name.startsWith("slim_"))
				name = "slim_" + name;
		}
		File file = new File(dir, name + ".png");
		int z = 1;
		while(file.exists()) {
			file = new File(dir, name + "_" + (++z) + ".png");
		}
//		Graphics2D g = img.createGraphics();
//		g.setBackground(new Color(0x7fff00ff, true));
//		g.clearRect(0, 0, 64, 64);
		int[] data = img.getRGB(0, 0, 64, 64, new int[64*64], 0, 64);
		int[] data2 = new int[data.length];
		relocateIntermediary(data, data2);
		data = data2;
		filterImage(data, data);
		img.setRGB(0, 0, 64, 64, data, 0, 64);
		try {
			ImageIO.write(img, "png", file);
		}
		catch(Exception e) {
			Log.IO.error(e, "Konnte Bild nicht speichern");
			return false;
		}
		Log.IO.info("Skin " + source + " gespeichert als " + file.getName());
		return true;
	}
	
//	public static void main(String[] args) {
//		if(args.length < 1) {
//			System.err.println("Verwendung: SkinConverter [-s | -n | -i] <Skin-Datei | Ordner ...>");
//			System.exit(1);
//		}
//		int n = 0;
//		boolean slim = false;
////		boolean intermediary = false;
//		for(String file : args) {
//			if(file.equals("-s")) {
//				slim = true;
//				continue;
//			}
////			else if(file.equals("-i")) {
////				intermediary = true;
////				continue;
////			}
//			else if(file.equals("-n")) {
//				slim = false;
////				intermediary = false;
//				continue;
//			}
//			else if(new File(file).isDirectory()) {
//				String[] files = new File(file).list();
//				if(files != null && files.length > 0) {
//					for(int z = 0; z < files.length; z++) {
//						files[z] = file + File.separator + files[z];
//					}
//					if(slim) { // || intermediary) {
//						String[] files2 = new String[files.length + /* (slim && intermediary ? 2 : */ 1]; // )];
//						int pos = 0;
//						if(slim)
//							files2[pos++] = "-s";
////						if(intermediary)
////							files2[pos++] = "-i";
//						System.arraycopy(files, 0, files2, pos, files.length);
//						files = files2;
//					}
//					main(files);
//				}
//				continue;
//			}
//			else if(file.endsWith("-converted.png"))
//				continue;
//			String out = (file.endsWith(".png") ? file.substring(0, file.length() - 4) : file) + "-converted.png";
//			BufferedImage img;
//			try {
//				img = ImageIO.read(new File(file));
//			}
//			catch(Exception e) {
//				System.err.println("Konnte Bild '" + file + "' nicht laden");
//				e.printStackTrace();
//				continue;
//			}
//			if(img == null) {
//				System.err.println("Konnte Bild '" + file + "' nicht öffnen");
//				continue;
//			}
//			if(img.getWidth() == 64 && img.getHeight() == 32) {
//				img = convertSkin(img);
//				System.out.println("Skin '" + file + "' von 64x32 nach 64x64 konvertiert");
//			}
//			else if(img.getWidth() != 64 || img.getHeight() != 64) {
//				System.err.println("Falsche Bildgröße für '" + file + "': " + img.getWidth() + "x" + img.getHeight());
//				continue;
//			}
//			if(slim) {
//				img = convertSlim(img);
//				System.out.println("Skin '" + file + "' von 'Slim' nach 64x64/'Schlank' konvertiert");
//			}
//			int[] data = img.getRGB(0, 0, 64, 64, new int[64*64], 0, 64);
////			if(intermediary) {
//			int[] data2 = new int[data.length];
//			relocateIntermediary(data, data2);
//			data = data2;
////			}
////			else {
//			filterImage(data, data);
////			}
//			img.setRGB(0, 0, 64, 64, data, 0, 64);
//			try {
//				ImageIO.write(img, "png", new File(out));
//			}
//			catch(Exception e) {
//				System.err.println("Konnte Bild '" + out + "' nicht speichern");
//				e.printStackTrace();
//				continue;
//			}
//			System.out.println("Skin von '" + file + "' nach '" + out + "' konvertiert");
//			n++;
//		}
//		if(n > 0)
//			System.out.println(n + " Skins wurden konvertiert");
//	}
}
