/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: ActivityLogger.java
 *
 * Copyright (c) 2004, Static Free Software. All rights reserved.
 *
 * Electric(tm) is free software; 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 3 of the License, or
 * (at your option) any later version.
 *
 * Electric(tm) 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.sun.electric.tool.user;

import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.text.Version;
import com.sun.electric.database.variable.EditWindow_;
import com.sun.electric.database.variable.UserInterface;
import com.sun.electric.tool.Job;
import com.sun.electric.util.ClientOS;

import java.awt.geom.Point2D;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;
import java.security.SecureRandom;

/**
 * Class to log job activity.
 */
public class ActivityLogger {

    /** log menu activations */         private static boolean logMenuActivations;
    /** log jobs starting */            private static boolean logJobs;
    /** timestamp everything */         private static boolean logTimeStamps;
//    /** if an exception was logged */   private static boolean exceptionLogged;

    /** Writer */                       private static PrintWriter out = null;
    /** the output file */              private static String outputFile;
    /** log count */                    private static int loggedCount = 0;
    private static final SecureRandom random = new SecureRandom();

    /**
     * Initialize the Activity Logger
     * @param logMenuActivations true to log menu activations
     * @param logJobs true to log jobs starting
     * @param useTimeStamps true to include time stamps (not recommended, makes file harder to read)
     * @param enableLog true to enable logging of events in Electric's log file
     * @param multipleLog true to generate different logfile names
     */
    public static synchronized void initialize(String fileName, boolean logMenuActivations, boolean logJobs,
                                               boolean useTimeStamps, boolean enableLog, boolean multipleLog) {
        ActivityLogger.logMenuActivations = logMenuActivations;
        ActivityLogger.logJobs = logJobs;
        ActivityLogger.logTimeStamps = useTimeStamps;

        if (!enableLog) return; // nothing to do.

        String dirName = ClientOS.isOSMac() ? System.getProperty("user.home") : System.getProperty("user.dir");
        outputFile = dirName + File.separator + fileName;
//        File dir = new File(dirName);
        
        try {
//            outputFile = File.createTempFile(fileName+"-", ".log").getAbsolutePath();
            if (multipleLog)
            {
                long n = random.nextLong();
                n = (n == Long.MIN_VALUE) ? 0 : Math.abs(n); // to cover corner case
                outputFile = outputFile+"-"+ n+".log";
            }
            else
                outputFile = outputFile + ".log";
            File file = new File(outputFile);

            FileOutputStream fos = new FileOutputStream(file);
            BufferedOutputStream bout = new BufferedOutputStream(fos);
            out = new PrintWriter(bout);
            // redirect stderr to the log file
            //System.setErr(new PrintStream(bout, true));
        } catch (IOException e) {
            System.out.println("Warning: Activity Log disabled: "+e.getMessage());
            System.out.println("Activity logs are sent to the standard output once you close Electric.");
            out = new PrintWriter(System.out);
        }
        if (out != null) out.println("Electric "+Version.getVersionInformation());
    }

    /**
     * Return the name of the log file so we can display it in the
     * messages window once the messages window is open.
     */
    public static String getLoggingInformation() 
    {
        if (outputFile != null)
            return "Electric's log file is " + outputFile + ".\n";
        return "Logging is disable. Electric must be restarted to resume logging.\n";
    }

    /**
     * Call to close output writer and warn user if any exceptions were logged.
     */
	public static synchronized void finished() {
		if (out != null) out.close();
	}

    /**
     * Log a menu activation
     * @param menuDescription description of the menu activated
     */
    public static synchronized void logMenuActivated(String menuDescription) {
        if (out == null) return;
        if (!logMenuActivations) return;
        printDelimeter(true);
        out.println("Menu Activated: "+menuDescription);
        //System.out.println("Menu Activated: "+((MenuBar.MenuItemInterface)m).getDescription());
        UserInterface ui = Job.getUserInterface();
        EditWindow_ wnd = ui.getCurrentEditWindow_();
        if (wnd != null)
        {
        	List<Highlight> savedContents = wnd.saveHighlightList();
            if (savedContents != null)
            {
                logHighlights(savedContents, wnd.getHighlightOffset());
            }
        }
    }

    /**
     * Log a tool bar button activation
     * @param buttonName the tool bar button activated
     */
    public static synchronized void logToolBarButtonActivated(String buttonName) {
        if (out == null) return;
        if (!logMenuActivations) return;
        printDelimeter(true);
        out.println("ToolBarButton Activated: "+buttonName);
    }

    /**
     * Log a Job. Logs at the start of the job, and also logs the highlights at the time
     * the job started.
     * @param jobName the job name
     * @param jobType the job type
     * @param cell the current cell
     * @param savedHighlights the starting highlights
     * @param savedHighlightsOffset the starting highlight offset (currently not used)
     */
    public static synchronized void logJobStarted(String jobName, Job.Type jobType, Cell cell,
                                                  List<Highlight> savedHighlights, Point2D savedHighlightsOffset) {
        if (out == null) return;
        if (!logJobs) return;
        printDelimeter(true);
        String cellName = (cell == null) ? "none" : cell.libDescribe();
        new Exception("stack trace");
        out.println("Job Started [Current Cell: "+cellName+"] "+jobName+", "+jobType);
        //System.out.println("Job Started [Current Cell: "+cellName+"] "+jobName+", "+jobType);
        logHighlights(savedHighlights, savedHighlightsOffset);
    }

    /**
     * Log a list of Highlight objects and their offset
     * @param highlights a list of Highlight objects
     * @param offset the offset
     */
    public static synchronized void logHighlights(List<Highlight> highlights, Point2D offset) {
        if (out == null) return;
        if (highlights.size() == 0) return;
        out.println("Currently highlighted: ");
        for (Highlight h: highlights) {
            out.println("    "+h.describe());
        }
    }

    /**
     * Log the time
     * @param time the current time in milliseconds (System.currentTimeMillis)
     */
    public static synchronized void logTime(long time) {
        if (out == null) return;
        if (!logTimeStamps) return;
        Date date = new Date(time);
        out.println("Time: "+date);
    }

    /**
     * Log an Exception. If an exception is logged, the user is prompted when
     * Electric exits to send the log file to a developer.
     * @param e the exeception
     */
    public static synchronized void logException(Throwable e) {
        if (out != null) {
            printDelimeter(true);
            e.printStackTrace(out);
            out.flush();
        }
        e.printStackTrace(System.out);
        String msg = "Exception Caught!!!\n" +
        	e.toString() + "\n" +
        	"The exception has been logged in '" +outputFile+"'";
        if (Job.getUserInterface() != null) {
            Job.getUserInterface().showErrorMessage(msg, "Exception Caught");
        } else {
            System.out.println(msg);
        }
//        exceptionLogged = true;
    }

    /**
     * Log some message
     * @param msg the message
     */
    public static synchronized void logMessage(String msg) {
        if (out == null) return;
        printDelimeter(true);
        out.println(msg);
    }

    /** Temp debug method */
    public static synchronized void logThreadMessage(String msg) {
        if (out == null) return;
        printDelimeter(false);
        out.println(msg);
    }

    /**
     * Print a delimiter between log events for easier reading of the log file
     */
    private static synchronized void printDelimeter(boolean printThreadInfo) {
        if (out == null) return;
        out.println("--------------- "+loggedCount+ " --------------");
        new Exception("stack trace");
        //if (printThreadInfo) out.println("(Thread: "+Thread.currentThread()+", stack size: "+e.getStackTrace().length+")");
        if (logTimeStamps) {
            Date date = new Date(System.currentTimeMillis());
            out.println("  "+date);
        }
        loggedCount++;
    }
}
