/*  This Java Application is used to convert an image file that Java can
    read (e.g. JPG or GIFF) into the CGMud source for a tile of the image.
    Normally, the images are expected to be 32 x 32 pixels, but it is also
    possible to grab a 32 x 32 region of a larger image. For example, the
    large oak tree in the standard scenario was a 64 x 64 GIF, so I
    turned it into four separate tiles. The general usage of this program
    is:

	java MkTile desc ...

    where each 'desc' is of the form:

	[bgfile[,bgcolour]:]name[+xOffset+yOffset[,name2]]

    In its simplest use:

	java MkTile blah.gif

    MkTile will produce file Blah.tile, which is the CGMud source to
    generate a tile from the 32 x 32 pixel image in blah.gif. If blah.gif
    is larger then 32 x 32, then the top-left chunk will be used.

    The "+xOffset+yOffset" addition to the file name specifies the offset
    in a larger image from which to grab the 32 x 32 chunk. You can also
    specify a second name "name2", which will be added to the end of the
    first part of the resulting file name. So, for the 64 x 64 oak tree
    image that I got from a friend, I can extract the four pieces as
    tiles using:

	java MkTile oak.gif+0+0,TL
	java MkTile oak.gif+0+32,BL
	java MkTile oak.gif+32+0,TR
	java MkTile oak.gif+32+32,BR

    which would create files "OakTL.tile", "OakBL.tile", "OakTR.tile"
    and "OakBR.tile".

    However, I want the oak tree to be displayed on top of the plain
    grass tile. So I want to combine some pixels from the grass tile with
    some pixels from one of the four oak tiles, to produce the final tile.
    By having the background of the oak.gif image be all one colour, I
    can get MkTile to do this, with the "bgfile" and "bgcolour" options.

	java MkTile grass.gif:oak.gif+0+0,TL

    would produce the top-left oak tree tile in which every initial black
    pixel has been replaced by the corresponding pixel from the grass.gif
    file. The background colour used for this can be changed to red,
    green or blue, by putting "red", "r", "green", "g", "blue" or "b"
    as the "bgcolour" value. So, since the actual oak-tree picture
    has red background (since black and green are used in the tree
    itself), I actually used:

	java MkTile grass.gif,red:oak.gif+0+0,TL
	java MkTile grass.gif,red:oak.gif+0+32,BL
	java MkTile grass.gif,red:oak.gif+32+0,TR
	java MkTile grass.gif,red:oak.gif+32+32,BR

    to produce the four oak-tree tile files that are part of the test
    tile world in the distributed sources.

    Note: don't blame my friend Don for this program - I did this one.
*/

import java.awt.Toolkit;
import java.awt.Frame;
import java.awt.MediaTracker;
import java.awt.Image;
import java.awt.Color;
import java.awt.image.PixelGrabber;
import java.awt.image.ColorModel;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;

public class MkTile {

    /* 6 * 7 * 6 = 252 <= 255 == 0xff */
    static final int R_SIZE = 6, G_SIZE = 7, B_SIZE = 6;

    static final int ROWS = 32, COLS = 32;

    static char[] Hex;

    static int mapColour(int rgb) {
	int r = (rgb >> 16) & 0xff;
	int g = (rgb >> 8) & 0xff;
	int b = rgb & 0xff;
	r = r * R_SIZE / 256;
	g = g * G_SIZE / 256;
	b = b * B_SIZE / 256;
	return (r * G_SIZE + g) * B_SIZE + b;
    }

    static boolean getImage(String name, int x, int y, int[] pixels) {
	Frame f = new Frame();
	MediaTracker mt = new MediaTracker(f);
	Image im = Toolkit.getDefaultToolkit().getImage(name);
	mt.addImage(im, 0);
	try {
	    mt.waitForAll();
	} catch (InterruptedException ex) {
	    System.out.println(name + " aborted");
	    return false;
	}
	if (mt.isErrorAny()) {
	    System.out.println(name + " failed");
	    return false;
	}
	PixelGrabber pg = new PixelGrabber(im, x, y, COLS, ROWS,
					   pixels, 0, COLS);
	try {
	    if (! pg.grabPixels()) {
		System.out.println(name + ": couldn't get pixels");
		return false;
	    }
	} catch (InterruptedException ex) {
	    System.out.println(name + ": pixel grab interrupted");
	    return false;
	}
	return true;
    }

    static void putValue(PrintWriter pw, int pos, int val) {
	char[] digit = {'0', '1', '2', '3', '4', '5', '6', '7',
			'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

	for (int i = 0; i < 8; i++) {
	    Hex[7 - i] = digit[val & 0xf];
	    val >>= 4;
	}
	pw.print("    tile[" + pos / 4 + "] := 0x");
	for (int i = 0; i < 8; i++) {
	    pw.print(Hex[i]);
	}
	pw.print(";");
	if (pos % 8 == 4) {
	    pw.println();
	}
    }

    static void generateTile(String name, String name2, int[] pixels) {
	int dotInd = name.indexOf('.');
	if (dotInd != -1) {
	    name = name.substring(0, dotInd);
	}
	name = name.substring(0, 1).toUpperCase() +
	    name.substring(1, name.length());
	if (name2 != null) {
	    name2 = name2.substring(0, 1).toUpperCase() +
		name2.substring(1, name2.length());
	    name = name + name2;
	}
	FileOutputStream fos;
	try {
	    fos = new FileOutputStream(name + ".tile");
	} catch (SecurityException ex) {
	    System.out.println(name + ".tile: security exception on creation");
	    return;
	} catch (FileNotFoundException ex) {
	    System.out.println(name + ".tile: directory not found");
	    return;
	} catch (IOException ex) {
	    System.out.println(name + ".tile: unknown I/O exception");
	    return;
	}
	PrintWriter pw = new PrintWriter(fos);
	pw.println("define t_tiles proc make" + name + "Tile()list int:");
	pw.println("    list int tile;");
	pw.println();
	pw.println("    tile := CreateIntArray(" + COLS * ROWS / 4 + ");");
	int pos = 0, val = 0;
	for (int i = 0; i < ROWS; i++) {
	    for (int j = 0; j < COLS; j++) {
		int index = mapColour(pixels[i * COLS + j]);
		val <<= 8;
		val |= index;
		pos++;
		if (pos % 4 == 0) {
		    putValue(pw, pos - 4, val);
		    val = 0;
		}
	    }
	}
	if (pos % 4 != 0) {
	    val <<= 8 * (4 - pos % 4);
	    putValue(pw, pos + 3, val);
	}
	if (pos % 8 != 0) {
	    pw.println();
	}
	pw.println("    tile");
	pw.println("corp;");
	pw.close();
    }

    static void convertImage(String name) {
	int bgColour = 0x000000;
	String bgString = null;
	String name2 = null;

	int colonPos = name.indexOf(':');
	if (colonPos != -1) {
	    bgString = name.substring(0, colonPos);
	    name = name.substring(colonPos + 1, name.length());
	    int commaPos = bgString.indexOf(',');
	    if (commaPos != -1) {
		String bgColStr =
		    bgString.substring(commaPos + 1, bgString.length());
		bgString = bgString.substring(0, commaPos);
		if (bgColStr.equals("r") || bgColStr.equals("red")) {
		    bgColour = 0xff0000;
		} else if (bgColStr.equals("g") || bgColStr.equals("green")) {
		    bgColour = 0x00ff00;
		} else if (bgColStr.equals("b") || bgColStr.equals("blue")) {
		    bgColour = 0x0000ff;
		} else {
		    System.out.println("Invalid background colour " +bgColStr);
		    return;
		}
	    }
	}

	int x = 0, y = 0;
	int plusPos = name.indexOf('+');
	if (plusPos != -1) {
	    String offsetStr = name.substring(plusPos + 1, name.length());
	    name = name.substring(0, plusPos);
	    int commaPos = offsetStr.indexOf(',');
	    if (commaPos != -1) {
		name2 = offsetStr.substring(commaPos + 1, offsetStr.length());
		offsetStr = offsetStr.substring(0, commaPos);
	    }
	    plusPos = offsetStr.indexOf('+');
	    if (plusPos == -1) {
		System.out.println("No second + in '" + offsetStr + "'");
		return;
	    }
	    String xStr = offsetStr.substring(0, plusPos);
	    String yStr = offsetStr.substring(plusPos + 1, offsetStr.length());
	    try {
		x = Integer.parseInt(xStr);
		y = Integer.parseInt(yStr);
	    } catch (NumberFormatException ex) {
		System.out.println("Invalid offsets '" + offsetStr + "'");
		return;
	    }
	}

	int[] mainPixels = new int[ROWS * COLS];
	if (! getImage(name, x, y, mainPixels)) {
	    return;
	}

	if (colonPos != -1) {
	    int[] bgPixels = new int[ROWS * COLS];
	    if (! getImage(bgString, 0, 0, bgPixels)) {
		return;
	    }
	    for (int i = 0; i != ROWS * COLS; i += 1) {
		if ((mainPixels[i] & 0x00ffffff) == bgColour) {
		    mainPixels[i] = bgPixels[i];
		}
	    }
	}

	generateTile(name, name2, mainPixels);
    }

    public static void main(String[] args) {
	Hex = new char[8];
	for (int i = 0; i != args.length; i++) {
	    convertImage(args[i]);
	}
	System.out.println("All done");
	System.exit(0);
    }
}
