/**
 * This work was created by participants in the DataONE project, and is
 * jointly copyrighted by participating institutions in DataONE. For 
 * more information on DataONE, see our web site at http://dataone.org.
 *
 *   Copyright ${year}
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 * 
 * $Id$
 */

package org.dataone.cn.utility.versiontool;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import org.apache.commons.lang3.StringUtils;

public class WebAppVersionReporter {

    public static final String newline = System.getProperty("line.separator");

    private static final String MANIFEST_PATH = "/META-INF/MANIFEST.MF";
    private static final String LIB_DIR_PATH = "/WEB-INF/lib/";

    private String PROPERTIES_FILE_PATH = null;
    private static final String TOMCAT_PATH_KEY = "tomcat_path";
    private static final String WEBAPP_NAME_KEY = "web_app_name";

    // move tomcat path and web app names to property file
    private static String tomcat_webapp_path = null;
    private static ArrayList<String> webAppNames = new ArrayList<String>();

    public WebAppVersionReporter() {
    }

    public WebAppVersionReporter(String propertyFilePath) {
        if (propertyFilePath != null) {
            PROPERTIES_FILE_PATH = propertyFilePath;
        }
    }

    /**
     * This method uses file system to find and report web app component
     * information.
     * 
     */
    public Collection<ComponentVersionInfo> report(StringBuilder log) {

        Collection<ComponentVersionInfo> webCompInfoList = new ArrayList<ComponentVersionInfo>();
        if (setPropertiesFromFile(log)) {
            File webAppDir = new File(tomcat_webapp_path);
            if (webAppDir.exists()) {
                for (String webAppName : webAppNames) {
                    Manifest manifest = getWebAppManifest(webAppName, log);
                    if (manifest != null) {
                        ComponentVersionInfo webCompInfo = new ComponentVersionInfo(webAppName,
                                tomcat_webapp_path + webAppName, manifest);

                        File libDir = new File(tomcat_webapp_path + webAppName + LIB_DIR_PATH);
                        addComponentInfoFromLib(webCompInfo, libDir, log);

                        webCompInfoList.add(webCompInfo);
                    }
                }
            }
        }
        return webCompInfoList;
    }

    private void addComponentInfoFromLib(ComponentVersionInfo webCompInfo, File libDir,
            StringBuilder log) {
        // reports on all jars with name that starts with d1_
        File[] files = libDir.listFiles(new FileFilter() {
            public boolean accept(File file) {
                if (file.getName().startsWith("d1_")) {
                    return true;
                }
                return false;
            }
        });
        for (File f : files) {
            JarFile jarFile = null;
            String jarName = null;
            try {
                jarFile = new JarFile(f);
            } catch (IOException ioe) {
                log.append("Unable to open jar: " + f.getAbsolutePath() + newline);
                continue;
            }
            jarName = StringUtils.substringBefore(jarFile.getName(), "_java");
            jarName = StringUtils.substringAfterLast(jarName, "/");
            jarName = StringUtils.substringBefore(jarName, "-");
            Manifest manifest = null;
            try {
                manifest = jarFile.getManifest();
            } catch (IOException ioe) {
                log.append("Unable to open manifest for: " + f.getAbsolutePath() + newline);
            }
            ComponentVersionInfo jarDep = new ComponentVersionInfo(jarName, f.getAbsolutePath(),
                    manifest);
            if (StringUtils.isEmpty(jarDep.getVersion())) {
                // scraping version off jar name....
                String version = jarFile.getName();
                int index = StringUtils.lastIndexOf(version, "-");
                version = StringUtils.substring(version, index - 5, index + 9);
                jarDep.setVersion(version);
            }
            webCompInfo.addDependency(jarDep);
        }
        Collections.sort(webCompInfo.getDependencies(), new ComponentInfoNameAlphabetizer());
    }

    private Manifest getWebAppManifest(String webAppName, StringBuilder log) {
        Manifest manifest = null;
        try {
            InputStream manifestStream = new FileInputStream(tomcat_webapp_path + webAppName
                    + MANIFEST_PATH);
            manifest = new Manifest(manifestStream);
        } catch (FileNotFoundException fnfe) {
            log.append("Unable to locate manifest for web app: " + webAppName + newline);
        } catch (IOException IOE) {
            log.append("Unable to open manifest for web app: " + webAppName + newline);
        }
        return manifest;
    }

    public boolean setPropertiesFromFile(StringBuilder log) {

        boolean returnValue = true;

        if (PROPERTIES_FILE_PATH != null) {
            File file = new File(PROPERTIES_FILE_PATH);
            if (file.exists() && file.canRead()) {
                try {
                    BufferedReader in = new BufferedReader(new FileReader(file));
                    String line;
                    boolean resetAppList = false;
                    while ((line = in.readLine()) != null) {
                        String key = StringUtils.substringBefore(line, "=");
                        key = StringUtils.trim(key);
                        String value = StringUtils.substringAfter(line, "=");
                        value = StringUtils.trim(value);
                        if (TOMCAT_PATH_KEY.compareTo(key) == 0) {
                            tomcat_webapp_path = value;
                        } else if (WEBAPP_NAME_KEY.compareTo(key) == 0) {
                            if (resetAppList == false) {
                                webAppNames.clear();
                                resetAppList = true;
                            }
                            webAppNames.add(value);
                        }
                    }
                    in.close();
                } catch (FileNotFoundException fnfe) {
                    returnValue = false;
                    log.append("Unable to locate properties file.  "
                            + "Please add default property file or pass one in via command line."
                            + newline);
                } catch (IOException ioe) {
                    returnValue = false;
                    log.append("Unable to read properties file.  "
                            + "Please add default property file or pass one in via command line."
                            + newline);
                }
            } else {
                returnValue = false;
                log.append("Unable to locate properties file: "
                        + "Please add default property file or pass one in via command line."
                        + newline);
            }
        } else {
            returnValue = false;
            log.append("No property file provided.  "
                    + "Please add default property file or pass one in via command line." + newline);
        }
        return returnValue;
    }
}