/** BEGIN COPYRIGHT BLOCK
 * Copyright (C) 2001 Sun Microsystems, Inc.  Used by permission.
 * Copyright (C) 2005 Red Hat, Inc.
 * All rights reserved.
 * 
 * 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; version 2
 * of the License.
 * 
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 
 * END COPYRIGHT BLOCK **/
package com.netscape.management.admserv;

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
import javax.swing.*;
import com.netscape.management.client.*;
import com.netscape.management.client.console.*;
import com.netscape.management.admserv.panel.IRestartControl;
import com.netscape.management.admserv.config.BaseConfigPanel;
import com.netscape.management.client.topology.*;
import com.netscape.management.client.util.*;
import com.netscape.management.nmclf.*;
import com.netscape.management.admserv.panel.*;
import netscape.ldap.*;

/**
 * Netscape admin server configuration entry point. The directory
 * server needs to contain the name of this class in order for the topology
 * view to load this class.
 */
public class AdminServer extends AbstractServerObject implements SuiConstants {
    public static ResourceSet _resource = new ResourceSet("com.netscape.management.admserv.admserv");

    ConsoleInfo _consoleInfo;
    int _serverStatus;
    private int adminUrlNodeDataIndex = -1;

    /**
    * Implements the IServerObject interface. Initializes the page with
    * the global information.
    *
    * @param info - global information.
    */
    public void initialize(ConsoleInfo info) {
        super.initialize(info);
        _consoleInfo = info;
        setIcon(new RemoteImage(_resource.getString("admin", "smallIcon")));
        _canRestartFromConsole = !info.getAdminURL().startsWith("https");
    }

    /**
       * Restart activator is used as a repository for various restart control parameters.
       * The reference to the activator is stored in the ConsoleInfo. panel/RestartOperation.java
       * is reading the restart parameters which are set by config panels and operations.
      */
    protected boolean _needsAutoRestart = false;
    protected boolean _canRestartFromConsole; // set in initialize()
    protected String _postRestartURL = null;
    protected boolean _isShutdown = false;

    private IRestartControl _restartControl = new IRestartControl() {
                public void setNeedsAutoRestart(boolean flag) {
                    _needsAutoRestart = flag;
                }
                public boolean needsAutoRestart() {
                    return _needsAutoRestart;
                }

                public void setCanRestartFromConsole(boolean flag) {
                    _canRestartFromConsole = flag;
                }
                public boolean canRestartFromConsole() {
                    return _canRestartFromConsole;
                }

                public void setPostRestartURL(String url) {
                    _postRestartURL = url;
                }

                public String getPostRestartURL() {
                    return _postRestartURL;
                }

                public void setServerShutdown(boolean flag) {
                    _isShutdown = flag;
                }
                public boolean isServerShutdown() {
                    return _isShutdown;
                }


            };

    /* TODO move to AdminTaskPage/ResourcePage/FrameworkInitializer
        IFrameworkListener _closeListener = new IFrameworkListener() {
    	    public void pageSelectionChanged(FrameworkEvent e) {}

    	    public void actionViewClosing(FrameworkEvent e) throws CloseVetoException {
    	        Debug.println("window closing, needs restart =" + _needsAutoRestart);
    	        if (_restartControl.needsAutoRestart()) {
    	            SuiOptionPane.showMessageDialog(_frame,
    	                _resource.getString("restart","mustRestart"),
    	                _resource.getString("restart","title"),
    	                SuiOptionPane.INFORMATION_MESSAGE);

    				AdminOperation operation = new RestartOperation(_consoleInfo);
    				operation.monitorOperation("");
    				String title = _resource.getString("taskName","restart");
    				DialogFrame dialog = new DialogFrame(_frame, title, operation.getPanel());
    				dialog.setVisible(true);
    				dialog.dispose();
    	        }
    	    }
    	};
    */

    private boolean run(IPage viewInstance) {
        // do not run if the server is down
        if (getServerStatus() == IServerObject.STATUS_STOPPED) {
            Frame frame = viewInstance.getFramework().getJFrame();
            String title = _resource.getString("error","OpenServerTitle");
            String msg = java.text.MessageFormat.format(
                    _resource.getString("error","CanNotOpenServer"),
                    new Object[]{ getName()});
            BaseConfigPanel.clearProgressIndicator(
                    (Component) viewInstance);
            SuiOptionPane.showMessageDialog(frame, msg, title,
                    SuiOptionPane.ERROR_MESSAGE);
            return false;
        }

        // Augment the console info with the server name
        _consoleInfo.put("SIE", getSIE());
        _consoleInfo.put("SIE_VERSION", getProductVersion());        
        _consoleInfo.put("SERVER_NAME", getName());
        _consoleInfo.put("HOST_NAME", getHostName());
        _consoleInfo.put(IRestartControl.ID, _restartControl);

        createFramework();

        return true;
    }

    /**
      * This function is called when the admin server is double clicked on the topology view.
      */
    public boolean run(IPage viewInstance,
            IResourceObject selectionList[]) {
        // create new frame
        if (selectionList.length == 1) {
            return run(viewInstance);
        }

        // Do not run if the server is down
        if (getServerStatus() == IServerObject.STATUS_STOPPED) {
            Frame frame = viewInstance.getFramework().getJFrame();
            String title = _resource.getString("error","OpenServerTitle");
            String msg = java.text.MessageFormat.format(
                    _resource.getString("error","CanNotOpenServer"),
                    new Object[]{ getName()});
            BaseConfigPanel.clearProgressIndicator(
                    (Component) viewInstance);
            SuiOptionPane.showMessageDialog(frame, msg, title,
                    SuiOptionPane.ERROR_MESSAGE);
            return false;
        }

        for (int i = 0; i < selectionList.length; i++) {
            if (!(selectionList[i] instanceof ServerNode)) {
                Debug.println("can't run, selection is " +
                        selectionList[i].getClass().getName());
                return false;
            }
            ServerNode node = (ServerNode) selectionList[i];
            if (!(node.getServerObject() instanceof AdminServer)) {
                Debug.println("can't run, server is " +
                        node.getServerObject().getClass().getName());
                return false;
            }

        }

        createFramework();

        return true;
    }


    protected void createFramework() {
        Framework frame = new Framework(
                new AdminFrameworkInitializer(_consoleInfo));
        StatusItemSecureMode _statusSecureMode =
                new StatusItemSecureMode(Framework.STATUS_SECURE_MODE);
        _statusSecureMode.setSecureMode(
                _consoleInfo.getAdminURL().startsWith("https"));
        frame.addStatusItem(_statusSecureMode, IStatusItem.LEFTFIRST);
        _statusSecureMode.setToolTipText(_consoleInfo.getAdminURL());
    }


    // return the host in which this server is installed
    protected String getHostName() {
        return (String)_nodeDataTable.get("serverHostName");
    }

    // return SIE name "admin-serv-<host>"
    protected String getSIE() {
        return (String)_nodeDataTable.get("cn");
    }

    // return the Server version number e.g. "4.1"
    protected String getProductVersion() {
        return (String)_nodeDataTable.get("nsProductVersion");
    }

    public ConsoleInfo getConsoleInfo() {
        return _consoleInfo;
    }


    private URL _serverURL = null;
    private URLConnection _serverConnection = null;

    /**
     * Implements the IServerObject interface.
     */
    public synchronized int getServerStatus() {
        // for admin server, just check whether connections are accepted  on the URL;
        // if the URL does not respond, then it is down. Otherwise it is up.

        // In case the method is called before AdminServer in initialized
        if (_consoleInfo == null) {
            return STATUS_UNKNOWN;
        }


        try {
            String adminURL = _consoleInfo.getAdminURL() + "admin-serv/tasks/operation/StatusPing";
            AdmTask task = new AdmTask(new URL(adminURL),
                    _consoleInfo.getAuthenticationDN(),
                    _consoleInfo.getAuthenticationPassword());
            task.exec();
            int status = task.getStatus();
            if (status == 0) {
                _serverStatus = STATUS_STARTED;
            } else if (task.getException() != null && task.getException()
                    instanceof java.net.SocketException) {
                _serverStatus = STATUS_STOPPED;
            } else {
                _serverStatus = STATUS_UNKNOWN;
            }
            return _serverStatus;
        } catch (MalformedURLException ex) {
            Debug.println("ERROR AdminConfigData.isRunning: bad URL " +
                    _consoleInfo.getAdminURL());
            return _serverStatus = STATUS_UNKNOWN;
        }


    }

    /**
      * Implements the IServerObject interface. This will launch the
      * necessary CGI to clone the configuration of the reference server
      * to this server. Only the following attributes are cloned:
      * <ul>
      * <li>nsadminaccessaddresses
      * <li>nsadminaccesshosts
      * <li>nsadmincachelifetime
      * <li>nsadminenabledsgw
      * <li>nsadminenableenduser
      * <li>nsadminoneacldir
      * <li>nsdefaultacceptlanguage
      * </ul>
      *
      * @param  referenceDN - DN of server to clone from.
      */
    public void cloneFrom(String referenceDN) {
        String configDN = "cn=configuration," + referenceDN;
        String configURL = null;
        try {
            // First, get the configuration information to clone using the referenceDN.
            LDAPConnection ldc = _consoleInfo.getLDAPConnection();
            if (ldc == null) {
                ldc = new LDAPConnection();
            }
            if (ldc.isConnected() == false) {
                ldc.connect(_consoleInfo.getHost(), _consoleInfo.getPort(),
                        _consoleInfo.getAuthenticationDN(),
                        _consoleInfo.getAuthenticationPassword());
            }
            LDAPEntry entry = ldc.read(configDN);
            String addresses = LDAPUtil.flatting(
                    entry.getAttribute("nsadminaccessaddresses",
                    LDAPUtil.getLDAPAttributeLocale()));
            String hosts = LDAPUtil.flatting(
                    entry.getAttribute("nsadminaccesshosts",
                    LDAPUtil.getLDAPAttributeLocale()));
            String cache = LDAPUtil.flatting(
                    entry.getAttribute("nsadmincachelifetime",
                    LDAPUtil.getLDAPAttributeLocale()));
            String dsgw = LDAPUtil.flatting(
                    entry.getAttribute("nsadminenabledsgw",
                    LDAPUtil.getLDAPAttributeLocale()));
            String endUser = LDAPUtil.flatting(
                    entry.getAttribute("nsadminenableenduser",
                    LDAPUtil.getLDAPAttributeLocale()));
            String oneAclDir = LDAPUtil.flatting(
                    entry.getAttribute("nsadminoneacldir",
                    LDAPUtil.getLDAPAttributeLocale()));
            String defaultAccLang = LDAPUtil.flatting(
                    entry.getAttribute("nsdefaultacceptlanguage",
                    LDAPUtil.getLDAPAttributeLocale()));
            boolean enableDSGW;
            boolean enableEndUser;
            if (dsgw != null && dsgw.equalsIgnoreCase("off")) {
                enableDSGW = false;
            } else {
                enableDSGW = true;
            }
            if (endUser != null && endUser.equalsIgnoreCase("off")) {
                enableEndUser = false;
            } else {
                enableEndUser = true;
            }

            // Invoke CGI to configure the server with the cloned configuration information.
            // Some attributes, such as nsadminenableenduser, must be forced set.
            configURL =
                    new String(_consoleInfo.getAdminURL() + "admin-serv/tasks/Configuration/ServerSetup?op=force_set" +
                    "&configuration.nsadminaccessaddresses=" +
                    addresses + "&configuration.nsadminaccesshosts=" +
                    hosts + "&configuration.nsadmincachelifetime=" +
                    cache + "&configuration.nsadminoneacldir=" + oneAclDir +
                    "&configuration.nsdefaultacceptlanguage=" +
                    defaultAccLang);
            if (enableDSGW == true) {
                configURL = configURL + "&configuration.nsadminenabledsgw=";
            } else {
                configURL = configURL + "&configuration.nsadminenabledsgw=off";
            }
            if (enableEndUser == true) {
                configURL = configURL + "&configuration.nsadminenableenduser=";
            } else {
                configURL = configURL + "&configuration.nsadminenableenduser=off";
            }
            Debug.println("TRACE AdminServer.cloneFrom: configURL = " +
                    configURL);

            // Need to make this another thread. Display a dialog to show progress!
            URL configAdminURL = new URL(configURL);
            // Is authenticating with the ConsoleInfo correct???
            AdmTask task = new AdmTask(configAdminURL,
                    _consoleInfo.getAuthenticationDN(),
                    _consoleInfo.getAuthenticationPassword());
            int execStatus = task.exec();
            int taskStatus = task.getStatus();
            String title = _resource.getString("status","cloneTitle");
            if (execStatus == 0 && taskStatus == 0) {
                Debug.println("TRACE AdminServer.cloneFrom: config CGI succeeded!");
                String msg = java.text.MessageFormat.format(
                        _resource.getString("status",
                        "cloneSucceeded"), new Object[]{ getName()});
                SuiOptionPane.showMessageDialog(null, msg, title,
                        SuiOptionPane.INFORMATION_MESSAGE);
            } else {
                // Either the exec or the task failed.
                Debug.println(
                        "ERROR AdminServer.cloneFrom: config CGI status = " +
                        (execStatus == 0 ? taskStatus : execStatus));
                String msg = java.text.MessageFormat.format(
                        _resource.getString("status", "cloneFailed"),
                        new Object[]{ getName()});
                SuiOptionPane.showMessageDialog(null, msg, title,
                        SuiOptionPane.ERROR_MESSAGE);
            }
        }
        catch (LDAPException e) {
            // TODO: Use SuiOptionPane error message
            Debug.println(
                    "ERROR AdminServer.cloneFrom: LDAP read failed: " +
                    configDN);
        }
        catch (MalformedURLException e) {
            // TODO: Use SuiOptionPane error message
            Debug.println("ERROR AdminServer.cloneFrom: Bad URL: " +
                    configURL);
        }
    }

    /**
      * Number of entries for this node.
      * Implements INodeInfo
      *
      * @return number of entries
      */
    public int getNodeDataCount() 
    {
        adminUrlNodeDataIndex = super.getNodeDataCount();
        return adminUrlNodeDataIndex + 1;
    }

    public boolean isCloningEnabled()
    {
        return false;
    }

    /**
      * Return node entry at specified index.
      * Implements INodeInfo
      *
      * @return the specified node data
      */
    public NodeData getNodeData(int index) {
        if(index == adminUrlNodeDataIndex)
        {
            String port = null;  // legal value, if null, this NodeData will not appear in panel
            String url = _consoleInfo.getAdminURL();
            int portIndex = url.lastIndexOf(':');
            if(portIndex != -1)
                port = url.substring(portIndex+1).replace('/', ' ').trim();
            return new NodeData("", _resource.getString("infopanel", "Port"), port, false);
        }
        else
        {
            return super.getNodeData(index);
        }
    }
}
