/*
 * RHQ Management Platform
 * Copyright (C) 2005-2014 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
 */

package org.rhq.modules.plugins.wildfly10;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;

/**
 * Discover domain deployments. This is analogous to {@link VersionedSubsystemDiscovery} but addresses only
 * domain deployments. See {@link VersionedSubsystemDiscovery} for more on controlling/overriding the version handling.
 *
 * @author Jay Shaughnessy
 */
public class VersionedDomainDeploymentDiscovery extends AbstractVersionedDomainDeploymentDiscovery {

    private static final Log LOG = LogFactory.getLog(VersionedDomainDeploymentDiscovery.class);

    private static final Pattern COMMA_PATTERN = Pattern.compile(",");

    @Override
    public Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext<BaseComponent<?>> context)
        throws Exception {

        // Perform the standard discovery. This can return deployments with versions in the name,
        // key and path.
        Set<DiscoveredResourceDetails> details = super.discoverResources(context);

        if (DISABLED || null == details || details.isEmpty()) {
            return details;
        }

        // Now, post-process the discovery as needed.  We need to strip the versions from the
        // resource name and the resource key.  We want to leave them in the path plugin config
        // property, that value reflects the actual DMR used to query EAP.
        // The stripped versions are then used to set the resource version string.

        // Work with a list because we may update the key, which is used in the DiscoveredResourceDetails.equals()
        ArrayList<DiscoveredResourceDetails> updatedDetails = new ArrayList<DiscoveredResourceDetails>(details);
        HashMap<String, Integer> keyCount = new HashMap<String, Integer>(updatedDetails.size());
        details.clear();

        // domain deployments are not actually deployed, they are basically just staged for deployment, so
        // they are fairly simple, they don't have subdeployments, etc...
        for (DiscoveredResourceDetails detail : updatedDetails) {
            MATCHER.reset(detail.getResourceName());
            if (MATCHER.matches()) {
                // reset the resource name with the stripped value
                detail.setResourceName(MATCHER.group(1) + MATCHER.group(3));
                detail.setResourceVersion(MATCHER.group(2));
            }

            StringBuilder sb = new StringBuilder();
            String comma = "";
            for (String segment : COMMA_PATTERN.split(detail.getResourceKey())) {
                sb.append(comma);
                comma = ",";
                MATCHER.reset(segment);
                if (MATCHER.matches()) {
                    sb.append(MATCHER.group(1)).append(MATCHER.group(3));
                } else {
                    sb.append(segment);
                }
            }
            detail.setResourceKey(sb.toString());
            Integer count = keyCount.get(detail.getResourceKey());
            keyCount.put(detail.getResourceKey(), (null == count ? 1 : ++count));
        }

        // Now, make sure that after we've stripped the versions that we don't end up with multiple discoveries
        // for the same key, this is an indication that there are multiple versions of the same Deployment deployed.
        // In this case we remove the duplicates and issue a warning so the user can hopefully rectify the situation.
        for (Map.Entry<String, Integer> entry : keyCount.entrySet()) {
            if (entry.getValue() > 1) {
                LOG.warn("Discovered multiple resources with resource key [" + entry.getKey()
                    + "].  This is not allowed and they will be removed from discovery.  This is typically caused by "
                    + "having multiple versions of the same Deployment deployed.  To solve the problem either remove "
                    + "all but one version of the problem deployment or disable versioned deployment handling by "
                    + "setting -Drhq.as7.VersionedSubsystemDiscovery.pattern=disable for the agent.");
                for (Iterator<DiscoveredResourceDetails> i = updatedDetails.iterator(); i.hasNext();) {
                    DiscoveredResourceDetails detail = i.next();
                    if (detail.getResourceKey().equals(entry.getKey())) {
                        i.remove();
                    }
                }
            }
        }

        details.addAll(updatedDetails);
        return details;
    }
}
