/*
 * 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.proxy;


import java.util.Enumeration;
import java.util.Hashtable;

import scone.Plugin;
import scone.Scone;
import scone.ras.RasServer;
import scone.util.BrowserControl;
import scone.util.ErrorLog;
import scone.util.PersistentProperties;
import scone.util.PluginRepository;
import scone.util.PluginRepositoryEntry;

import com.ibm.wbi.PluginException;
import com.ibm.wbi.SystemContext;
import com.ibm.wbi.protocol.http.HttpPlugin;
import com.ibm.wbi.protocol.http.beans.FixContentTypeEditor;


/**
 * the proxy class of the Scone framework.
 *
 * Internally, this class is actually a WBI plugin.
 */

public class Proxy extends HttpPlugin {

    public static final String COPYRIGHT = "(C) Harald Weinreich & Volkert Buchmann";

    // the standard megs
    private static GeneralResourceGenerator generalResourceGenerator = null;

    protected static SystemContext systemContext;

    protected static Hashtable rasServers = new Hashtable();

    // the requirements
    private int requirements;
    private PluginRepository plugins = null;

    /**
     * do not meddle with this method, it is internal!
     */
    public void initialize() {

        try {
            this.plugins = Scone.plugins;
            this.requirements = plugins.getRequirements();
            systemContext = getSystemContext();

            // WBI's fix ContentType for GIFs
            FixContentTypeEditor fixContentTypeEditor = new FixContentTypeEditor();

            fixContentTypeEditor.setup("Fix Content Type Editor for GIFs", "!host=null & content-type=text/html", 100);  // Fix Mime Type (Do First!)
            addMeg(fixContentTypeEditor);

            // Scones fix ContentType2 for CSS and JavaScript
            FixContentTypeEditor2 fixContentTypeEditor2 = new FixContentTypeEditor2();

            fixContentTypeEditor2.setup("Fix Content Type Editor2 for CSS and JS", "!host=null & content-type=text/html", 100);  // Fix Mime Type (Do First!)
            addMeg(fixContentTypeEditor2);
            
            // and let's go!
            meetRequirements();
            initPlugins();
            startRas();

            System.out.println("-> Scone initialization completed.");

        } catch (Exception exc) {
            ErrorLog.log(this, "initialize()", "Fatal Error!", exc);
        }
        System.out.print("WBI: ");
    }

    /**
     * If RESOURCEGENERATOR is required, the proxy comes with a
     * preinstalled GeneralResourceGenerator. This method adds a mapping
     * to this Generator.<br>
     * @param web see GeneralResourceGenerator.addPath()
     * @param fileSystem see GeneralResourceGenerator.addPath()
     */
    public static void addVirtualPath(String web, String fileSystem) {
        generalResourceGenerator.addPath(web, fileSystem);
    }

    // returns true if the requirement has been added to the requirements
    protected boolean isRequired(int requirement) {
        return ((requirements & requirement) == requirement);
    }

    // register stuff according to the requirements
    private void meetRequirements() {

        PersistentProperties props = new PersistentProperties("config/scone/accesstracking.xml");

        System.out.println("-> Scone requirements : " + Integer.toBinaryString(requirements));

        if (isRequired(Plugin.ACCESSTRACKING2) && !isRequired(Plugin.ACCESSTRACKING)) {
            // we need usertracking. that means we might have to consider new requirements!
            plugins.register("scone.accesstracking2.AccessTracking");
            requirements |= plugins.getRequirements();
            System.out.println("-> AccessTacking2     : enabled");
        }

        if (isRequired(Plugin.ACCESSTRACKING)) {
            // yes we need usertracking. that means we might have to consider new requirements!
            plugins.register("scone.accesstracking.AccessTracking");
            requirements |= plugins.getRequirements();
            System.out.println("-> AccessTracking     : enabled");
        }

        if (isRequired(Plugin.ACCESSTRACKING2) ||  isRequired(Plugin.ACCESSTRACKING))
        {

            if (props.get("Disable user handling").equals("true")) {
                System.out.println("-> UserHandling       : disabled");
            } else {
                if (isRequired(Plugin.ACCESSTRACKING2) && !isRequired(Plugin.ACCESSTRACKING))
                    plugins.register("scone.accesstracking2.UserHandling");
                else if (isRequired(Plugin.ACCESSTRACKING)) 
                    plugins.register("scone.accesstracking.UserHandling");
                System.out.println("-> UserHandling       : enabled");
            }

            try {
                System.out.print("   Trying to clear IE cache... ");
                BrowserControl.ClearIECache();
                System.out.println("OK");
            } catch (java.io.IOException e) {
                System.out.println("Failed");
                e.printStackTrace();
            }

        }

        // Prevent caching of pages...
        if (isRequired(Plugin.NOCACHE)) {
            NoCacheMeg ncm = new NoCacheMeg();

            ncm.setup("NoCacheMeg", Plugin.HTDOCCONDITION, 95);    // FixContentTypeEditor has 100!
            addMeg(ncm);
            System.out.println("-> Scone: NoCacheMeg installed.");
        }

        // Limit caching of pages...
        if (isRequired(Plugin.PAGETIMEOUT)) {
            PageTimeoutMeg ptm = new PageTimeoutMeg();

            ptm.setup("PageTimeoutMeg", Plugin.HTDOCCONDITION, 1);    // Do this last! 
            addMeg(ptm);
            System.out.println("-> Scone: PageTimeoutMeg installed.");
        }

        // is there need for the StandardHtmlTokenHandler?
        if (isRequired(Plugin.USEPARSINGMEG)) {
            PostDataExtractor pde = new PostDataExtractor();

            pde.setup("Scone PostDataExtractor", Plugin.DECENT_HOST_CONDITION, 90); // FixContentTypeEditor has 100!
            addMeg(pde);

            ParsingMeg pm = new ParsingMeg(requirements);

            pm.setup("Scone ParsingMeg", Plugin.HTDOCCONDITION, 85);
            addMeg(pm);
            // System.out.println("-> Scone: ParsingMeg installed.");

            System.out.println("-> Scone: PostDataExtractor and ParsingMeg installed.");
        }

        // AddPreambleEditor adds Code before the (first) "BODY"-Element.
        if (isRequired(Plugin.ADDPREAMBLE)) {
            AddPreambleEditor ape = new AddPreambleEditor();

            ape.setup("AddPreambleEditor", Plugin.HTDOCCONDITION, 50);
            addMeg(ape);
            System.out.println("-> Scone: AddPreambleEditor installed.");
        }

        // map web paths to filepaths
        if (isRequired(Plugin.RESOURCEGENERATOR)) {
            generalResourceGenerator = new GeneralResourceGenerator();
            generalResourceGenerator.setup("GeneralResourceGenerator", "%true%", 5);
            addMeg(generalResourceGenerator);
            System.out.println("-> Scone: GeneralResourceGenerator installed.");
        }

    }

    // initialize the registered plugins
    private void initPlugins() {

        for (Enumeration e = plugins.getEntries(); e.hasMoreElements();) {
            PluginRepositoryEntry entry = (PluginRepositoryEntry) e.nextElement();

            if (entry.isEnabled() && (entry.getPlugin() != null)) {
                System.out.print("-> Scone: plugin " + entry.getName() + "...");
                entry.getPlugin().init(this);
                entry.getPlugin().init();
                System.out.println("installed.");
            }
        }
    }

    // Start RAS servers
    private void startRas() {
        for (Enumeration e = plugins.getEntries(); e.hasMoreElements();) {
            PluginRepositoryEntry entry = (PluginRepositoryEntry) e.nextElement();

            if (entry.isEnabled() && (entry.getPlugin() != null)
                    && ((entry.getPlugin().getRequirements() | Plugin.RAS) > 0)) {
                try {
                    int rasPort = entry.getPlugin().getRasPort();

                    if (rasPort > 0
                            && rasServers.get(String.valueOf(rasPort)) == null)  // not already started.
                    {  // start RAS
                        RasServer ras = new RasServer(rasPort);

                        ras.start();
                        System.out.println("-> Scone: RAS at port " + entry.getPlugin().getRasPort() + " started.");
                        rasServers.put(String.valueOf(rasPort), ras); // store port and RasServer
                    }
                } catch (Exception ex) {
                    System.out.println("-> Scone: RAS-Server NOT Started! See error log!");
                    ErrorLog.log(this, "meetRequirements()", "Could not start RAS.", ex);
                }
            }
        }
    }

    /**
     * do not call this method. This is done by the WBI framework.
     */
    public void terminate() throws PluginException {

        System.out.println("\n-> Scone: Terminating RAS-Servers...");
        for (Enumeration e = rasServers.elements(); e.hasMoreElements();) {
            RasServer ras = (RasServer) e.nextElement();

            ras.shutdown();
            ras = null;
        }

        // notifies scone of the termination
        Scone.terminate();

        super.terminate();

        System.out.println("\n-> Scone: shutdown complete. CU!");

    }

}

