package modules.convert;

import com.one.Application;
import com.one.ColorQuantizer;
import com.one.ErrScreen;
import com.one.ImageProcessor;
import com.one.ModuleRegistry;
import com.one.PNGFile;
import com.one.PlayList;
import com.one.ProgressBar;
import com.one.file.Connector;
import com.one.file.FileConnection;
import com.vmx.Locale;
import com.vmx.ProgressCallback;
import filemanager.main;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.microedition.lcdui.Choice;
import javax.microedition.lcdui.ChoiceGroup;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Gauge;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.ImageItem;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemStateListener;

public class PNGConverter implements Application, CommandListener, ItemStateListener
{
	public static final String EXTENSION = ".png";
	public static final String NEW_SUFFIX = ".new";

	public static final int MAX_COLORS = 256;
	public static final int MIN_COLORS = 1;

	public static final int[] TYPES =
	{
		PNGFile.TRUECOLOR,
		PNGFile.GREYSCALE,
		PNGFile.INDEXED,
		PNGFile.TRUECOLOR_ALPHA,
		PNGFile.GREYSCALE_ALPHA,
		PNGFile.INDEXED_ALPHA
	};

	public static final String[] TYPE_NAMES =
	{
		"TrueColor",			// 0
		"Greyscale",			// 1
		"Indexed",				// 2
		"TrueColor + Alpha",	// 3
		"Greyscale + Alpha",	// 4
		"Indexed + Alpha"		// 5
	};

	public static final String[] FILTER_NAMES =
	{
		"Auto",			// 0
		"None",			// 1
		"Sub",			// 2
		"Up",			// 3
		"Average",		// 4
		"Paeth"			// 5
	};

	protected Object parent;
	protected String filename;

	protected Image source;

	protected ImageItem preview;
	protected Gauge gNumColors;
	protected ChoiceGroup cgPreprocess;
	protected ChoiceGroup cgType;
	protected ChoiceGroup cgFilter;

	protected Command cmdOK = new Command(Locale.getString(this, Locale.OK_CMD), Command.OK, 1);
	protected Command cmdUpdate = new Command(Locale.getString(this, Locale.UPDATE_CMD), Command.ITEM, 2);
	protected Command cmdCancel = new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.CANCEL, 3);

	public void openFile(String filename, PlayList filelist) throws IOException
	{
		this.filename = filename;

		InputStream is = Connector.openInputStream("file:///" + filename);
		source = Image.createImage(is);
		is.close();

		Form form = new Form(ModuleRegistry.getModuleName(getClass().getName()));

		preview = new ImageItem(null, source, ImageItem.LAYOUT_CENTER | ImageItem.LAYOUT_NEWLINE_AFTER, null);

		gNumColors = new Gauge(null, true, MAX_COLORS - MIN_COLORS, PNGOptions.numColors - MIN_COLORS);
		itemStateChanged(gNumColors);

		cgPreprocess = new ChoiceGroup(Locale.getString(this, Locale.PREPROCESS), Choice.MULTIPLE);

		cgPreprocess.append(Locale.getString(this, Locale.QUANTIZATION), null);
		cgPreprocess.setSelectedIndex(0, PNGOptions.quantize);

		cgPreprocess.append(Locale.getString(this, Locale.ERROR_DISTRIBUTION), null);
		cgPreprocess.setSelectedIndex(1, PNGOptions.dither);

		cgType = new ChoiceGroup(Locale.getString(this, Locale.FILE_TYPE), Choice.EXCLUSIVE, TYPE_NAMES, null);
		cgType.setSelectedIndex(PNGOptions.imageType, true);

		cgFilter = new ChoiceGroup(Locale.getString(this, Locale.FILTER_TYPE), Choice.EXCLUSIVE, FILTER_NAMES, null);
		cgFilter.setSelectedIndex(PNGOptions.filterType, true);

		form.append(preview);
		form.append(gNumColors);
		form.append(cgPreprocess);
		form.append(cgType);
		form.append(cgFilter);

		form.addCommand(cmdOK);
		form.addCommand(cmdUpdate);
		form.addCommand(cmdCancel);
		
		form.setCommandListener(this);
		form.setItemStateListener(this);

		parent = main.dsp.getCurrent();
		main.dsp.setCurrent(form);
	}

	public void commandAction(Command c, Displayable dp)
	{
		if(c == cmdUpdate)
		{
			if(cgPreprocess.isSelected(0))
			{
				final ProgressCallback callback = ProgressBar.getProgressCallback();
				callback.setProgress(0);
				callback.setMax(1);
				callback.setText(Locale.getString(this, Locale.WAIT_PLEASE));
				ProgressBar.show();

				Runnable runnable = new Runnable()
				{
					public void run()
					{
						ColorQuantizer quantizer = new ColorQuantizer(source, gNumColors.getValue() + MIN_COLORS, ColorQuantizer.MAX_NODES_ALPHA * 2, true, true, callback);
						preview.setImage(ImageProcessor.quantizeImage(source, quantizer, cgPreprocess.isSelected(1), callback));

						ProgressBar.hide();
					}
				};

				(new Thread(runnable)).start();
			}
			else
			{
				preview.setImage(source);
			}
		}
		else if(c == cmdOK)
		{
			PNGOptions.numColors = gNumColors.getValue() + MIN_COLORS;

			PNGOptions.quantize = cgPreprocess.isSelected(0);
			PNGOptions.dither = cgPreprocess.isSelected(1);
			
			PNGOptions.imageType = cgType.getSelectedIndex();
			PNGOptions.filterType = cgFilter.getSelectedIndex();

			final ProgressCallback callback = ProgressBar.getProgressCallback();
			callback.setProgress(0);
			callback.setMax(1);
			callback.setText(Locale.getString(this, Locale.WAIT_PLEASE));
			ProgressBar.show();

			Runnable runnable = new Runnable()
			{
				public void run()
				{
					try
					{
						String newname = filename.substring(0, filename.lastIndexOf('.'));

						if(filename.toLowerCase().endsWith(EXTENSION.toLowerCase()))
						{
							newname += NEW_SUFFIX;
						}

						FileConnection fc = (FileConnection)Connector.open("file:///" + newname + EXTENSION);

						if(fc.exists())
						{
							fc.truncate(0);
						}
						else
						{
							fc.create();
						}

						DataOutputStream dos = fc.openDataOutputStream();

						if(PNGOptions.quantize)
						{
							ColorQuantizer quantizer = new ColorQuantizer(source, PNGOptions.numColors, ColorQuantizer.MAX_NODES_ALPHA * 2, true, true, callback);
							source = ImageProcessor.quantizeImage(source, quantizer, PNGOptions.dither, callback);
						}

						PNGFile.writePNG(source, dos, TYPES[PNGOptions.imageType], PNGOptions.filterType - 1, callback);
						
						dos.close();
						fc.close();
					}
					catch(Throwable t)
					{
						ErrScreen.showErrMsg(ModuleRegistry.getErrCode(PNGConverter.class.getName()), t);
					}

					ProgressBar.hide();

					main.FileSelect.showWait(main.currentFile);
				}
			};

			(new Thread(runnable)).start();
		}
		else
		{
			main.FileSelect.showWait(main.currentFile);
		}
	}

	public void itemStateChanged(Item item)
	{
		if(item == gNumColors)
		{
			gNumColors.setLabel(Locale.getString(this, Locale.COLOR_COUNT, Integer.toString(gNumColors.getValue() + MIN_COLORS)));
		}
	}
}
