/*
 * RHQ 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.platform.win;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.sigar.win32.RegistryKey;
import org.hyperic.sigar.win32.Win32Exception;

import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.content.PackageDetailsKey;
import org.rhq.core.domain.content.PackageType;
import org.rhq.core.domain.content.transfer.ResourcePackageDetails;

/**
 * Provides for discovery of Windows Installed Software. Uses the uninstall registry that's
 * used by Add/Remove Programs. Only supports discovery, not installation.
 *
 * @author Greg Hinkle
 */
public class WindowsSoftwareDelegate {

    private final Log log = LogFactory.getLog(WindowsSoftwareDelegate.class);

    public Set<ResourcePackageDetails> discoverInstalledSoftware(PackageType type) {
        Set<ResourcePackageDetails> installedSoftware = new HashSet<ResourcePackageDetails>();
        try {
            String uninstallList = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
            RegistryKey key = RegistryKey.LocalMachine;
            RegistryKey uninstall = key.openSubKey(uninstallList);
            String[] packages = uninstall.getSubKeyNames();

            for (String packageName : packages) {

                RegistryKey packageKey = uninstall.openSubKey(packageName);

                String installDateString = getStringValue(packageKey, "InstallDate");
                String displayName = getStringValue(packageKey, "DisplayName");
                String version = getStringValue(packageKey, "DisplayVersion");

                if (displayName != null && installDateString != null && version != null) {
                    if (version.length() == 0) {
                        version = "1";
                    }
                    try {
                        ResourcePackageDetails details = new ResourcePackageDetails(new PackageDetailsKey(displayName,
                            version, type.getName(), "noarch"));
                        details.setFileCreatedDate(getDate(installDateString));
                        details.setInstallationTimestamp(getDate(installDateString));
                        details.setFileSize((long) packageKey.getIntValue("EstimatedSize", 0));
                        details.setDeploymentTimeConfiguration(getConfigurations(packageKey));
                        installedSoftware.add(details);
                    } catch (IllegalArgumentException e) {
                        if (log.isDebugEnabled()) {
                            log.debug("Skipping windows package discovery for illegal entry [name=" + displayName
                                + ",version=" + version + ",installDate=" + installDateString + "]", e);
                        }
                    }
                }
            }
        } catch (Win32Exception e) {
            log.warn("Failed in discovery of installed Windows software.", e);
        }
        return installedSoftware;
    }

    private Configuration getConfigurations(RegistryKey packageKey) {
        Configuration config = new Configuration();
        String[] properties = { "Publisher", "Comments", "Contact", "HelpLink", "HelpTelephone", "InstallLocation",
            "InstallSource" };
        for (String key : properties) {
            config.put(new PropertySimple(key, getStringValue(packageKey, key)));
        }

        config.put(new PropertySimple("EstimatedSize", packageKey.getIntValue("EstimatedSize", 0)));

        return config;
    }

    private static Long getDate(String dateString) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

        Date date = null;

        try {
            date = sdf.parse(dateString);
        } catch (ParseException e) {

            DateFormat df = DateFormat.getDateTimeInstance();
            try {
                date = df.parse(dateString);
            } catch (ParseException e1) {
                /* Poorly formatted dates are ignored */
            }
        }

        return (date == null ? null : date.getTime());
    }

    /**
     * String values are returned with their null terminator in the string... clear them out
     */
    private static String getStringValue(RegistryKey key, String name) {
        String value = key.getStringValue(name, null);
        if (value != null) {
            value = value.trim();
        }
        return value;
    }
}
