// $Id: PmiiFacade.java,v 1.12 2004/09/24 20:07:11 m31 Exp $
//
// This file is part of the program suite "Principia Mathematica II"
// which is a working prototype for the main project:
// "Hilbert II" - http://www.qedeq.org
//
// Copyright 2001-2004  Michael Meyling <mime@qedeq.org>.
//
// "Principia Mathematica II" 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 2 of the License, or (at your option) any later version.
//
// This program 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.

package com.meyling.principia;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import com.meyling.principia.config.Settings;
import com.meyling.principia.log.Log;
import com.meyling.principia.log.Logger;
import com.meyling.principia.log.Trace;
import com.meyling.principia.module.ModuleContext;
import com.meyling.principia.module.ModuleEventListener;


/**
 * Gives outside access to the application. 
 *
 * @version $Revision: 1.12 $
 * @author  Michael Meyling
 */
public class PmiiFacade {

    /** the one and only instance. */
    private static PmiiFacade instance = null;

    
    private final FileOutputStream lockStream;
    
    private final File lockFile;


    private PmiiFacade() throws AlreadyRunningException {
        this.lockFile = new File("pmiilock.lck" );
        final String osName = System.getProperty("os.name");
        if (osName.startsWith("Windows")) {
            if ((lockFile.exists() && !lockFile.delete())) {
                throw new AlreadyRunningException("It seems the application is already running.\n" +
                    "At least the file \"" + lockFile.getAbsolutePath() + "\" couldn't be deleted.");
            }
        } else {
            if ((lockFile.exists())) {
                throw new AlreadyRunningException("It seems the application is already running or crashed.\n" +
                    "At least the file \"" + lockFile.getAbsolutePath() + "\" must be manually deleted!");
            }
        }
        try {
            lockStream = new FileOutputStream(lockFile);
            lockStream.write("LOCKED".getBytes());
            lockStream.flush();
        } catch (IOException e) {
            Trace.trace(this, "Constructor", e);
            throw new AlreadyRunningException("It seems the application is already running.\n" +
                    "At least locking the file \"" + lockFile.getAbsolutePath() + "\" failed.");
        }
    }


    /**
     * Get instance of config access. Method {@link #init} must have been called before.
     *
     * @return  singleton, which is responsible for the outside access of this programm suite.
     * @throws  IllegalStateException   {@link #init} wasn't called before this method call.
     */
    public final static PmiiFacade getInstance() throws IllegalStateException {
        if (instance == null) {
            throw new IllegalStateException(PmiiFacade.class.getName() 
                + " not initialized, call init before!");
        }
        return instance;
    }


    public final static void init() throws IOException, AlreadyRunningException {
        setup();
        ModuleContext.setup();
    }
            

    public final static void init(final ModuleEventListener listener) 
            throws IOException, AlreadyRunningException {
        setup();
        ModuleContext.setup(listener);
    }


    public final static void init(final ModuleEventListener listener, final Log log) 
            throws IOException, AlreadyRunningException {
        setup();
        Logger.getInstance().addLog(log);
        ModuleContext.setup(listener);
    }


    private final static void setup() throws IOException, AlreadyRunningException {

        if (instance != null) {
            throw new IllegalStateException(PmiiFacade.class.getName() 
                + " is already initialized!");
        }
        synchronized (PmiiFacade.class) {
            if (instance == null) {
                instance = new PmiiFacade();
            } else {
                throw new IllegalStateException(PmiiFacade.class.getName() 
                    + " is already initialized!");
            }
        }
        
        // get start directory for config location
        final String webStart = (String) System.getProperties().get("javawebstart.version");
        final File startDirectory;
        if (webStart != null) {
            final String userHomeWS = System.getProperties().get("jnlpx.deployment.user.home") 
                != null ? (String) System.getProperties().get("jnlpx.deployment.user.home")
                : "";
            final String userHome = System.getProperties().get("user.home") != null
                ? (String) System.getProperties().get("user.home") : "";
            startDirectory = new File(
                new File((userHomeWS.length() != 0 ? userHomeWS : userHome)), "pmii");    
        } else {
            startDirectory = new File(".");
        }
        
        // setup config
        Settings.setup(startDirectory);
        
        // setup trace
        final String traceName = Settings.getInstance().getTraceFilePath();
        final File trace = new File(traceName);
        trace.getParentFile().mkdirs();
        Trace.setPrintStream(new PrintStream(new FileOutputStream(trace)));
        
        // setup logging
        final String logName = Settings.getInstance().getLogFilePath();
        final File log = new File(logName);
        log.getParentFile().mkdirs();
        Logger.getInstance().addLog(new PrintStream(new FileOutputStream(log, true)));
    }


    public final ModuleContext getModuleContext() {
        if (instance == null) {
            throw new IllegalStateException(PmiiFacade.class.getName() 
                + " was not initialized!");
        }
        return ModuleContext.getInstance();
    }


    public static void shutdown() {
        try {
            if (Settings.isInitialized()) {
                Settings.getInstance().setCheckedModules(ModuleContext.getInstance()
                    .getAllCheckedModules());
                Settings.getInstance().store();
            }
        } catch (IOException ex) {
            Trace.trace(PmiiFacade.class, "shutdown", ex);
        }
        if (instance != null) {
            try {
                instance.lockStream.close();
            } catch (IOException e) {
            }
            instance.lockFile.delete();
        }
        instance = null;
        // TODO
        // what todo with instance? 
        // shutdown process?
        // close logging
        // close trace
    }

}
