/**
 * $Revision: $
 * $Date: $
 *
 * Copyright (C) 2004-2008 Jive Software. All rights reserved.
 *
 * This software is published under the terms of the GNU Public License (GPL),
 * a copy of which is included in this distribution, or a commercial license
 * agreement with Jive.
 */

package org.jivesoftware.openfire.fastpath;

import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager;
import org.jivesoftware.openfire.user.UserNameManager;
import org.jivesoftware.openfire.user.UserNameProvider;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.openfire.cluster.ClusterEventListener;
import org.jivesoftware.openfire.cluster.ClusterManager;
import org.jivesoftware.openfire.fastpath.util.TaskEngine;
import org.jivesoftware.xmpp.workgroup.WorkgroupManager;
import org.jivesoftware.xmpp.workgroup.Workgroup;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.xmpp.component.ComponentManagerFactory;
import org.xmpp.component.ComponentException;
import org.xmpp.packet.JID;

import java.io.File;

/**
 * Openfire Fastpath plugin.
 *
 * @author Matt Tucker
 */
public class FastpathPlugin implements Plugin, ClusterEventListener {

    /**
     * Keep a reference to Fastpath only when the service is up and running in this JVM.
     */
    private WorkgroupManager workgroupManager;

    public void initializePlugin(PluginManager manager, File pluginDirectory) {
        System.out.println("Starting Fastpath Server");

        // Make sure that the enteprise folder exists under the home directory
        File fastpathDir = new File(JiveGlobals.getHomeDirectory() +
            File.separator + "fastpath");
        if (!fastpathDir.exists()) {
            fastpathDir.mkdirs();
        }

        workgroupManagerStart();

        // Listen to cluster events
        ClusterManager.addListener(this);
    }

    public void destroyPlugin() {
        workgroupManagerStop();

        // Stop listen to cluster events
        ClusterManager.removeListener(this);

        // Dispose pending tasks
        TaskEngine.getInstance().dispose();
    }

    private void workgroupManagerStart() {
        workgroupManager = WorkgroupManager.getInstance();
        // Register Fastpath service
        try {
            ComponentManagerFactory.getComponentManager().addComponent("workgroup", workgroupManager);
        }
        catch (ComponentException e) {
            // Do nothing. Should never happen.
            ComponentManagerFactory.getComponentManager().getLog().error(e);
        }
        // Register the provider of workgroup names
        UserNameManager.addUserNameProvider(workgroupManager.getAddress().toString(),
            new UserNameProvider() {
                public String getUserName(JID entity) {
                    try {
                        Workgroup workgroup = workgroupManager.getWorkgroup(entity);
                        return workgroup.getDisplayName();
                    }
                    catch (UserNotFoundException e) {
                        return entity.toString();
                    }
                }

            });
        // Start the Fastpath module
        workgroupManager.start();
    }

    private void workgroupManagerStop() {
        // Unregister workgroup component
        try {
            ComponentManagerFactory.getComponentManager().removeComponent("workgroup");
        }
        catch (ComponentException e) {
            Log.error("Error unregistering workgroup component", e);
        }
        if (workgroupManager != null) {
            // Unregister the provider of workgroup names
            UserNameManager.removeUserNameProvider(workgroupManager.getAddress().toString());
            // Stop the Fastpath module
            workgroupManager.stop();
        }
        // Clean up the reference to the workgroup manager as a way to say that FP is no longer running in this JVM
        workgroupManager = null;
    }

    public void joinedCluster() {
        workgroupManagerStop();
    }

    public void joinedCluster(byte[] nodeID) {
        // Do nothing
    }

    public void leftCluster() {
        workgroupManagerStart();
    }

    public void leftCluster(byte[] nodeID) {
        // Do nothing
    }

    public void markedAsSeniorClusterMember() {
        workgroupManagerStart();
    }
}
