/*
 * The contents of this file are subject to the terms 
 * of the Common Development and Distribution License 
 * (the License).  You may not use this file except in
 * compliance with the License.
 * 
 * You can obtain a copy of the license at 
 * https://glassfish.dev.java.net/public/CDDLv1.0.html or
 * glassfish/bootstrap/legal/CDDLv1.0.txt.
 * See the License for the specific language governing 
 * permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL 
 * Header Notice in each file and include the License file 
 * at glassfish/bootstrap/legal/CDDLv1.0.txt.  
 * If applicable, add the following below the CDDL Header, 
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information: 
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 */

package com.sun.enterprise.tools.admingui.handlers;

import java.util.List;
import java.util.EventObject;
import java.util.Properties;
import java.util.Enumeration;

import com.iplanet.jato.RequestContext;
import com.iplanet.jato.RequestManager;
import com.iplanet.jato.view.View;
import com.iplanet.jato.view.ViewBase;
import com.iplanet.jato.view.ViewBean;
import com.iplanet.jato.model.DefaultModel;
import com.iplanet.jato.model.ModelControlException;
import com.sun.enterprise.tools.admingui.util.Util;

import com.sun.web.ui.model.CCActionTableModel;
import javax.management.AttributeList;
import javax.management.Attribute;

import com.sun.enterprise.tools.guiframework.exception.FrameworkException;
import com.sun.enterprise.tools.guiframework.view.DescriptorContainerView;
import com.sun.enterprise.tools.guiframework.view.HandlerContext;
import com.sun.enterprise.tools.guiframework.view.descriptors.ViewDescriptor;
import com.sun.enterprise.tools.guiframework.view.descriptors.CCActionTableDescriptor;
import com.sun.enterprise.tools.guiframework.view.event.BeforeCreateEvent;

import com.sun.web.ui.model.CCActionTableModelInterface;

import com.sun.enterprise.tools.admingui.util.MBeanUtil;
import com.sun.enterprise.tools.admingui.util.Util;


public class PropertiesHandlers {

    public static final String	PROPERTY_NAME	= "propertyName";
    public static final String	PROPERTY_VALUE 	= "propertyValue";
    public static final String	PROPERTY_WEIGHT 	= "weight";
    public static final String	PROPERTY_DEFAULT_VALUE 	= "defaultValue";
    public static final String	PROPERTY_ORIGINAL_OVERRIDE_VALUE = "originalOverrideValue";

    private CCActionTableModelInterface getModel(HandlerContext handlerCtx) {
        CCActionTableModelInterface model =
            (CCActionTableModelInterface)handlerCtx.getInputValue("propertiesModel");
        //model.setRowSelectionType("multiple");

        if (model == null) {
            throw new FrameworkException("PropertiesHandler.getModel: Parameter 'propertiesModel' not specified");
        }
        return model;
    }

    private void loadModel(CCActionTableModelInterface model, AttributeList attrs, Object excludes) 
        throws ModelControlException {
	RequestContext ctx = RequestManager.getRequestContext();
        if (attrs == null) 
            return;
	// Log some info...
	StringBuffer buf = new StringBuffer();
	if (Util.isLoggableFINER()) {
            for(int rowNo = 0; rowNo < attrs.size(); rowNo++) {
                Attribute attr = (Attribute)attrs.get(rowNo);
                buf.append("properties table : name = " + attr.getName() + " , value = " + attr.getValue()+"\n");
            }
	    Util.logFINER(buf.toString());
	}
        model.beforeFirst();
        for (int rowNo = 0; rowNo < attrs.size(); rowNo++) {
            
            Attribute attr = (Attribute)attrs.get(rowNo);
            if (! shouldExclude(attr.getName(), excludes)){
                model.appendRow();
                model.setValue(PROPERTY_NAME, attr.getName());
                model.setValue(PROPERTY_VALUE, attr.getValue());
                model.setRowSelected(false);
            }
        }
    }

    private void loadModel(CCActionTableModelInterface model, Properties props, Object excludes) 
        throws ModelControlException {
        if (props == null) 
            return;
        //System.out.println("loading model, props = " + props);
        ((DefaultModel)model).clear();
        model.beforeFirst();
        Enumeration ee = props.propertyNames();
        while (ee.hasMoreElements()) {
            String name = (String)ee.nextElement();
            if (!shouldExclude(name, excludes)){
                model.appendRow();
                model.setValue(PROPERTY_NAME, name);
                model.setValue(PROPERTY_VALUE, props.getProperty(name));
                model.setRowSelected(false);
                if (Util.isLoggableFINER()) {
                    Util.logFINER("properties table : " + 
                        name + ":" + props.getProperty(name));
                }
            }
        }
    }
    
    private boolean shouldExclude(String name, Object excludes){
        List list = (List) excludes;
        if(list == null || list.isEmpty())
            return false;
        for(int i=0; i< list.size(); i++){
            if (list.get(i).equals(name)){
                return true;
            }
        }
        return false;
    }
    
    private void loadModel(CCActionTableModelInterface model, 
                Properties configProps, Properties targetProps, 
                boolean instPropsOnly) 
        throws ModelControlException {
        if (configProps == null) 
            return;
        model.beforeFirst();
        Enumeration ee = configProps.propertyNames();
        if (instPropsOnly == false) {
            while (ee.hasMoreElements()) {
                String name = (String)ee.nextElement();
                model.appendRow();
                model.setValue(PROPERTY_NAME, name);
                model.setValue(PROPERTY_DEFAULT_VALUE, configProps.getProperty(name));
                if (targetProps != null) {
                    model.setValue(PROPERTY_VALUE, targetProps.getProperty(name, ""));
                    model.setValue(PROPERTY_ORIGINAL_OVERRIDE_VALUE, targetProps.getProperty(name, ""));
                } else {
                    model.setValue(PROPERTY_VALUE, "");
                    model.setValue(PROPERTY_ORIGINAL_OVERRIDE_VALUE, "");
                }
                model.setRowSelected(false);
                if (Util.isLoggableFINER()) {
                    String msg = "properties table : " + name + ":" 
                        + configProps.getProperty(name);
                    if (targetProps != null)
                        msg += ":" + targetProps.getProperty(name, "");
                    //System.out.println("::: "+msg);
                    Util.logFINER( msg);
                }
            }
        } else {
        // add any props that are just on the target and not on the config
            ee = targetProps.propertyNames();
            while (ee.hasMoreElements()) {
                String name = (String)ee.nextElement();
                String value = configProps.getProperty(name, null);
                if (value == null) {
                    model.appendRow();
                    model.setValue(PROPERTY_NAME, name);
                    model.setValue(PROPERTY_VALUE, targetProps.getProperty(name, ""));
                    model.setValue(PROPERTY_ORIGINAL_OVERRIDE_VALUE, targetProps.getProperty(name, ""));
                 }
            }
        }
    }
    
    
    public void loadProperties(RequestContext ctx, HandlerContext handlerCtx) {
        try {
            CCActionTableModelInterface model = getModel(handlerCtx);
            ((DefaultModel)model).clear();
            Object obj = handlerCtx.getInputValue("properties");
            Object excludes = handlerCtx.getInputValue("excludes");
            if (obj instanceof AttributeList) {
                loadModel(model, (AttributeList)obj, excludes);
            }
            else {
                loadModel(model, (Properties)obj, excludes);
            }
        } catch (Exception ex) {
            throw new FrameworkException("loadProperties: Loading error. ", ex);
        }
    }
    
    public void loadSystemProperties(RequestContext ctx, HandlerContext handlerCtx) {
        try {
            CCActionTableModelInterface model = getModel(handlerCtx);
            String objectName = (String)handlerCtx.getInputValue("objectName");
            String methodName = (String)handlerCtx.getInputValue("methodName");
            String configName = (String)handlerCtx.getInputValue("configName");
            String targetName = (String)handlerCtx.getInputValue("targetName");
            Boolean inherit = (Boolean)handlerCtx.getInputValue("inherit");
            Boolean instPropsOnly = (Boolean)handlerCtx.getInputValue("instPropsOnly");
            if (objectName == null || methodName == null || configName == null) {
                throw new FrameworkException("Missing input parameter to loadSystemProperties()");
            }
            
            String[] types = new String[]{"java.lang.String", "boolean"};
            Object[] params = new Object[]{configName, inherit};
            Properties configProps = (Properties)
                MBeanUtil.invoke(objectName, methodName, params, types);
            
            Properties targetProps = null;
            if (targetName != null) {
                params = new Object[]{targetName, inherit};
                targetProps = (Properties)
                    MBeanUtil.invoke(objectName, methodName, params, types);
            }
            loadModel(model, configProps, targetProps, instPropsOnly.booleanValue());
        } catch (Exception ex) {
            throw new FrameworkException("loadSystemProperties: Loading error. ", ex);
        }
    }
    
    public void saveProperties(RequestContext ctx, HandlerContext handlerCtx) throws ModelControlException {
        Object objectName = handlerCtx.getInputValue("objectName");
	if (objectName == null) {
	    throw new FrameworkException(
                "objectName not specified in saveProperties.");
	}
        
        String setMethodName = (String)handlerCtx.getInputValue("setMethodName");
	if (setMethodName == null) {
            setMethodName="setProperty";
	}

        CCActionTableModelInterface model = getModel(handlerCtx);
        //model.setRowSelectionType("multiple");
        model.beforeFirst();

        /* get the current properties, delete those and set new ones */
        AttributeList originalProperties = (AttributeList)handlerCtx.getInputValue("originalProperties");
        AttributeList attrs = new AttributeList();
        while(model.next()) {
            String name = (String) model.getValue(PROPERTY_NAME);
            String value = (String) model.getValue(PROPERTY_VALUE);
            if (!Util.isEmpty(name) && !Util.isEmpty(value)) {
                attrs.add(new Attribute(name, value));
            }
        }

        String[] type = new String[]{"javax.management.Attribute"};

        if (originalProperties != null) {
            for (int i = 0; i < originalProperties.size(); i++) {
                Attribute originalProperty = (Attribute)originalProperties.get(i);
                boolean found = false;
                for (int j = 0; j < attrs.size(); j++) {
                    Attribute attr = (Attribute)(attrs.get(j));
                    if (attr.getName().equals(originalProperty.getName())) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    Attribute propertyToClear = new Attribute(originalProperty.getName(), null);
                    Object[] params = new Object[]{propertyToClear};
                    MBeanUtil.invoke(objectName.toString(), setMethodName, params, type);
                }
            }
        }
        for (int i = 0; i < attrs.size(); i++) {
            Attribute attr = (Attribute)attrs.get(i);
            Object[] params = new Object[]{attr};
            MBeanUtil.invoke(objectName.toString(), setMethodName, params, type);
        }
    }

    
    public void saveSystemProperties(RequestContext ctx, HandlerContext handlerCtx) throws ModelControlException {
        Object objectName = handlerCtx.getInputValue("objectName");
	if (objectName == null) {
	    throw new FrameworkException(
                "objectName not specified in saveSystemProperties.");
	}
        String target = (String)handlerCtx.getInputValue("target");
	if (target == null) {
	    throw new FrameworkException(
                "target not specified in saveSystemProperties.");
	}
        String createMethodName = (String)handlerCtx.getInputValue("createMethodName");
        if (createMethodName == null)
            createMethodName = "createSystemProperties";
        String deleteMethodName = (String)handlerCtx.getInputValue("deleteMethodName");
        if (deleteMethodName == null)
            deleteMethodName = "deleteSystemProperty";

        CCActionTableModelInterface model = getModel(handlerCtx);
        //model.setRowSelectionType("multiple");
        model.beforeFirst();

        Properties originalProperties = (Properties)handlerCtx.getInputValue("originalProperties");
        Properties propertiesToCreate  = new Properties();
        while(model.next()) {
            String name = (String) model.getValue(PROPERTY_NAME);
            if (name != null && (!name.trim().equals(""))) {
                //if (originalProperties.getProperty(name) == null) {
                    String value = (String) model.getValue(PROPERTY_VALUE);
                    propertiesToCreate.setProperty(name, value);
                //}
            }
        }
        String[] types = null;
        if (originalProperties != null) {
            Enumeration deleteProps = originalProperties.propertyNames();
            types = new String[]{"java.lang.String", "java.lang.String"};
            while(deleteProps.hasMoreElements()) {
                String name = (String)deleteProps.nextElement();
                Object[] params = new Object[]{name, target};
                MBeanUtil.invoke(objectName.toString(), deleteMethodName, params, types);
            }
        }
        types = new String[]{"java.util.Properties", "java.lang.String"};
        Object[] params = new Object[]{propertiesToCreate, target};
        MBeanUtil.invoke(objectName.toString(), createMethodName, params, types);
    }
    
    public void deleteInstOnlyProps(RequestContext ctx, HandlerContext handlerCtx) throws ModelControlException {
        String deleteMethodName = (String)handlerCtx.getInputValue("deleteMethodName");
        if (deleteMethodName == null)
            deleteMethodName = "deleteSystemProperty";

        String objectName = (String)handlerCtx.getInputValue("objectName");
        String methodName = (String)handlerCtx.getInputValue("methodName");
        String configName = (String)handlerCtx.getInputValue("configName");
        String targetName = (String)handlerCtx.getInputValue("targetName");
        Boolean inherit = (Boolean)handlerCtx.getInputValue("inherit");
        if (objectName == null || methodName == null || configName == null || targetName == null) {
            throw new FrameworkException("Missing input parameter to deleteInstOnlyProps()");
        }

        String[] types = new String[]{"java.lang.String", "boolean"};
        Object[] params = new Object[]{configName, inherit};
        Properties configProps = (Properties)
            MBeanUtil.invoke(objectName, methodName, params, types);

        Properties targetProps = null;
        params = new Object[]{targetName, inherit};
        targetProps = (Properties)
            MBeanUtil.invoke(objectName, methodName, params, types);
            
        types = new String[]{"java.lang.String", "java.lang.String"};
        Enumeration ee = targetProps.propertyNames();
        while (ee.hasMoreElements()) {
            String name = (String)ee.nextElement();
            String value = configProps.getProperty(name, null);
            if (value == null) {
                params = new Object[]{name, targetName};
                MBeanUtil.invoke(objectName, deleteMethodName, params, types);
             }
        }
    }
 

    public void saveSystemPropertiesValues(RequestContext ctx, HandlerContext handlerCtx) throws ModelControlException {
        Object objectName = handlerCtx.getInputValue("objectName");
        //System.out.println("saveSystemPropertiesValues: "+objectName);
	if (objectName == null) {
	    throw new FrameworkException(
                "objectName not specified in saveSystemProperties.");
	}
        String target = (String)handlerCtx.getInputValue("target");
	if (target == null) {
	    throw new FrameworkException(
                "target not specified in saveSystemProperties.");
	}
        String createMethodName = (String)handlerCtx.getInputValue("createMethodName");
        if (createMethodName == null)
            createMethodName = "createSystemProperties";
        String deleteMethodName = (String)handlerCtx.getInputValue("deleteMethodName");
        if (deleteMethodName == null)
            deleteMethodName = "deleteSystemProperty";

        CCActionTableModelInterface model = getModel(handlerCtx);
        //model.setRowSelectionType("multiple");
        model.beforeFirst();
        String[] deleteTypes = new String[]{"java.lang.String", "java.lang.String"};

        Properties propertiesToCreate  = new Properties();
        while(model.next()) {
            String name = (String) model.getValue(PROPERTY_NAME);
            String originalValue = (String) model.getValue(PROPERTY_ORIGINAL_OVERRIDE_VALUE);
            String newValue = (String) model.getValue(PROPERTY_VALUE);
            //System.out.println("name: "+name+" oValue: "+originalValue+" newValue: "+newValue);
            if (name == null || (name.trim().length() == 0))
                continue;
            if (originalValue.trim().equals(newValue.trim())) {
                //System.out.println("same values -- continue");
                continue;
            }
            if (originalValue.trim().length() != 0 && newValue.trim().length() == 0) {
                // delete the prop.
                Object[] params = new Object[]{name, target};
                //System.out.println("deleting: "+name+" on target: "+target);
                try {
                    MBeanUtil.invoke(objectName.toString(), deleteMethodName, params, deleteTypes);
                } catch (Exception ex) {
                    System.out.println("error while trying to delete a system property!!");
                }
                //System.out.println("deleted");
            }
            if (newValue.trim().length() != 0) {
                // set a new value or replace existing value
                propertiesToCreate.setProperty(name, newValue);
                //System.out.println("create new: "+name+" value: "+newValue);
            }
        }
        if (propertiesToCreate.size() > 0) {
            String[] types = new String[]{"java.util.Properties", "java.lang.String"};
            Object[] params = new Object[]{propertiesToCreate, target};
            try {
                MBeanUtil.invoke(objectName.toString(), createMethodName, params, types);
            } catch (Exception ex) {
                //System.out.println("Error while creating sys props!!");
            }
        }
        //System.out.println("DONE!!");
    }
    
    public void deleteProperties(RequestContext ctx, HandlerContext handlerCtx) throws ModelControlException {
        CCActionTableModelInterface model = getModel(handlerCtx);
        AttributeList attrs = new AttributeList();
        model.setRowSelectionType("multiple");
        model.beforeFirst();
        while(model.next()) {
            if (!model.isRowSelected()) {
                String name = (String) model.getValue(PROPERTY_NAME);
                String value = (String)model.getValue(PROPERTY_VALUE);
                attrs.add(new Attribute(name, value));
            }
        }
        ((DefaultModel)model).clear();
        model.beforeFirst();
        for (int i = 0; i < attrs.size(); i++) {
            model.appendRow();
            Attribute attr = (Attribute)attrs.get(i);
            model.setValue(PROPERTY_NAME, attr.getName());
            model.setValue(PROPERTY_VALUE, attr.getValue());
            model.setRowSelected(false);
        }
    }

    public void clearProperties(RequestContext ctx, HandlerContext handlerCtx) throws ModelControlException {
        CCActionTableModelInterface model = getModel(handlerCtx);
        ((DefaultModel)model).clear();
        model.beforeFirst();
    }

    public void addProperty(RequestContext ctx, HandlerContext handlerCtx) throws ModelControlException {
        CCActionTableModelInterface model = getModel(handlerCtx);
        model.setRowSelectionType("multiple");
        model.appendRow();
        model.setValue(PROPERTY_VALUE, "");
        model.setValue(PROPERTY_NAME, "");
        model.sort();
        model.beforeFirst();
    }

    // returns Properties Object for table model
    public void getPropertiesObjectFromTable(RequestContext ctx, HandlerContext handlerCtx) throws ModelControlException {
	Boolean ignoreEmptyValues = (Boolean)handlerCtx.getInputValue("ignoreEmptyValues");
        String propValue = (String)handlerCtx.getInputValue("propValue");   
        CCActionTableModelInterface model = getModel(handlerCtx);
        //model.setRowSelectionType("multiple");
        ((DefaultModel)model).dumpValues(System.out);
        model.beforeFirst();
        CCActionTableModel cct = (CCActionTableModel) model;
        Properties properties = new Properties();
        while (model.next()) {
            String name = (String) model.getValue(PROPERTY_NAME);
            String value;
            if(propValue != null) {
                value = (String) model.getValue(propValue);
            } else {
                value = (String) model.getValue(PROPERTY_VALUE);
            }
            if (!Util.isEmpty(name)) {
                if (Util.isEmpty(value)) {
                    if (ignoreEmptyValues!=null && ignoreEmptyValues.booleanValue()==true)
                        continue;
                }
                properties.setProperty(name, value);
            }
        }
        handlerCtx.setOutputValue("properties", properties);
    }
    
    
    public void sortModel(RequestContext ctx, HandlerContext handlerCtx) throws ModelControlException {
        CCActionTableModelInterface model = getModel(handlerCtx);
        if (model != null) {
            model.sort();
        }
    }
    
    public void addTableRow(RequestContext ctx, HandlerContext handlerCtx) throws ModelControlException {
        CCActionTableModelInterface model =
            (CCActionTableModelInterface)handlerCtx.getInputValue("model");
        model.setRowSelectionType("multiple");
        model.appendRow();
        model.beforeFirst();
    }
}
