/*
 * Copyright 2009-2010 Yuichiro Moriguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.morilib.nina.cmd;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

import net.morilib.nina.NinaCompoundException;
import net.morilib.nina.NinaException;
import net.morilib.nina.Quadro;
import net.morilib.nina.translate.NinaTranslator;

/**
 *
 *
 * @author MORIGUCHI, Yuichiro 2013/10/23
 */
public class Ninat {

	private static final Pattern POPT = Pattern.compile(
			"-P([^=]+)=(.*)");

	NinatOptions opts;

	int parseOptions(String[] args, Map<String, String> prms) {
		int k = 0, x;
		Matcher m;
		String s;

		for(; k < args.length; k++) {
			s = args[k];
			if(s.equals("-J")) {
				opts.jflag = true;
			} else if(s.startsWith("-L")) {
				opts.libs.add(s.substring(2));
			} else if(s.equals("-v")) {
				opts.console = opts;
			} else if((m = POPT.matcher(s)).matches()) {
				prms.put(m.group(1), m.group(2));
			} else if(!s.startsWith("--")) {
				return k;
			} else if(s.equals("--help")) {
				opts.usage();
				System.exit(2);
			} else if(s.equals("--lint")) {
				Quadro.errst = System.err;
			} else if(s.startsWith("--libpath=")) {
				opts.libs.add(s.substring(10));
			} else if(s.equals("--verbose")) {
				opts.console = opts;
			} else if((x = s.indexOf('=')) < 0) {
				opts.opts.put(s.substring(2), "");
			} else {
				opts.opts.put(s.substring(2, x), s.substring(x + 1));
			}
		}
		return k;
	}

	void process(String arg, Map<String, String> prms, boolean only) {
		InputStream ins = null;
		NinaTranslator tr;
		Reader rd = null;
		String s, t;
		int x;

		if(arg.endsWith("/")) {
			opts.perror("filenotfound", arg);
			return;
		} else if((x = arg.lastIndexOf('.')) < 0) {
			s = arg + ".nina";
			t = arg;
		} else {
			s = arg;
			t = arg.substring(0, x);
		}

		if((x = t.lastIndexOf('/')) < 0) {
			opts.filename = t;
		} else {
			opts.filename = t.substring(x + 1);
		}

		try {
			ins = new FileInputStream(s);
			rd  = new InputStreamReader(ins);
			tr  = opts.getTranslator();
			if(tr == null) {
				opts.perror("languagenotsupport");
				System.exit(2);
			}

			if(only) {
				tr.compile(s, rd, opts, prms);
			} else {
				tr.translate(s, rd, opts, prms);
			}

			if(!opts.getOption("statistics").equals("")) {
				tr.reportStatistics(System.out);
			}
		} catch(FileNotFoundException e) {
			opts.perror("filenotfound", s);
			System.exit(2);
		} catch(IOException e) {
			opts.perror("ioerror");
			if(!opts.getOption("exception").equals("")) {
				e.printStackTrace(System.err);
			}
			System.exit(2);
		} catch(NinaCompoundException e) {
			for(NinaException e1 : e.getExceptions()) {
				opts.pmessage(e1.getMessage());
			}

			try {
				if(!opts.getOption("exception").equals("")) {
					e.getCells().putBadfile(opts.filename + ".bad");
				} else if(!opts.getOption("trace").equals("")) {
					e.getCells().putBadfile(opts.filename + ".bad");
				}
			} catch(IOException e1) {
				opts.perror("ioerror");
			}
			System.exit(2);
		} catch(NinaException e) {
			opts.pmessage(e.getMessage());
			if(!opts.getOption("exception").equals("")) {
				e.printTrace(System.err);
				e.printStackTrace(System.err);
			} else if(!opts.getOption("trace").equals("")) {
				e.printTrace(System.err);
			}
			System.exit(2);
		} finally {
			if(ins != null) {
				try {
					ins.close();
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
		}
	}

	/**
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		Map<String, String> z;
		Ninat t = new Ninat();
		JavaCompiler cp;
		int k, x;

		z = new HashMap<String, String>();
		t.opts = new NinatOptions();
		if(args.length == 0) {
			t.opts.usage();
			System.exit(2);
		} else if((k = t.parseOptions(args, z)) == args.length) {
			t.opts.perror("nofiles");
			System.exit(2);
		} else if(t.opts.isOptionDefined("only")) {
			for(; k < args.length; k++) {
				t.process(args[k], z, true);
			}
			System.exit(Quadro.isWarning() ? 1 : 0);
		} else {
			for(; k < args.length; k++) {
				t.process(args[k], z, false);
			}

			if(t.opts.jflag) {
				try {
					cp = ToolProvider.getSystemJavaCompiler();
					x  = cp.run(null, null, null,
							t.opts.getJavaFile().toString());
					System.exit(x);
				} catch(Exception e) {
					t.opts.perror("javacompiler");
					System.exit(4);
				}
			} else {
				System.exit(0);
			}
		}
	}

}
