/*
 * Copyright (C) 2005, 2006 Mikhail A. Kryshen
 *
 * $Id: Tema.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $
 */

package kryshen.tema;

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

import java.util.Map;
import java.util.HashMap;
import java.util.Properties;
import java.util.List;
import java.util.Collections;

import java.io.*;

/**
 * Tema main class.
 *
 * @author Mikhail A. Kryshen
 */
public class Tema {
    private static final String CONFIG_FILE = "tema.properties";
    private static final String ENV_PREFIX = "kryshen.tema.";

    private static Properties config = new Properties();
    static Connection connection = null;

    private static String inputEncoding;
    private static String outputEncoding;

    static Map<File, String> fileCache = null;

    public static void main(String[] args) 
	throws IOException, TemplateException, SQLException,
	       ClassNotFoundException, InstantiationException, 
	       IllegalAccessException {
	
        InputStream configIn = new FileInputStream(CONFIG_FILE);
        config.load(configIn);
        configIn.close();

        String logFile = getProperty("log");
        if (logFile != null && logFile.length() > 0)
            System.setErr(new PrintStream(new FileOutputStream(logFile)));

	if (Boolean.parseBoolean(getProperty("cache_read")) == true)
	    fileCache = new HashMap<File, String>();

	inputEncoding = getProperty("input_encoding", "iso-8859-1");
	outputEncoding = getProperty("output_encoding", "iso-8859-1");

	String resourceProperty = getProperty("resource");

	if (resourceProperty != null) {
	    String driverProperty = getProperty("driver");
	    if (driverProperty != null) {
		// Register driver.  
		Driver d = (Driver)Class.forName(driverProperty).newInstance();
	    }
	
	    // Open connection.
	    connection = DriverManager.getConnection(resourceProperty);
	}
	
// 	String maxFilesString = getProperty("max_output_files");
// 	int maxFiles = -1;
// 	if (maxFilesString != null)
// 	    maxFiles = Integer.parseInt(maxFilesString);

	String main = getProperty("main_template");
	String output = getProperty("output");
	
	Writer out;

	if ("stderr".equals(output))
	    out = new OutputStreamWriter(System.err);
	else
	    out = new OutputStreamWriter(System.out);

	InputStream is = new FileInputStream(main);
        Reader in = new BufferedReader(new InputStreamReader(is, inputEncoding));

        TemplateParser p = new TemplateParser();
	try {
	    p.parse(in, out);
	} finally {
	    in.close();
	    out.flush();
	}  

	System.err.println("Done");
    }

//     private static void readEscapes() {
// 	for (int i = 1;; i++) {
// 	    String pattern = getProperty("escape_char_" + i);

// 	    if (pattern == null) break;

// 	    escapes.put(pattern.charAt(0),
// 			getProperty("escape_string_" + i));
// 	}
//     }

    /**
     * Get configuration property.
     */
    static String getProperty(String name) {
        String value = System.getProperty(ENV_PREFIX + name);
        if (value != null) return value;
        return config.getProperty(name);
    }

    /**
     * Get configuration property.
     */
    static String getProperty(String name, String fallback) {
	String value = getProperty(name);
	if (value != null) return value;
	return fallback;
    }

    /**
     * Process subquery and template.
     *
     * @param template template to fill with data.
     * @param ps query statement to execute.
     * @param args list of query parameters.
     * @param superParser invoking object.
     * @param out Writer to output processed data.
     *
     * @return number of processed rows in query result.
     */
    static int query(String template, PreparedStatement ps,
		     List<String> args,
		     TemplateParser superParser, 
                     Writer out)
	throws IOException, SQLException, TemplateException {

	StringReader templateReader = new StringReader(template);

	int i = 1;

	for (String arg : args) {
	    ps.setString(i++, arg);
	}
	
	ResultSet r = ps.executeQuery();
	ResultSetMetaData rm = r.getMetaData();
	int columnCount = rm.getColumnCount();

	String[] names = new String[columnCount];
	
	for (int j = 0; j < columnCount; j++) {
	    names[j] = rm.getColumnName(j + 1);
	}

	TemplateParser p = new TemplateParser(superParser);
	
	for (i = 1; r.next(); i++) {
	    p.clearValues();

	    for (int j = 0; j < columnCount; j++) {
		Object value = r.getObject(j + 1);
		if (r.wasNull()) value = null;

		p.setValue(names[j], value);
	    }

	    p.setValue("NUMBER", i);
            p.parse(templateReader, out);
	    templateReader.reset();
	}

	r.close();
	ps.clearParameters();
	return i - 1;
    }

    static Writer createFileWriter(String filename) throws IOException {
	OutputStream os = new FileOutputStream(filename);
	return new OutputStreamWriter(os, Tema.outputEncoding);
    }

    static Reader createFileReader(File file) throws IOException {
	InputStream is = new FileInputStream(file);
	return new InputStreamReader(is, Tema.inputEncoding);
    }

    static Reader createCachedFileReader(File file) throws IOException {
	if (fileCache != null) return new StringReader(readFile(file));
	else return createFileReader(file);
    }

    /**
     * Read text file.
     */
    static String readFile(File file) throws IOException {
	String data;

	if (fileCache != null) {
	    data = fileCache.get(file);	    
	    if (data != null) return data;
	}

        Reader r = new BufferedReader(createFileReader(file));

        // FIXME: possible overflow (long -> int).
	StringBuffer sb = new StringBuffer((int)file.length());

	try {
 	    for (int c = r.read(); c >= 0; c = r.read()) {
 		sb.append((char)c);
 	    }
	} finally {
	    r.close();
	}

	data = sb.toString();

	if (fileCache != null) {
	    fileCache.put(file, data);
	}

	return data;
    }
}