/*
 * Scone - The Web Enhancement Framework
 * Copyright (C) 2009 Harald Weinreich, Volkert Buchmann, Frank Wollenweber, Torsten Haß
 *
 * This program 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package scone;


import java.util.Enumeration;
import java.util.Vector;

import scone.netobjects.AccessCache;
import scone.netobjects.CacheTable;
import scone.netobjects.DBTableAdapter;
import scone.netobjects.HtmlNodeCache;
import scone.netobjects.InclusionCache;
import scone.netobjects.KeywordCache;
import scone.netobjects.LinkCache;
import scone.netobjects.NetNodeCache;
import scone.netobjects.Node2KeyCache;
import scone.netobjects.PersonCache;
import scone.netobjects.ServerCache;
import scone.netobjects.UserCache;
import scone.robot.Robot;
import scone.robot.RobotTask;
import scone.util.ConfigGui;
import scone.util.PluginRepository;
import scone.util.WbiKillerGUI;


/**
 * This class has the main method to invoke the Scone framework.
 * Execute <code>java scone.Scone -help</code> for command line options.
 *
 * @author Harald Weinreich
 * @author Volkert Buchmann
 * @author Torsten Haß
 * @author Frank Wollenweber
 *
 * @version 1.2.1
 */

public class Scone {
    public static final String COPYRIGHT = "Harald Weinreich, Volkert Buchmann, Torsten Haß, Frank Wollenweber";
    public static final String VERSION = "1.2.1";

    public static PluginRepository plugins = null;

    private static WbiKiller wbiKiller = new WbiKiller();

    public static void main(String args[]) {

        System.out.println("\nThis is Scone "+VERSION);
        if (posInArray("-help", args) >= 0 || posInArray("-h", args) >= 0) { // || posInArray("-?",args)>=0){
            System.out.println("");
            System.out.println("Scone command line options:");
            System.out.println("-config /-setup   GUI to configure database, user tracking and plugins");
            System.out.println("-register plugin  Register a new Scone plugin");
            System.out.println("-noWBI            Start Scone without WBI");
            System.out.println("-killergui        Start Scone with the WBI Killer GUI");
            System.out.println("");
            System.out.println("WBI options:");
            System.out.println("-c config_name    Use other configuration file    ");
            System.out.println("-t trace_levels:                          ");
            System.out.println("   n              No (default)");
            System.out.println("   e              Exceptions only ");
            System.out.println("   m              MEG-Communications");
            System.out.println("   v              Verbose");
            System.out.println("-m msg_levels:");
            System.out.println("   n              No (default)");
            System.out.println("   i              Informative");
            System.out.println("   w              Warnings");
            System.out.println("   e              Errors");
            System.out.println("   v              Verbose");
            System.out.println("-g                Start WBI with GUI (WBI 4.5 only) ");
            System.out.println("-nogui            Disable GUI        (WBI 4.5 only) ");
            System.out.println("                  To enable GUI in 4.6 type 'enable ibm/gui' at console");

            System.exit(0);
        }

        // read the configuration
        plugins = new PluginRepository();

        // does someone want to register something?
        if (posInArray("-register", args) >= 0) {
            if (args.length >= (posInArray("-register", args) + 1)) {
                String name = args[posInArray("-register", args) + 1];

                System.out.println("registering " + name);
                plugins.register(name);
                plugins.store();
                System.exit(0);
            } else {
                System.out.println("You have to specify a plugin!");
                System.exit(0);
            }
        }

        // did the user request the config GUI?
        if (posInArray("-config", args) >= 0 || posInArray("-setup", args) >= 0) {
            new ConfigGui(plugins);
        } else // No? Start Scone!
        {
            System.out.println("Call \"runscone -help\" for options");

            // initialize the database
            initCaches();

            // do we have run WBI?
            if (posInArray("-noWBI", args) == -1) {

                // try {
                    System.out.print("WBI: ");
                    com.ibm.wbi.Run.main(args);
                    // do we have to run the killer gui?
                    if (posInArray("-killergui", args) >= 0) {
                        new WbiKillerGUI();
                    }
                // } catch (java.util.MissingResourceException e) {
                //    System.err.println("ERRRROORRRR");
                //}
            }
        }

    }

    // helper method for commandline commands
    protected static String[] delPosInArray(int pos, String array[]) {
        String a[] = new String[array.length - 1];
        int j = 0;

        for (int i = 0; i < array.length; i++) {
            if (i != pos) {
                a[j] = array[i];
            }
            j++;
        }
        return a;
    }

    // helper method for commandline commands
    protected static int posInArray(String arg, String args[]) {
        arg = arg.toUpperCase();
        for (int i = 0; i < args.length; i++) {
            if (arg.toUpperCase().equals(args[i].toUpperCase())) {
                return i;
            }
        }
        return -1;
    }

    // this method must be called before the first cache is accessed!
    public static void initCaches() {
        // init DBTableAdapter
        // DBTableAdapter.init();
        DBTableAdapter.init();

        // Init the caches: First parameter is save interval (ms +- 10s random, see CacheTable.java)
        NetNodeCache.init(  1 * 60 * 1000, CacheTable.LAZYGC);
        HtmlNodeCache.init( 2 * 60 * 1000, CacheTable.LAZYGC);
        LinkCache.init(     2 * 60 * 1000, CacheTable.LAZYGC);
        InclusionCache.init(2 * 60 * 1000, CacheTable.LAZYGC);
        ServerCache.init(   3 * 60 * 1000, CacheTable.LAZYGC);
        KeywordCache.init(  4 * 60 * 1000, CacheTable.LAZYGC);
        Node2KeyCache.init( 4 * 60 * 1000, CacheTable.LAZYGC);
        AccessCache.init(   2 * 60 * 1000, CacheTable.LAZYGC);
        UserCache.init(    10 * 60 * 1000, CacheTable.LAZYGC);
        PersonCache.init(  10 * 60 * 1000, CacheTable.LAZYGC);
    }

    /**
     * Invoke this method in order to shut down scone.
     * This does not shut down the proxy, but is called by the proxy when
     * it shut downs itself.
     * cleans the caches for safe termination and calls each Plugin's
     * terminate() method
     */
    public static void terminate() {

        // The RAS-Servers are terminated in scone.plugin.Plugin

        System.out.println("\n-> Scone: Terminating Plugins...");
        plugins.terminate();

        System.out.println("\n-> Scone: Terminating Robots...");
        Robot robot = Robot.instance(); // Get a reference to the scone-robot
        Vector robotTasks = robot.getRobotTasks();
        Enumeration tasks = robotTasks.elements();
        while (tasks.hasMoreElements()) {
            RobotTask rt = (RobotTask) tasks.nextElement();
            if (rt!=null) robot.stopRobotTask(rt);
        }
        while (robot.getNumberOfRobotTasks()>0) {}   // Wait until they are finished...

        System.out.println("\n-> Scone: Writing Data to Database...");

        LinkCache.clean();
        InclusionCache.clean();
        NetNodeCache.clean();
        HtmlNodeCache.clean();
        ServerCache.clean();
        KeywordCache.clean();
        Node2KeyCache.clean();
        AccessCache.clean();
        UserCache.clean();
        PersonCache.clean();
    }

    /**
     * aborts WBI.
     * Works like the "abort" command on the WBI console.
     */
    public static void abortWBI() {
        wbiKiller.abort();
    }

    /**
     * shuts down WBI.
     * Works like the "shutdown" command on the WBI console.
     * @param timeout the timeout
     */
    public static void shutdownWBI(int timeout) {
        wbiKiller.shutdown(timeout);
    }

    // this class is able to shtudown or abort WBI
    private static class WbiKiller extends com.ibm.wbi.Run {

        // aborts WBI
        public void abort() {
            System.out.println("Aborting WBI...");
            theProxy.abort();
            System.out.println("WBI aborted.");
            System.exit(0);
        }

        // shuts WBI down
        public void shutdown(int timeout) {
            System.out.println("Shutting down WBI, timout = " + timeout);
            if (!theProxy.terminate(timeout)) {
                System.out.println("Could not terminate all threads within time limit!");
            }
            System.out.println("WBI shut down");
            System.exit(0);
        }
    }

}
