package com.postgres.util.Logger;

import java.io.*;
import java.util.*;
import org.apache.log4j.*;
import org.apache.log4j.helpers.*;
import org.apache.log4j.spi.*;

public class LogRepl
implements Logger {
    public static final String LOG_PROPERTIES = "repliclog.cfg";
    public static final String APPENDER_PREFIX = "log4j.appender.A2";
    private static String logFileName = "replication.log";
    private static String logDir = "log";
    private static boolean debug = true;
    private static LogRepl instance;

    // put some defaults:
    private static Properties appenderProperties = new Properties();
    static {
        appenderProperties.put("log4j.appender.A2","org.apache.log4j.RollingFileAppender");
        //appenderProperties.put("log4j.appender.A2.File", logDir + "/" + logFileName);
        appenderProperties.put("log4j.appender.A2.Append","true");
        appenderProperties.put("log4j.appender.A2.MaxFileSize","5MB");
        appenderProperties.put("log4j.appender.A2.MaxBackupIndex","4");
        appenderProperties.put("log4j.appender.A2.layout","org.apache.log4j.TTCCLayout");
        appenderProperties.put("log4j.appender.A2.layout.ContextPrinting","true");
        appenderProperties.put("log4j.appender.A2.layout.DateFormat","ISO8601");
        appenderProperties.put("log4j.rootCategory","DEBUG,A2");
    }

    private static MyCategory categoryR = null;
    private static boolean initialized;

    private static String replicHome;

    public void warn(Object value) { getCategory().warn(value); }

    public void warn(Object value, Throwable t)
    { getCategory().warn(value, t); }

    public void error(Object value) { getCategory().error(value); }

    public void error(Object value, Throwable t)
    { getCategory().error(value, t); }

    public void debug(Object value) { getCategory().debug(value); }

    public void debug(Object value, Throwable t)
    { getCategory().debug(value, t); }

    public void fatal(Object value) { getCategory().fatal(value); }

    public void fatal(Object value, Throwable t)
    { getCategory().fatal(value, t); }

    public void info(Object value) { getCategory().info(value); }

    public void info(Object value, Throwable t)
    { getCategory().info(value, t); }

    public void log(Throwable value) { getCategory().error(value); }

    public void log(String value) { getCategory().debug(value); }

    public void log(Object value) {
        if (value instanceof Collection) {
            for (Iterator it = ((Collection)value).iterator(); it.hasNext(); ) {
                getCategory().debug(it.next());
            }
        }
        else {
            getCategory().debug(value);
        }
    }

    public static LogRepl getInstance(){
        if ( instance == null)  {
            instance= new  LogRepl();
        }
        return instance;
    }

    //logDir

    public static void initialize(String alogFileName, String alogDir, String areplicHome)
    throws Exception {
        if (alogFileName != null && !alogFileName.trim().equals("")) {
            logFileName = alogFileName;
        }

        if (alogDir != null && !alogDir.trim().equals("")) {
            logDir = alogDir;
        }

        if (areplicHome == null && areplicHome.trim().equals("")) {
            throw new Exception("LogRepl::initialize: areplicHome may not be empty");
        }
        replicHome = areplicHome;

        //start the logger:
        getCategory();
        initialized = true;
    }

    public static void initialize(String alogFileName, String areplicHome)
    throws Exception {
        initialize(alogFileName, null, areplicHome);
    }

    public static void initialize(String areplicHome) throws Exception {
        initialize(null, areplicHome);
    }

    /*
    */

    private static Properties loadConfig()
    throws Exception {

        // The configuration file is considered to be a system
        // resource.
        java.io.InputStream in;
        Properties appenderProperties = null;

        // Get our class loader
        ClassLoader cl = LogRepl.class.getClassLoader();
        if (cl != null) {
            in = cl.getResourceAsStream(LOG_PROPERTIES);
        }
        else {
            in = ClassLoader.getSystemResourceAsStream(LOG_PROPERTIES);
        }

        // If the input stream is null, then the configuration file
        // was not found
        if (in == null) {
            System.out.println("Replication configuration file '" +
            LOG_PROPERTIES + "' not found: using default properties");
        } else {
            try {
                appenderProperties = new java.util.Properties();

                // Load the configuration file into the properties table
                appenderProperties.load(in);
            } finally {
                // Always close the input stream
                if (in != null) {
                    try {
                        in.close();
                    } catch (Exception ex) {}
                }
            }
        }
        return appenderProperties;
    }

    private static Category getCategory() {
        if (!initialized && categoryR != null) {
            System.out.println("LogRepl::getCategory: Logger is not initialized!");
            System.exit(3);
        }
        if (categoryR == null) {
            synchronized(LogRepl.class) {
                try {
                    Properties fileProperties = loadConfig();

                    if (fileProperties != null) {
                          java.util.Enumeration enum = fileProperties.keys();
                          while (enum.hasMoreElements()) {
                              String key = (String) enum.nextElement();
                              String value = fileProperties.getProperty(key);
                              if(debug) trace("(File Property) " + key + " = " + value);
                              appenderProperties.put(key, value);
                          }
                    }
                    String relativeName = logDir + "/" + logFileName;
                    if (fileProperties != null) {
                         relativeName = fileProperties.get("log4j.appender.A2.File") == null ? relativeName : (String) fileProperties.get("log4j.appender.A2.File");
                    }
                    String logPath = replicHome + "/" + relativeName;
                    if (debug) System.out.println("LogRepl::getCategory: logPath="+logPath);
                    if (debug) System.out.println("LogRepl::getCategory: BEFORE put get(log4j.appender.A2.File)="+appenderProperties.get("log4j.appender.A2.File"));
                    appenderProperties.put("log4j.appender.A2.File", logPath);
                    if (debug) System.out.println("LogRepl::getCategory: AFTER put get(log4j.appender.A2.File)="+appenderProperties.get("log4j.appender.A2.File")+"\n");

                    makeDir(logPath) ;

                    if (debug) {
                        java.util.Enumeration enum = appenderProperties.keys();
                        while (enum.hasMoreElements()) {
                              String key = (String) enum.nextElement();
                              String value = appenderProperties.getProperty(key);
                              if(debug) trace("(Appender Property) " + key + " = " + value);
                          }
                    }

                    //String props = LogRepl.class.getResource(LOG_PROPERTIES).getFile();
                    //String logPathFile = props.get(APPENDER_PREFIX);

                    //trace(appenderProperties);
                    //PropertyConfigurator.configure(props);
                    PropertyConfigurator.configure(appenderProperties);
                }
                catch (Exception xcp) {
                    Category root = Category.getRoot();
                    Layout layout = new TTCCLayout();
                    root.addAppender(
                        new FileAppender(layout, System.out));
                }

                categoryR = (MyCategory)MyCategory.getInstance("replic");
                categoryR.debug("LOGGER STARTED");
            }
        }

        return categoryR;
    }

    private static class MyCategory extends Category {
        private static MyFactory g_factory = new MyFactory();

        public MyCategory(String name) { super(name); }

        public static Category getInstance(String name) {
            return Category.getInstance(name, g_factory);
        }
    }


    private static class MyFactory implements CategoryFactory {
        public Category makeNewCategoryInstance(String name) {
            return new MyCategory(name);
        }
    }

    /*
    */
    private static void makeDir(String name) throws Exception {
        if (name == null || name.trim().equals("")) {
            throw new Exception("LogRepl::makeDir: file name arg has to represent full file path & may not be empty string");
        }

        try {
             File file = new File(name);
             String dir = file.getParent();
             if (debug) System.out.println("LogRepl::makeDir: make dir [" + dir +"]");
             (new File(dir)).mkdirs();
        } catch (Exception e) {
             throw new Exception("LogRepl::makeDir: " + e.toString());
        } finally {
        
        }
    }

    /** <p>Trace the given string */
    private static void trace(String s) {
        System.out.println("Logrepl: " + s);
    }
}
