/*
 * ECatalog is a database front-end, with two main features:
 * 1. Use of preferences
 *  A preference-based approach, where the user is allowed to define the importance of each criterion.
 *  Then the items are ranked accordingly to his criteria.
 * 2. Trade-off analysis
 *  A cooperative database approach, where the system "argues" with the user about his criteria.
 *  When there are no matching items, the system explains the minimal conflicting set and
 *  give some possible strong and weak relaxations about his criteria.
 * This package also containts the software and the set-up details used for our User Study,
 * comparing the use or not of the two previous features mentioned above.
 *
 * Copyright (C) 2006 David Portabella Clotet, Artificial Intelligence Laboratory, EPFL
 * 
 * This file is part of ecatalog-1.0.zip
 * 
 * ECatalog is free software and a free user study set-up;
 * you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * ECatalog 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with ECatalog; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 * @version 1.0
 * @author David Portabella
 * To contact the author:
 * email: david@portabella.name and david.portabella@epfl.ch
 * 
 * More information about ECatalog:
 *  http://sourceforge.net/projects/ecatalog/
 *  http://icwww.epfl.ch/~portabel/ecatalogs/
 */

package utils;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;

import java.io.*;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.TimeZone;
import java.text.SimpleDateFormat;
import java.util.Vector;

import dpc.utils.TextUtil;
import dpc.utils.OutputStreamStringBuffer;


//TODO: catch Exceptions and printStackTrace in the logFile with a custom <error> attribute

public class Log {
    public PrintWriter out;
    SimpleDateFormat sdf;
    String rootTagName;

    public Log(String rootTagName, String fileName) throws IOException {
	this(rootTagName, true, new PrintWriter(new FileWriter(fileName, false), true));
    }

    public Log(String rootTagName, boolean printHeader, PrintWriter out) {
	this.out = out;
	this.rootTagName = rootTagName;

	String DATE_FORMAT = "yyyy/MM/dd HH:mm:ss.SSS";
	sdf = new java.text.SimpleDateFormat(DATE_FORMAT);
	sdf.setTimeZone(TimeZone.getDefault());          

	if (printHeader)
	    out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
	
	//out.println("<ecatalogLog configTitle=" + escape(ecatalog.getConfig().getTitle()) + " " + getTimeTags() + ">");
	out.println("<" + rootTagName + " " + getTimeTags() + ">");
    }
    
    public void close() {
	out.println("<closing " + getTimeTags() + "/>");
	out.println("</" + rootTagName + ">");
	out.close();
    }

    /* It is the responsability of the one using this log or the subclasses of this class to
     * take care if there can be open tags... */
    public PrintWriter getPrintWriter() {
	return out;
    }

    public void genericInfo(String name) {
	genericInfo(name, null, null);
    }

    public void genericInfo(String name, String[][] valuePairs) {
	genericInfo(name, valuePairs, null);
    }

    public void genericInfo(String name, String[][] valuePairs, String attributeBody) {
	out.print("<" + name + " " + getTimeTags());
	if (valuePairs != null) {
	    for (int i = 0; i < valuePairs.length; i++) {
		if (valuePairs[i][1] != null)
		    out.print(" " + valuePairs[i][0] + "=" + escape(valuePairs[i][1]));
	    }
	}
	if (attributeBody == null)
	    out.println("/>");
	else
	    out.print(">\n" + attributeBody + "\n</" + name + ">\n");

	out.flush();
    }


    public void error(Throwable e) {
	System.out.println("ECatalogLog: " + e);
	e.printStackTrace(System.out);

	String[][] valuePairs = new String[][] {{"string", e.toString()}};
	OutputStreamStringBuffer eString = new OutputStreamStringBuffer(5000);
	e.printStackTrace(new PrintStream(eString));
	
	genericInfo("error", valuePairs, escapeXmlText(eString.toString()));
    }

    public String valuePairsToString(String[][] valuePairs) {
	if (valuePairs == null) 
	    return "";
	StringBuffer text = new StringBuffer();
	for (int i = 0; i < valuePairs.length; i++) {
	    if (valuePairs[i][1] != null)
		text.append(" " + valuePairs[i][0] + "=" + escape(valuePairs[i][1]));
	}
	return text.toString();
    }


    public String escape(String text) {
	//return TextUtil.escapeText(text, true);
	return "\"" + escapeXmlText(text) + "\"";
    }


    //dpc.exe.createCharTable
    //String validCars = " !#$%()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~";
    boolean[] validCars = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,false,true,true,true,false,false,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,false,true,false,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,false,true,true,true,false,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false};
    public String escapeXmlText(String text) {
	StringBuffer escapedText = new StringBuffer();
	for (int i = 0; i < text.length(); i++) {
	    int car = text.charAt(i);
	    if (validCars[car])
		escapedText.append((char)car);
	    else
		escapedText.append("&#" + (int)car + ";");
	}
	return escapedText.toString();
    }

    public String getTimeTags() {
	Calendar cal = Calendar.getInstance(TimeZone.getDefault());
	String timeString = "\"" + sdf.format(cal.getTime()) + "\"";
	String timeMsString = "\"" + String.valueOf(cal.getTimeInMillis()) + "\"";

	return "time=" + timeString + " timeMs=" + timeMsString;
    }

    public String[][] merge(String[][] valuePairs1, String[][] valuePairs2) {
	if (valuePairs1 == null) valuePairs1 = new String[0][];
	if (valuePairs2 == null) valuePairs2 = new String[0][];

	String[][] valuePairs = new String[valuePairs1.length + valuePairs2.length][];
	for (int i = 0; i < valuePairs1.length; i++)
	    valuePairs[i] = valuePairs1[i];

	for (int i = 0; i < valuePairs2.length; i++)
	    valuePairs[i+valuePairs1.length] = valuePairs2[i];
	return valuePairs;
    }

    /*
    String time() {
	Calendar cal = Calendar.getInstance(TimeZone.getDefault());
	return "\"" + sdf.format(cal.getTime()) + "\"";
    }
    */

    /*
      durationf = new java.text.SimpleDateFormat(DATE_FORMAT);
      durationf.setTimeZone(TimeZone.getDefault());          
      String DURATION_FORMAT = ":mm:ss:SSS";
      
    public Object processStart() {
	long start = System.currentTimeMillis();
	return new Long(long);
    }

    public void processFinished(Object id, String name) {
	long end = System.currentTimeMillis();
	int duration = end - (Long)id;
	
	Calendar cal = Calendar.getInstance(TimeZone.getDefault());
	cal.setTimeInMillis(duration);
	int hours = duration / (1000*3600);

	String durationString = "\"" + String.valueOf(hours) + durationf.format(cal.getTime()) + "\"";
	
	genericInfo(name, {{"duration", durationString}});
    }
    */

}


