/**
 * 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.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;

import org.apache.commons.lang3.StringUtils;

public class ComponentVersionReportTool {

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

    public static void main(String[] args) {

        String propertyFilePath = null;
        boolean outputHtml = false;
        boolean showHelp = false;
        for (String arg : args) {
            if (StringUtils.startsWith(arg, "-F")) {
                propertyFilePath = StringUtils.substringAfter(arg, "-F");
            } else if (StringUtils.startsWith(arg, "-html")) {
                outputHtml = true;
            } else if (StringUtils.startsWith(arg, "-help")) {
                showHelp = true;
            }
        }

        if (propertyFilePath == null || showHelp) {
            showHelp();
            return;
        }

        StringBuilder log = new StringBuilder();
        StringBuilder output = new StringBuilder();

        WebAppVersionReporter webAppUtil = new WebAppVersionReporter(propertyFilePath);
        Collection<ComponentVersionInfo> warReports = webAppUtil.report(log);

        JarAppVersionReporter jarAppUtil = new JarAppVersionReporter(propertyFilePath);
        Collection<ComponentVersionInfo> jarReports = jarAppUtil.report(log);

        if (outputHtml) {
            getHtmlOutput(output, warReports, jarReports, log);
            System.out.print(output.toString());
        } else {
            System.out.print(log);
            getTextOutput(output, warReports);
            System.out.print(output.toString());
        }
    }

    public static void showHelp() {
        System.out.println("DataONE CN stack version tool help:");
        System.out.println(" ");
        System.out.println("This tool generates version reports on the local dataONE CN stack.");
        System.out.println("   This tool uses a properties file to find components to report on.");
        System.out
                .println("   This property file must be specified at run time.  A default version");
        System.out.println("   should be distributed with this tool: version-tool.properties.");
        System.out.println(" ");
        System.out
                .println("-F     Specifies the file path to the properites file to use to discover");
        System.out.println("       CN components. For example, if the properties file is in the");
        System.out.println("       same directory:");
        System.out.println("             -F./version-tool.properties");
        System.out.println(" ");
        System.out.println("-html  The default report output is plain text.  To generate an html");
        System.out.println("       document use this option.");
        System.out.println(" ");
        System.out.println("-help  To see this help text.");
        System.out.println(" ");
        System.out.println("Example of complete command:");
        System.out
                .println("   ./dataone-cn-version-tool.sh -F./version-tool.properties -html > version.html");
        System.out
                .println("This will output the html document to a file called version.html using a ");
        System.out.println("property file called version-tool.properties in the same directory.");
    }

    public static void getTextOutput(StringBuilder output,
            Collection<ComponentVersionInfo> warReports) {

        if (warReports.size() > 0) {
            output.append("CN web application component versions:" + newline);
            for (ComponentVersionInfo warCompInfo : warReports) {
                getComponentTextOutput(output, warCompInfo);
                output.append(newline);
                for (ComponentVersionInfo depVersionInfo : warCompInfo.getDependencies()) {
                    getComponentTextOutput(output, depVersionInfo);
                    output.append(newline);
                }
                output.append(newline);
            }
        } else {
            output.append("No CN web application components found." + newline);
        }
    }

    private static void getComponentTextOutput(StringBuilder output,
            ComponentVersionInfo componentVersionInfo) {
        if (componentVersionInfo.isDependent()) {
            output.append("       ");
        } else {
            output.append("Component: ");
        }
        output.append(componentVersionInfo.getName());
        if (StringUtils.isNotEmpty(componentVersionInfo.getPath())) {
            output.append(" PATH: " + componentVersionInfo.getPath());
        }
        if (StringUtils.isNotEmpty(componentVersionInfo.getVersion())) {
            output.append(" VERSION: " + componentVersionInfo.getVersion());
        }
        if (StringUtils.isNotEmpty(componentVersionInfo.getBranch())) {
            output.append(" BRANCH: " + componentVersionInfo.getBranch());
        }
        if (StringUtils.isNotEmpty(componentVersionInfo.getRevision())) {
            output.append(" REVISION: " + componentVersionInfo.getRevision());
        }
        if (StringUtils.isNotEmpty(componentVersionInfo.getBuildTimeString())) {
            output.append(" BUILT AT: " + componentVersionInfo.getBuildTimeString());
        }
    }

    private static void getHtmlOutput(StringBuilder output,
            Collection<ComponentVersionInfo> warReports,
            Collection<ComponentVersionInfo> jarReports, StringBuilder log) {

        getHtmlHeaderOutput(output, log);
        if (!warReports.isEmpty()) {
            getAppTableHtmlHeaderOutput(output, "web");
            for (ComponentVersionInfo cvi : warReports) {
                getHtmlAppTableRow(output, cvi);
                for (ComponentVersionInfo depInfo : cvi.getDependencies()) {
                    getHtmlAppTableRow(output, depInfo);
                }
            }
            output.append("</table>");
        }

        if (!jarReports.isEmpty()) {
            getAppTableHtmlHeaderOutput(output, "java");
            for (ComponentVersionInfo cvi : jarReports) {
                getHtmlAppTableRow(output, cvi);
                for (ComponentVersionInfo depInfo : cvi.getDependencies()) {
                    getHtmlAppTableRow(output, depInfo);
                }
            }
            output.append("</table>");
        }
        output.append("</body></html>");
    }

    private static void getHtmlHeaderOutput(StringBuilder output, StringBuilder log) {
        DateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm");
        output.append("<!doctype html><html><head>");

        output.append("<style type=\"text/css\">");
        output.append("body { background-color:WhiteSmoke; }");
        output.append("table { border-collapse:collapse; border:1px solid black }");
        output.append("tr.component {background-color:YellowGreen}");
        output.append("tr.dependency {background-color:white}");
        output.append("tr.spacer {background-color:LightGray}");
        output.append("th { padding:10px }");
        output.append("td { padding-left:10px; padding-right:10px; "
                + "padding-top:10px; border-top: 1px solid black; }");
        output.append("</style>");

        output.append("<title>DataONE Coordinating Components</title>");
        output.append("</head><body>");
        output.append("<p>Version report created at "
                + format.format(new Date(System.currentTimeMillis())) + ".</p>");
        output.append("<p>" + log.toString() + "</p>");

    }

    private static void getAppTableHtmlHeaderOutput(StringBuilder output, String appType) {
        output.append("<p>DataONE CN Node " + appType + " applications: </p></br>");
        output.append("<table><tr><th>App Name</th><th>Dep Name/Path</th><th>Version</th><th>Build Time</th><th>Source Branch</th><th>Revision</th></tr>");
    }

    private static void getHtmlAppTableRow(StringBuilder output, ComponentVersionInfo cvi) {
        if (cvi.isMainComponent()) {
            output.append("<tr class='component'>");
            output.append("<td>" + cvi.getName() + "</td>");
            output.append("<td width=\"300px\" style=\"word-wrap:break-word;\"><div style=\"width:280px;overflow:auto\">"
                    + cvi.getPath() + "</div></td>");
        } else {
            output.append("<tr class='dependency'>");
            output.append("<td></td><td>" + cvi.getName() + "</td>");
        }
        output.append("<td>" + cvi.getVersion() + "</td>");
        output.append("<td>" + cvi.getBuildTimeString() + "</td>");
        output.append("<td>" + cvi.getBranch() + "</td>");
        output.append("<td>" + cvi.getRevision() + "</td></tr>");
        if (cvi.isDependent()) {
            if (!"".equals(cvi.getPath())) {
                output.append("<tr class='dependency'><td></td><td colspan='5'>" + cvi.getPath()
                        + "</td></tr>");
            }
            output.append("<tr class='spacer'><td colspan='6'>&nbsp;</td></tr>");
        }
    }
}