/*
 * Copyright (c) 2014 Villu Ruusmann
 *
 * This file is part of JPMML-Converter
 *
 * JPMML-Converter is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JPMML-Converter is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with JPMML-Converter.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.jpmml.converter;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.transform.stream.StreamResult;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.ParameterException;
import com.google.protobuf.CodedInputStream;
import org.dmg.pmml.PMML;
import org.jpmml.model.JAXBUtil;
import rexp.Rexp;

public class Main {

	@Parameter (
		names = "--pb-input",
		description = "ProtoBuf input file",
		required = true
	)
	private File input = null;

	@Parameter (
		names = "--pmml-output",
		description = "PMML output file",
		required = true
	)
	private File output = null;


	static
	public void main(String... args) throws Exception {
		Main main = new Main();

		JCommander commander = new JCommander(main);
		commander.setProgramName(Main.class.getName());

		try {
			commander.parse(args);
		} catch(ParameterException pe){
			commander.usage();

			System.exit(-1);
		}

		main.run();
	}

	public void run() throws Exception {
		Rexp.REXP rexp;

		InputStream is = new FileInputStream(this.input);

		try {
			logger.log(Level.INFO, "Parsing ProtoBuf..");

			CodedInputStream cis = CodedInputStream.newInstance(is);
			cis.setSizeLimit(Integer.MAX_VALUE);

			long start = System.currentTimeMillis();
			rexp = Rexp.REXP.parseFrom(cis);
			long end = System.currentTimeMillis();

			logger.log(Level.INFO, "Parsed ProtoBuf in " + (end - start) + " ms.");
		} catch(Exception e){
			logger.log(Level.SEVERE, "Failed to parse ProtoBuf", e);

			throw e;
		} finally {
			is.close();
		}

		ConverterFactory converterFactory = ConverterFactory.getInstance();

		Converter converter = converterFactory.getConverter(rexp);

		PMML pmml;

		try {
			logger.log(Level.INFO, "Converting model..");

			long start = System.currentTimeMillis();
			pmml = converter.convert(rexp);
			long end = System.currentTimeMillis();

			logger.log(Level.INFO, "Converted model in " + (end - start) + " ms.");
		} catch(Exception e){
			logger.log(Level.SEVERE, "Failed to convert model", e);

			throw e;
		}

		OutputStream os = new FileOutputStream(this.output);

		try {
			logger.log(Level.INFO, "Marshalling PMML..");

			long start = System.currentTimeMillis();
			JAXBUtil.marshalPMML(pmml, new StreamResult(os));
			long end = System.currentTimeMillis();

			logger.log(Level.INFO, "Marshalled PMML in " + (end - start) + " ms.");
		} catch(Exception e){
			logger.log(Level.SEVERE, "Failed to marshal PMML", e);

			throw e;
		} finally {
			os.close();
		}
	}

	public File getInput(){
		return this.input;
	}

	public void setInput(File input){

		if(input == null){
			throw new NullPointerException();
		}

		this.input = input;
	}

	public File getOutput(){
		return this.output;
	}

	public void setOutput(File output){

		if(output == null){
			throw new NullPointerException();
		}

		this.output = output;
	}

	private static final Logger logger = Logger.getLogger(Main.class.getName());
}
@@ -1573,16 +1573,122 @@
  null;%0A%0A
+%09@Parameter (%0A%09%09names = %22--converter%22,%0A%09%09description = %22Converter class%22%0A%09)%0A%09private String name = null;%0A%0A
 %0A%09static
@@ -2598,16 +2598,174 @@
 );%0A%09%09%7D%0A%0A
+%09%09Converter converter;%0A%0A%09%09if(this.name != null)%7B%0A%09%09%09Class%3C?%3E clazz = Class.forName(this.name);%0A%0A%09%09%09converter = (Converter)clazz.newInstance();%0A%09%09%7D else%0A%0A%09%09%7B%0A%09
 %09%09Conver
@@ -2825,34 +2825,25 @@
 tance();%0A%0A%09%09
-Converter 
+%09
 converter = 
@@ -2878,16 +2878,20 @@
 r(rexp);
+%0A%09%09%7D
 %0A%0A%09%09PMML
@@ -4072,16 +4072,135 @@
 ut;%0A%09%7D%0A%0A
+%09public String getConverter()%7B%0A%09%09return this.name;%0A%09%7D%0A%0A%09public void setConverter(String name)%7B%0A%09%09this.name = name;%0A%09%7D%0A%0A
 %09private

Support for user-defined Converter classes