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

import com.netscape.management.client.console.ConsoleInfo;
import com.netscape.management.client.util.ModalDialogUtil;
import com.netscape.management.client.security.*;
import netscape.ldap.*;

import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.StringTokenizer;
import java.net.URL;
import java.lang.String;

import com.netscape.management.admserv.config.*;
import com.netscape.management.client.util.*;
import com.netscape.management.nmclf.*;

public class TurnOnSSL implements IPluginConfigPanel, EncryptionOptions, IClientAuthOptions{

    static ResourceSet _resource;
    EditMonitor _monitor = null;
    ConsoleInfo _consoleInfo;
    JPanel encryptionPanel = null;
    Hashtable securitySettings = new Hashtable();
    EncryptionPanel _adminEncryptionPanel;
    boolean _isDirty = false;
    boolean _domestic = false;
    ClientAuthPanel _clientAuthPanel;

	static String _i18nMsgNoSslPreferences, _i18nMsgNoSslFamily, _i18nMsgNoCertificate,  _i18nMsgSaved;

    static {
        _resource = new ResourceSet("com.netscape.management.admserv.panel.panel");
        _i18nMsgNoSslPreferences = _resource.getString("TurnOnSSL","MsgNoSslPreferences");
        _i18nMsgNoSslFamily = _resource.getString("TurnOnSSL","MsgNoSslFamily");
        _i18nMsgNoCertificate = _resource.getString("TurnOnSSL","MsgNoCertificate");
        _i18nMsgSaved = _resource.getString("TurnOnSSL","Saved");
    }

    public void clientAuthSettingChanged(int type) {
        Debug.println("TurnOnSSL:clientAuthSettingChanged:"+type);
	securitySettings.put("clientauth", (type==CLIENT_AUTH_REQUIRED)?"on":"off");
	setDirty(true);
    }
    public int getClientAuthSetting() {
        return securitySettings.get("clientauth").equals("on")?CLIENT_AUTH_REQUIRED:CLIENT_AUTH_DISABLED;
    }

    public int[] getClientAuthUIOption() {
        int[] uiOptions = { CLIENT_AUTH_DISABLED, CLIENT_AUTH_REQUIRED };
        return uiOptions;
    }


    private void setDirty(boolean dirty) {
	if (_monitor != null) {
	    _monitor.setDirtyFlag(dirty);
	    _isDirty = dirty;
	}
    }


    void changeSecuritySetting(String key, String val) {
	try {
	    securitySettings.put(key, val);
	    setDirty(true);
	    //Debug.printHashtable("Security Setting", securitySettings);

	    /*System.out.println("TEST="+key+":"+val);*/
	    if (key.equals("security")) {
		_clientAuthPanel.setEnabled(val.equals("on"));
	    }
	} catch (Exception e) {
	    Debug.println("TurnOnSSL: unable to change security setting");
	}
    }

    public void securityEnabledChanged(boolean enabled){
	changeSecuritySetting("security", enabled?"on":"off");
	Debug.println("Security enabled:"+(enabled?"on":"off"));
	//Debug.println(securitySettings);
    }

	
    public void cipherFamilyEnabledChanged(String cipherFamily, boolean enabled){
	Object familyList = securitySettings.get("familyList");
	if ((familyList == null) || (familyList.toString().indexOf(cipherFamily) == -1)) {
	    String listString = familyList.toString();
	    securitySettings.put("familyList", listString.length()>0?(listString+","+cipherFamily):cipherFamily);
	}

	changeSecuritySetting(cipherFamily+"-activated", enabled?"on":"off");
	Debug.println("Enable cipherFamily:"+cipherFamily+":"+enabled);
	//System.out.println(securitySettings);
    }

    public void selectedDeviceChanged(String cipherFamily, String device){
	changeSecuritySetting(cipherFamily+"-token", device);

	Debug.println("Selected device:"+cipherFamily+":"+device);
	//System.out.println(securitySettings);
    }

	public void selectedCertificateChanged(String cipherFamily, String certName){
	    changeSecuritySetting(cipherFamily+"-cert", certName);
	    Debug.println("Selected cert"+cipherFamily+":"+certName);
	    //System.out.println(securitySettings);
	}

	public void showCipherPreferenceDialog(String cipherFamily){
	    Debug.println("Show cipher preference dialog:"+cipherFamily);
	    CipherPreferenceDialog cipherPref = null;

	    if (cipherFamily.toLowerCase().equals("fortezza")) {
		cipherPref = new CipherPreferenceDialog(null,
							"",
							(String)(securitySettings.get("ssl3")),
							"") {
		    public void cipherStateChanged(String SSLVersion, String cipher, boolean enabled) {
			setDirty(true);
		    }
		};
	    } else {
		cipherPref = new CipherPreferenceDialog(null,
							(String)(securitySettings.get("ssl2")),
							(String)(securitySettings.get("ssl3")),
							(String)(securitySettings.get("tls"))) {
		    public void cipherStateChanged(String SSLVersion, String cipher, boolean enabled) {
			setDirty(true);
		    }
		};
	    }

	    cipherPref.setVisible(true);

	    if (!(cipherPref.isCancel())) {
		securitySettings.put("ssl2", cipherPref.getCipherPreference(cipherPref.SSL_V2));
		securitySettings.put("ssl3", cipherPref.getCipherPreference(cipherPref.SSL_V3));
		securitySettings.put("tls", cipherPref.getCipherPreference(cipherPref.SSL_TLS));

		securitySettings.put("ssl2-activated", cipherPref.isSSLVersionEnabled(cipherPref.SSL_V2)?"on":"off");
		securitySettings.put("ssl3-activated", cipherPref.isSSLVersionEnabled(cipherPref.SSL_V3)?"on":"off");
		securitySettings.put("tls-activated", cipherPref.isSSLVersionEnabled(cipherPref.SSL_TLS)?"on":"off");
	    }
	}

	public void setSecurityIsDomestic(boolean domestic) {
	    _domestic = domestic;

	    Object ssl2Setting = securitySettings.get("ssl2");
	    Object ssl3Setting = securitySettings.get("ssl3");
	    Object tlsSetting  = securitySettings.get("tls");

	    //construct a default cipher preference dialog, and get the default settings
	    CipherPreferenceDialog cipherPref = new CipherPreferenceDialog(null, true, true, true, domestic, false, true);

	    if ((ssl2Setting == null) || 
		(ssl2Setting.toString().length() == 0) ||
		(ssl2Setting.toString().equals("blank"))) {
		securitySettings.put("ssl2", cipherPref.getCipherPreference(cipherPref.SSL_V2));
	    }
	    if ((ssl3Setting == null) || 
		(ssl3Setting.toString().length() == 0) || 
		(ssl3Setting.toString().equals("blank"))) {
		securitySettings.put("ssl3", cipherPref.getCipherPreference(cipherPref.SSL_V3));
	    }
	    if ((tlsSetting == null) || 
		(tlsSetting.toString().length() == 0) || 
		(tlsSetting.toString().equals("blank"))) {
		securitySettings.put("tls", cipherPref.getCipherPreference(cipherPref.SSL_TLS));
	    }

	    Object ssl2On = securitySettings.get("ssl2-activated");
	    Object ssl3On = securitySettings.get("ssl3-activated");
	    Object tlsOn  = securitySettings.get("tls-activated");
	    if ((ssl2On == null) || 
		(ssl2On.toString().equals("blank")) ||
		(ssl2On.toString().length() == 0) ) {
		securitySettings.put("ssl2-activated", "on");
	    }
	    if ((ssl3On == null) || 
		       (ssl3On.toString().equals("blank")) ||
		       (ssl3On.toString().length() == 0)) {
		securitySettings.put("ssl3-activated", "on");
	    }
	    if ((tlsOn == null)  ||
		       (tlsOn.toString().equals("blank")) ||
		       (tlsOn.toString().length() == 0) ) {
		securitySettings.put("tls-activated", "on");
	    }
	}

	public boolean isSecurityEnabled() {
	    boolean securityEnabled = false;
	    try {
		securityEnabled = securitySettings.get("security").equals("on");
	    } catch (Exception e) {
		Debug.println("TurnOnSSL: no security setting");
	    }
	    return securityEnabled;
	}

	public boolean isCipherFamilyEnabled(String cipherFamily) {
	    boolean cipherFamilyEnabled = false;
	    try {
		cipherFamilyEnabled = securitySettings.get(cipherFamily+"-activated").equals("on");
	    } catch (Exception e) {
		Debug.println("TurnOnSSL: no security setting");
	    }
	    Debug.println("Cipher family enabled:"+(cipherFamilyEnabled?"true":"false"));
	    return cipherFamilyEnabled;
	}

	public String getSelectedCertificate(String cipherFamily) {
	    String certName = "";
	    try {
		certName = (String)(securitySettings.get(cipherFamily+"-cert"));
	    } catch (Exception e) {
		Debug.println("TurnOnSSL: no security setting");
	    }
	    Debug.println("Get selected cert:"+certName);
	    return certName;
	}

	public String getSelectedDevice(String cipherFamily) {
	    String deviceName = "";
	    try {
		deviceName = (String)(securitySettings.get(cipherFamily+"-token"));
	    } catch (Exception e) {
		Debug.println("TurnOnSSL: no security setting");
	    }
	    Debug.println("Get selected device:"+deviceName);
	    return deviceName;
	}



    public TurnOnSSL(ConsoleInfo consoleInfo) {

        _consoleInfo = consoleInfo;
	Debug.println("TurnOnSSL:TurnOnSSL()");
        _resource = new ResourceSet("com.netscape.management.admserv.panel.panel");

        try {
            AdmTask task = new AdmTask(
                    new URL(_consoleInfo.getAdminURL() + "admin-serv/tasks/configuration/SSLActivate"),
                    _consoleInfo.getAuthenticationDN(),
                    _consoleInfo.getAuthenticationPassword());
            task.exec();
            //System.out.println(task.getStatus());
            //if (task.getStatus()) {  do some error message here }
            Debug.println(task.getResultString().toString());
            StringTokenizer st = new StringTokenizer(
                    task.getResultString().toString(), "\n", false);
            while (st.hasMoreTokens()) {
                String line = st.nextToken();

                int index = line.indexOf("=");
                if (index != -1) {
                    Object key = line.substring(0, index);
                    Object val = securitySettings.get(key);
		    String hashVal = line.substring(index + 1, line.length());
                    if (val == null) {
			securitySettings.put(key,
					     hashVal.toLowerCase().equals("null")?"":hashVal);

			//changeSecuritySetting(key, hashVal.toLowerCase().equals("null")?"":hashVal);
		    } else if (!(hashVal.toString().toLowerCase().equals("null"))) {
                        securitySettings.put(key,
                                val + ","+
                                hashVal);
                    }
                }
            }

        }
        catch (Exception e) {
	    //e.printStackTrace();
	    Debug.println(e.toString());
	}

	if ((securitySettings.get("clientauth") == null) || securitySettings.get("clientauth").toString().equals("")) {
	    //initialize the default setting
	    securitySettings.put("clientauth", "off");
	}


	//Debug.printHashtable("Security Setting", securitySettings);

        //addEncryptionPaneListener(this);
        /*resource = new ResourceSet("com.netscape.management.admserv.panel.panel");
        noTokenSelected = resource.getString("TurnOnSSL", "noTokenSelected");
        noCertSelected = resource.getString("TurnOnSSL", "noCertSelected");
        noCipherSelected = resource.getString("TurnOnSSL", "noCipherSelected");

        setupEncryption();*/
    }

    public String getTitleText() {
        return "";
    }


    public JPanel getPanel() {
	Debug.println("TurnOnSSL:getPanel()");
	if (encryptionPanel == null) {
	    encryptionPanel = new JPanel();
	    encryptionPanel.setLayout(new GridBagLayout());
	    _adminEncryptionPanel = new EncryptionPanel(_consoleInfo, (String)(_consoleInfo.get("SIE")), this);
	    GridBagUtil.constrain(encryptionPanel, _adminEncryptionPanel, 
				  0, 0,  1, 1, 
				  1.0, 0.0,
				  GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL,
				  0, 0, 0, 0);

            _clientAuthPanel = new ClientAuthPanel(this);
            _clientAuthPanel.setBorder(new CompoundBorder(new EtchedBorder(),
                                     new EmptyBorder(SuiConstants.COMPONENT_SPACE, SuiConstants.COMPONENT_SPACE,
                                                     SuiConstants.COMPONENT_SPACE, SuiConstants.COMPONENT_SPACE)));
            GridBagUtil.constrain(encryptionPanel, _clientAuthPanel,
                                  0, 1,  1, 1,
                                  1.0, 0.0,
                                  GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL,
                                  SuiConstants.COMPONENT_SPACE, 0, 0, 0);

	    GridBagUtil.constrain(encryptionPanel, Box.createVerticalGlue(),
				  0, 1,  1, 1, 
				  1.0, 1.0,
				  GridBagConstraints.WEST, GridBagConstraints.VERTICAL,
				  0, 0, 0, 0);

	    Object clientAuthSetting = securitySettings.get("security");
	    _clientAuthPanel.setEnabled(clientAuthSetting==null?false:clientAuthSetting.toString().equals("on"));

	    setDirty(false);
	}

        return encryptionPanel;
    }

    public IConfigDataModel getDataModel() {
        return null;
    }

    public void setDataModel(IConfigDataModel datModel)
            throws ConfigPanelException {
    }
    public void initialize() throws ConfigPanelException {
    }

    public void registerEditComponents(EditMonitor monitor) {
        _monitor = monitor;
    }

    public void resetContent() throws ConfigPanelException {
	_adminEncryptionPanel.reset();
	_clientAuthPanel.reset();

	Object clientAuthSetting = securitySettings.get("security");
	_clientAuthPanel.setEnabled(clientAuthSetting==null?false:clientAuthSetting.toString().equals("on"));
    }

    public void applyChanges() throws ValidationException {
        if (_isDirty) {
            try {
                
                if (validEntries()) {
                    String adminURL = _consoleInfo.getAdminURL() + "admin-serv/tasks/configuration/SSLActivate";
                    AdmTask task = new AdmTask(new URL(adminURL),
                                               _consoleInfo.getAuthenticationDN(),
                                               _consoleInfo.getAuthenticationPassword());
                    
                    securitySettings.put("trustdb", (String)(_consoleInfo.get("SIE")));
                    Debug.printHashtable("Security Setting", securitySettings);
                    task.setArguments(securitySettings);
                    task.exec();
                    Debug.println(task.getResultString().toString());
                    StringTokenizer st = new StringTokenizer(task.getResultString().toString(), "\n", false);
                    //AdminOperation.processAdmTaskStatus(adminURL, task, _consoleInfo);
                    if (task.getResult().get("NMC_Description") != null) {
                        _adminEncryptionPanel.setSaved();
                        _clientAuthPanel.setSaved();
                        SuiOptionPane.showMessageDialog(UtilConsoleGlobals.getActivatedFrame(),
                                                        _i18nMsgSaved);
                    } else if (task.getResult().get("NMC_ErrType") != null) {
                        SuiOptionPane.showMessageDialog(UtilConsoleGlobals.getActivatedFrame(),
                                                        task.getResult().get("NMC_ErrType") + "\n\n"+
                                                        task.getResult().get("NMC_ErrInfo") +
                                                        ((task.getResult().get("NMC_ErrDetail") !=
                                                          null) ?
                                                         "\n"+task.getResult().get("NMC_ErrDetail") :
                                                         ""));
                    }
                    
                    setDirty(false);
                }

            } catch (ValidationException ve) {
                throw ve;
            } catch (Exception e) {
                Debug.println("TurnOnSSL.applyChanges: ERROR - " + e.toString());
            }
        }
    }

    /**
     * Validates the user choices
     */
    private boolean validEntries() throws ValidationException {
	String error = null;
	boolean valid = true;

        // Count the problems
        int howManyEnabled = 0;
        int howManyNoDevice = 0;
        int howManyNoCertif = 0;
        
	if (securitySettings.get("security").equals("on")) {

            StringTokenizer st = new StringTokenizer( (String)securitySettings.get("familyList"), ",");
            if (st.countTokens() != 0) {
                while (st.hasMoreTokens()) {
                    try {
                        String cipherFamily = st.nextToken();
                        String val = (String)securitySettings.get(cipherFamily+"-activated");
                        if ( val != null && val.equals("on") ) {
                            howManyEnabled++;
                            val = (String)securitySettings.get(cipherFamily+"-token");
                            if (val == null || val.toString().length()==0) howManyNoDevice++;
                            val = (String)securitySettings.get(cipherFamily+"-cert");
                            if (val == null || val.toString().length()==0) howManyNoCertif++;
                        }

                    } catch(NoSuchElementException nsee) {
                        Debug.println("TurnOnSSL.validateEntries: Unable to read family cipher token");
                    }

                    
                }

            } else {
                Debug.println("TurnOnSSL.validateEntries: no family ciphers");
            }
            
	    // Select the error message according to the problem
	    if (howManyEnabled == 0) {
		valid = false;
		throw new ValidationException("", _i18nMsgNoSslFamily);
	    }
	    else if (howManyNoDevice >= 1) {
		valid = false;
		throw new ValidationException("", _i18nMsgNoSslPreferences);
	    }
	    else if (howManyNoCertif >= 1) {
		valid = false;
		throw new ValidationException("", _i18nMsgNoCertificate);
	    }
        
        } else {
	    Debug.println(6, "TurnOnSSL.validateEntries: SSL is off");
	}

        return valid;

    }

    public void showHelp() {
        Help help = new Help(_resource);
        help.contextHelp("TurnOnSSL", "help");
    }

}
