
import java.awt.Color;
import java.util.Properties;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.NoSuchElementException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.File;


import dirk_krause.jtools.LogContentsForCommand;
import dirk_krause.jtools.StatusChanger;
import dirk_krause.jtools.PropertyTool;
import dirk_krause.jtools.StringTool;
import dirk_krause.jtools.StatusChanger;

public class Png2PdfController
{
	/**
	 * The application name (Png2PdfGUI), as found in the
	 * constructor.
	 */
	protected String appName = null;
	
	/**
	 * PDF format version to produce.
	 */
	protected int pdfVersion = PDF_VERSION_14;
	
	/**
	 * Run in make mode
	 */
	protected boolean makeMode = true;
	
	/**
	 * Either set interpolation bit or not
	 */
	protected boolean interpolate = true;
	
	/**
	 * Alpha channel by default expresses opacity.
	 * This flag can be used to change this to transparency.
	 */
	protected boolean alphaTrans = false;
	
	/**
	 * Mix alpha channel against a background color.
	 */
	protected boolean mix = false;
	
	/**
	 * The color to mix against.
	 */
	protected Color mixColor = null;
	
	/**
	 * Prefer specified color over background chunk contents.
	 */
	protected boolean preferMyColor = true;
	
	/**
	 * Create image mask or not.
	 */
	protected boolean mask = false;
	
	/**
	 * Use inverted mask levels or normal levels.
	 */
	protected boolean maskInverted = false;
	
	/**
	 * Write alpha channel to output.
	 */
	protected boolean alpha = true;
	
	/**
	 * Show file names while processing.
	 */
	protected boolean showFilenames = false;
	
	/**
	 * Status changer to show file names
	 */
	protected StatusChanger sc = null;
	
	protected synchronized void internalSetPdfVersion(int i) { pdfVersion = i; }
	
	public void setPdfVersion(int i)
	{
		int v = i;
		if(v < PDF_VERSION_12) v = PDF_VERSION_12;
		if(v > PDF_VERSION_14) v = PDF_VERSION_14;
		internalSetPdfVersion(v);
	}
	
	public synchronized int getPdfVersion() { return pdfVersion; }
	
	public synchronized boolean getMakeMode() { return makeMode; }
	
	public synchronized void setMakeMode(boolean b) { makeMode = b; }
	
	public synchronized boolean getInterpolate() { return interpolate; }
	
	public synchronized void setInterpolate(boolean b) { interpolate = b; }
	
	public synchronized boolean getAlphaTrans() { return alphaTrans; }
	
	public synchronized void setAlphaTrans(boolean b) { alphaTrans = b; }
	
	public synchronized boolean getMix() { return mix; }
	
	public synchronized void setMix(boolean b) { mix = b; }
	
	public synchronized Color internalGetMixColor() { return mixColor; }
	
	public Color getMixColor()
	{
		Color back = mixColor;
		if(back == null) {
			back = new Color(255,255,255);
		} else {
			back = new Color(back.getRed(), back.getGreen(), back.getBlue());
		}
		return back;
	}
	
	public void internalSetMixColor(Color c) { mixColor = c; }
	
	public synchronized void setMixColor(Color c)
	{
		Color x;
		if(c != null) {
			x = new Color(c.getRed(), c.getGreen(), c.getBlue());
		} else {
			x = new Color(255,255,255);
		}
		internalSetMixColor(x);
	}
	
	public synchronized boolean getPreferMyColor() { return preferMyColor; }
	
	public synchronized void setPreferMyColor(boolean b) { preferMyColor = b; }
	
	public synchronized boolean getMask() { return mask; }
	
	public synchronized void setMask(boolean b) { mask = b; }
	
	public synchronized boolean getMaskInverted() { return maskInverted; }
	
	public synchronized void setMaskInverted(boolean b) { maskInverted = b; }
	
	public synchronized boolean getAlpha() { return alpha; }
	
	public synchronized void setAlpha(boolean b) { alpha = b; }
	
	public synchronized boolean getShowFilenames() { return showFilenames; }
	
	public synchronized void setShowFilenames(boolean b) { showFilenames = b; }
	
	public synchronized StatusChanger getStatusChanger() { return sc; }
	
	public synchronized void setStatusChanger(StatusChanger s) { sc = s; }
	
	public static final String[] pk = {
		"directory",
		".",
		"png2pdf GUI settings",
		"show-filenames",
	};
	
	public static final int PDF_VERSION_12 = 0;
	public static final int PDF_VERSION_13 = 1;
	public static final int PDF_VERSION_14 = 2;
	
	public static final String[] allArgs = {
		/*  0 */	"png2pdf",
		/*  1 */	"--/ui/lang=en",
		/*  2 */	"--/ui/lang/env=no",
		/*  3 */	"--/log/stdout/level=warning",
		/*  4 */	"--/log/stderr/level=none",
		/*  5 */	"--/log/file/level=none",
		/*  6 */	"--/log/file/name=png2pdf-gui.log",
		/*  7 */	"-C",
		/*  8 */	"-r",
		/*  9 */	"-c",
		/* 10 */	"-p",
		/* 11 */	"1.2",
		/* 12 */	"1.3",
		/* 13 */	"1.4",
		/* 14 */	"-m",
		/* 15 */	"-m-",
		/* 16 */	"-s",
		/* 17 */	"-s-",
		/* 18 */	"-i",
		/* 19 */	"-i-",
		/* 20 */	"-a",
		/* 21 */	"-a-",
		/* 22 */	"-l",
		/* 23 */	"-l-",
		/* 24 */	"-t",
		/* 25 */	"-t-",
		/* 26 */	"-b",
		/* 27 */	"-b-",
		/* 28 */	"-n",
		/* 29 */	"-n-",
		/* 30 */	"-f",
		/* 31 */	"-f-",
		/* 32 */	",",
		/* 33 */	".",
		/* 34 */	".pdf",
		/* 35 */	"Processing file: ",
	};
	
	public static final String[] options = {
		"-p",	//  0
		"-m",	//  1
		"-s",	//  2
		"-i",	//  3
		"-a",	//  4
		"-l",	//  5
		"-t",	//  6
		"-b",	//  7
		"-n",	//  8
		"-f",	//  9
	};
	
	public static final String[] versions = {
		"1.2", "1.3", "1.4"
	};
	
	protected String workingDirectory = "." ;
	
	protected synchronized void internalSetCwd(String s) { workingDirectory = s; }
	protected synchronized String internalGetCwd() { return workingDirectory; }
	public void setCwd(String newcwd)
	{
		internalSetCwd(new String(newcwd));
	}
	public String getCwd()
	{
		String back = new String(internalGetCwd());
		return back;
	}
	
	public Png2PdfController(String an)
	{
		appName = an;
		initialize();
	}
	
	public Png2PdfController()
	{
		this(Png2PdfGUI.appName);
	}
	
	protected void addProgramOptions(LogContentsForCommand l)
	{
		int pv = getPdfVersion();
		boolean al = getAlpha();
		boolean ma = getMask();
		boolean mi = getMaskInverted();
		boolean mx = getMix();
		Color   co = getMixColor();
		boolean pc = getPreferMyColor();
		boolean in = getInterpolate();
		boolean mm = getMakeMode();
		boolean tr = getAlphaTrans();
		if(pv < PDF_VERSION_12) pv = PDF_VERSION_12;
		if(pv > PDF_VERSION_14) pv = PDF_VERSION_14;
		if(pv < PDF_VERSION_14) {
			al = false;
		}
		if(al) {
			mx = false;
			ma = false;
		}
		if(pv < PDF_VERSION_13) {
			ma = false;
		}
		l.addArgv(allArgs[10]);
		l.addArgv(allArgs[11+pv]);
		if(al) {
			l.addArgv(allArgs[20]);
		} else {
			l.addArgv(allArgs[21]);
			if(mx) {
				l.addArgv(allArgs[14]);
				StringBuilder sb = new StringBuilder();
				sb.append(Integer.toString(co.getRed()));
				sb.append(allArgs[32]);
				sb.append(Integer.toString(co.getGreen()));
				sb.append(allArgs[32]);
				sb.append(Integer.toString(co.getBlue()));
				l.addArgv(new String(sb));
				if(pc) {
					l.addArgv(allArgs[16]);
				} else {
					l.addArgv(allArgs[17]);
				}
			} else {
				l.addArgv(allArgs[15]);
			}
			if(ma) {
				l.addArgv(allArgs[18]);
				if(mi) {
					l.addArgv(allArgs[22]);
				} else {
					l.addArgv(allArgs[23]);
				}
			} else {
				l.addArgv(allArgs[19]);
			}
		}
		if(al || mx || ma) {
			if(tr) {
				l.addArgv(allArgs[24]);
			} else {
				l.addArgv(allArgs[25]);
			}
		}
		if(pv >= PDF_VERSION_13) {
			if(in) {
				l.addArgv(allArgs[28]);
			} else {
				l.addArgv(allArgs[29]);
			}
		}
	}
	
	public LogContentsForCommand restoreOptions()
	{
		int i;
		int pv = PDF_VERSION_14;
		boolean al = true;
		boolean ma = false;
		boolean mi = false;
		boolean mx = false;
		Color   co = null;
		boolean pc = false;
		boolean in = true;
		boolean mm = true;
		boolean tr = true;
		LogContentsForCommand back = new LogContentsForCommand();
		for(i = 0; i <= 7; i++) {
			back.addArgv(allArgs[i]);
		}
		back.run();
		if(back.getSuccess()) {
			Iterator<String> it = back.getIterator();
			int state = 0;
			while(it.hasNext()) {
				String s = it.next();
				String t = s.trim();
				switch(state) {
				case 0: {
					if(t.startsWith(LogContentsForCommand.msgTexts[1])) {
						state = 1;
					}
				} break;
				case 1: {
					if(t.startsWith(LogContentsForCommand.msgTexts[2])) {
						state = 2;
					} else {	// process line
						StringTokenizer st = new StringTokenizer(t);
						if(st.hasMoreTokens()) {
							try {
								String k = st.nextToken();
								if(st.hasMoreTokens()) {
									String v = st.nextToken();
									boolean b = StringTool.getBoolean(v, false);
									switch(StringTool.getArrayIndex(options, k)) {
									case 0: {	// -p
										pv = StringTool.getArrayIndex(versions, v);
									} break;
									case 1: {	// -m
										StringTokenizer st2 = new StringTokenizer(v, " \t,");
										try {
											if(st2.hasMoreTokens()) {
												String sr = st2.nextToken();
												if(st2.hasMoreTokens()) {
													String sg = st2.nextToken();
													if(st2.hasMoreTokens()) {
														String sb = st2.nextToken();
														try {
															int r = Integer.parseInt(sr);
															int g = Integer.parseInt(sg);
															int blue = Integer.parseInt(sb);
															co = new Color(r,g,blue);
														}
														catch(NumberFormatException e) {}
													}
												}
											}
										}
										catch(NoSuchElementException e) {}
									} break;
									case 2: {	// -s
										pc = b;
									} break;
									case 3: {	// -i
										ma = b;
									} break;
									case 4: {	// -a
										al = b;
									} break;
									case 5: {	// -l
										mi = b;
									} break;
									case 6: {	// -t
										tr = b;
									} break;
									case 7: {	// -b
										// nichts tun, ignorieren
									} break;
									case 8: {	// -n
										in = b;
									} break;
									case 9: {	// -f
										mm = b;
									} break;
									}
								}
							}
							catch(NoSuchElementException e) {}
						}
					}
				} break;
				}
			}
		}
		if(pv < PDF_VERSION_12) pv = PDF_VERSION_12;
		if(pv > PDF_VERSION_14) pv = PDF_VERSION_14;
		if(pv < PDF_VERSION_14) {
			al = false;
		}
		if(pv < PDF_VERSION_13) {
			in = false;
		}
		if(al) {
			mx = false; ma = false;
		}
		if(!ma) {
			mi = false;
		}
		if(!mx) {
			pc = false;
		}
		setPdfVersion(pv);
		setAlpha(al);
		setAlphaTrans(tr);
		setInterpolate(in);
		setMakeMode(mm);
		setMask(ma);
		setMaskInverted(mi);
		setMix(mx);
		setPreferMyColor(pc);
		setMixColor(co);
		return back;
	}
	
	public LogContentsForCommand saveOptions()
	{
		LogContentsForCommand back = new LogContentsForCommand();
		int i = 0;
		back.addArgv(allArgs[0]);
		for(i = 3; i <= 6 ; i++) {
			back.addArgv(allArgs[i]);
		}
		for(i = 8; i <= 9; i++) {
			back.addArgv(allArgs[i]);
		}
		addProgramOptions(back);
		if(getMakeMode()) {
			back.addArgv(allArgs[30]);
		} else {
			back.addArgv(allArgs[31]);
		}
		back.run();
		
		return back;
	}
	
	protected boolean mustConvert(String sname, String dname)
	{
		boolean back = true;
		File sfile = new File(sname);
		File dfile = new File(dname);
		if(dfile.exists()) {
			if(dfile.isFile()) {
				if(dfile.lastModified() > sfile.lastModified()) {
					back = false;
				}
			}
		}
		return back;
	}
	
	protected String changeSuffix(String fn)
	{
		String back = fn;
		StringBuilder sb;
		int ind = fn.lastIndexOf(allArgs[33]);
		if(ind > -1) {
			sb = new StringBuilder(fn.substring(0, ind));
		} else {
			sb = new StringBuilder(fn);
		}
		sb.append(allArgs[34]);
		back = new String(sb);
		return back;
	}
	
	protected void runShowingFilenames(LogContentsForCommand l)
	{
		boolean mm = getMakeMode();
		Png2PdfFileFilter ff = new Png2PdfFileFilter();
		File d = new File(getCwd());
		StatusChanger s = getStatusChanger();
		if(d.isDirectory()) {
			File[] inputNames = d.listFiles(ff);
			for(int k = 0; k < inputNames.length; k++) {
				String sname = inputNames[k].getAbsolutePath();
				String dname = changeSuffix(sname);
				boolean mustRun = true;
				if(mm) {
					mustRun = this.mustConvert(sname, dname);
				}
				if(mustRun) {
					if(s != null) {
						StringBuilder sb = new StringBuilder();
						sb.append(allArgs[35]);
						sb.append(inputNames[k].getName());
						s.setStatus(new String(sb));
					}
					l.newCommand();
					l.addArgv(allArgs[0]);
					for(int i = 3; i <= 6 ; i++) {
						l.addArgv(allArgs[i]);
					}
					addProgramOptions(l);
					if(getMakeMode()) {
						l.addArgv(allArgs[30]);
					} else {
						l.addArgv(allArgs[31]);
					}
					l.addArgv(sname);
					l.addArgv(dname);
					l.run();
				}
			}
		} else {
			// ERROR No directory
		}
		ff = null;
	}
	
	public LogContentsForCommand runTheProgram()
	{
		int i;
		LogContentsForCommand back = new LogContentsForCommand();
		if(getShowFilenames()) {
			runShowingFilenames(back);
		} else {
			back.addArgv(allArgs[0]);
			for(i = 3; i <= 6 ; i++) {
				back.addArgv(allArgs[i]);
			}
			addProgramOptions(back);
			if(getMakeMode()) {
				back.addArgv(allArgs[30]);
			} else {
				back.addArgv(allArgs[31]);
			}
			back.addArgv(this.getCwd());
			back.run();
		}
		return back;
	}
	
	/**
	 * Write current working directory to preferences
	 * after the directory was changed.
	 *
	 */
	public void writeCwd()
	{
		try {
			Properties p = new Properties();
			p.setProperty(pk[0], getCwd());
			p.setProperty(
					pk[3],
					((showFilenames)
					? (StringTool.theBooleanStrings[3])
					: (StringTool.theBooleanStrings[8]))
			);
			PropertyTool.writePropertiesForApp(Png2PdfGUI.appName, p, pk[2]);
		}
		catch(FileNotFoundException e) {
		}
		catch(IOException e) {
		}
		catch(SecurityException e) {
		}
	}
	
	/**
	 * Initialize object, read working directory from
	 * preferences.
	 *
	 */
	public void initialize()
	{
		try {
			Properties p = PropertyTool.readPropertiesForApp(Png2PdfGUI.appName);
			String newcwd = p.getProperty(pk[0], pk[1]);
			setCwd(newcwd);
			String s = p.getProperty(pk[3], StringTool.theBooleanStrings[8]);
			showFilenames = StringTool.getBoolean(s, false);
		}
		catch(FileNotFoundException e) {}
		catch(IOException e) {}
		catch(SecurityException e) {}
	}
	
	
}
