 /*
  * Jopr Management Platform
  * Copyright (C) 2005-2008 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, version 2, as
  * published by the Free Software Foundation, and/or the GNU Lesser
  * General Public License, version 2.1, also as published by the Free
  * Software Foundation.
  *
  * 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 and the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU General Public License
  * and the GNU Lesser 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.
  */

package org.rhq.plugins.jbossas;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mc4j.ems.connection.bean.EmsBean;
import org.mc4j.ems.connection.bean.attribute.EmsAttribute;

import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.measurement.DataType;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementDataTrait;
import org.rhq.core.domain.measurement.MeasurementReport;
import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
import org.rhq.core.pluginapi.inventory.CreateChildResourceFacet;
import org.rhq.core.pluginapi.inventory.ResourceComponent;
import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.plugins.jbossas.util.DeploymentUtility;
import org.rhq.plugins.jbossas.util.XMLConfigurationEditor;
import org.rhq.plugins.jmx.MBeanResourceComponent;

/**
 * Common base class for Messaging related stuff
 * @author Heiko W. Rupp
 */
public abstract class AbstractMessagingComponent extends MBeanResourceComponent<JBossASServerComponent> implements
    CreateChildResourceFacet {

    private static final Pattern PROPERTY_PATTERN = Pattern.compile("^(.*:.*):(.*)$");

    protected static final String PLUGIN_CONFIG_NAME_PROP = "name";
    private static final String MBEAN_NAME_PROP = "MBeanName";

    XMLConfigurationEditor xmlEditor;
    ResourceType resourceType;
    protected String name;

    protected Log LOG =  LogFactory.getLog(AbstractMessagingComponent.class);;

    public void start(ResourceContext<JBossASServerComponent> resourceContext, XMLConfigurationEditor editor) {
        super.start(resourceContext);
        this.resourceType = resourceContext.getResourceType();
        xmlEditor = editor;
        this.name = resourceContext.getPluginConfiguration().getSimpleValue(PLUGIN_CONFIG_NAME_PROP, null);
    }

    protected void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> requests, String pattern) {

        Set<MeasurementScheduleRequest> others = new HashSet<MeasurementScheduleRequest>();
       try { 
        for (MeasurementScheduleRequest request : requests) {

            // Handle stuff for the generic Messaging MBeans ourselves. Pass the remainder
            // to our parent later.
            if (request.getName().startsWith(pattern)) {
                Matcher m = PROPERTY_PATTERN.matcher(request.getName());
                if (m.matches() && (m.group(1) != null)) {
                    EmsBean eBean = getEmsConnection().getBean(m.group(1));

                    List<String> attributes = new ArrayList<String>(1);
                    attributes.add(m.group(2));
                    eBean.refreshAttributes(attributes);
                    EmsAttribute emsAtt = eBean.getAttribute(m.group(2));
                    Object value = emsAtt.getValue();
                    if ((request.getDataType() == DataType.MEASUREMENT) && (value instanceof Number)) {
                        report.addData(new MeasurementDataNumeric(request, ((Number) value).doubleValue()));
                    } else if (request.getDataType() == DataType.TRAIT) {
                        String displayValue = null;
                        if ((value != null) && value.getClass().isArray()) {
                            displayValue = Arrays.deepToString((Object[]) value);
                        } else {
                            displayValue = String.valueOf(value);
                        }

                        report.addData(new MeasurementDataTrait(request, displayValue));
                    }
                }
            } else
                others.add(request);
        }

        super.getValues(report, others);
       }catch(Throwable e){
           LOG.error("Failed to obtain measurement [" + name + "]", e);
       }
    }

    @Override
    public Configuration loadResourceConfiguration() {

        String resourceKey = getResourceContext().getResourceKey();

        JBossASServerComponent jasco = getOurJBossASComponent();
        File deploymentFile = jasco.getDeploymentFilePath(resourceKey);
        Configuration loadedConfiguration = xmlEditor.loadConfiguration(deploymentFile, this.name);
        if (loadedConfiguration==null)
            return null;
        String boundJNDIName = DeploymentUtility.getJndiNameBinding(getEmsBean());
        loadedConfiguration.put(new PropertySimple("JNDIBinding", boundJNDIName));
        return loadedConfiguration;
    }

    private JBossASServerComponent getOurJBossASComponent() {

        ResourceComponent parent = getResourceContext().getParentResourceComponent();
        JBossASServerComponent jasco;
        if (parent instanceof JMSComponent) {
            jasco = ((JMSComponent) parent).getResourceContext().getParentResourceComponent();
        } else if (parent instanceof JBossMessagingComponent) {
            jasco = ((JBossMessagingComponent) parent).getResourceContext().getParentResourceComponent();
        } else if (parent instanceof JBossASServerComponent) {
            jasco = (JBossASServerComponent) parent;
        } else
            jasco = new JBossASServerComponent(); // TODO fix me
        return jasco;
    }

    @Override
    public void updateResourceConfiguration(ConfigurationUpdateReport report) {

        JBossASServerComponent jasco = getOurJBossASComponent();
        File deploymentFile = jasco.getDeploymentFilePath(getResourceContext().getResourceKey());

        // Check to see if the user is changing the name of this JMS Topic/Queue
        String mBeanName = report.getConfiguration().getSimpleValue(MBEAN_NAME_PROP, null);
        boolean mBeanNameChanged = false;
        if (!mBeanName.equals(this.name)) {
            LOG
                .info("The MBEan Name for this Topic/Queue has been changed. This change will appear in the <mbean> tag for"
                    + "this Topic/Queue.");

            // User has changed the name, so update the plugin configuration.
            PropertySimple nameProp = getResourceContext().getPluginConfiguration().getSimple(PLUGIN_CONFIG_NAME_PROP);
            nameProp.setStringValue(mBeanName);
            mBeanNameChanged = true;
        }

        if ((deploymentFile == null) || !deploymentFile.exists()) {
            deploymentFile = new File(jasco.getConfigurationPath(), name
                + ".xml");
        }

        xmlEditor.updateConfiguration(deploymentFile, this.name, report);
        if (mBeanNameChanged) {
            this.name = mBeanName;
        }
    }

    public void deleteResource() throws Exception {
        String resourceKey = getResourceContext().getResourceKey();
        JBossASServerComponent parent = getOurJBossASComponent();
        File deploymentFile = parent.getDeploymentFilePath(resourceKey);
        assert deploymentFile.exists() : "Deployment file " + deploymentFile + " doesn't exist for resource "
            + resourceKey;
        xmlEditor.deleteComponent(deploymentFile, this.name);
        parent.redeployFile(deploymentFile);
    }

    /**
     * Returns the canonical version of the passed ObjectName
     * @param objectName a valid {@link ObjectName}
     * @return an {@link ObjectName} in its canonical form
     * @throws MalformedObjectNameException if the passed {@link ObjectName} is invalid
     */
    public String getCanonicalName(String objectName) throws MalformedObjectNameException {
        ObjectName on = new ObjectName(objectName);
        return on.getCanonicalName();
    }

}
