/* Copyright (C) 2005-2011 Fabio Riccardi */

package com.lightcrafts.utils;

import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.MalformedURLException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.ResourceBundle;
import java.util.Map;
import java.util.HashMap;
import java.util.regex.Pattern;

/** A container and accessor for static version data, either configured in
  * properties or added to resources at compile time.
  * <p>
  * The compile-time files are generated by the "revision" ant target, which
  * just calls "svn info" and "cat version.txt" and places the stdout into
  * lightcrafts/resources/com/lightcrafts/app/resources.
  */
public final class Version {

    ////////// public /////////////////////////////////////////////////////////

    /**
     * Gets the application's name.
     *
     * @return Returns said name.
     */
    public static String getApplicationName() {
        return m_properties.getString( "app-name" );
    }

    public static URL getApplicationURL() {
        try {
            return new URL( m_properties.getString( "app-URL" ) );
        }
        catch ( MalformedURLException e ) {
            return null;
        }
    }

    public static URL getVideoLearningCenterURL() {
        try {
            return new URL( m_properties.getString( "VideoLearningCenter-URL" ) );
        }
        catch ( MalformedURLException e ) {
            return null;
        }
    }

    public static Map<String, URL> getVideoURLs() {
        Map<String, URL> map = new HashMap<String, URL>();
        // TODO put in final video URLs
        map.put("Introduction to Relight", getVideoLearningCenterURL());
        map.put("Advanced Relight", getVideoLearningCenterURL());
        map.put("Introduction to ZoneMapper", getVideoLearningCenterURL());
        map.put("Advanced ZoneMapper", getVideoLearningCenterURL());
        return map;
    }

    /**
     * Gets the Subversion revision number that was current at the time this
     * class was compiled.
     */
    public static int getRevisionNumber() {
        if ( SVNInfo == null )
            return -1;
        try {
            final String text =
                RevisionPattern.matcher( SVNInfo ).replaceAll( "$1" );
            return Integer.parseInt( text );
        }
        catch ( NumberFormatException e ) {
            return -1;
        }
    }

    public static Date getChangeDate() {
        if ( SVNInfo == null )
            return null;
        try {
            final String text =
                ChangeDatePattern.matcher( SVNInfo ).replaceAll( "$1" );
            return ChangeDateFormat.parse( text );
        }
        catch ( ParseException e ) {
            return null;
        }
    }

    /**
     * Get the URL of the Subversion repository that provided this class.
     */
    public static URI getUri() {
        if (SVNInfo == null) {
            return null;
        }
        try {
            String text = UrlPattern.matcher(SVNInfo ).replaceAll("$1");
            return new URI(text);
        }
        catch (URISyntaxException e) {
            return null;
        }
    }

    /**
     * Gets the user-presentable version String.
     */
    public static String getVersionName() {
        return Version;
    }

    /**
     * Get the Light Crafts homepage URL, or null if the URL text is not
     * configured or is invalid.
     */
    public static URL getHomepageURL() {
        try {
            return new URL( m_properties.getString( "company-URL" ) );
        }
        catch ( MalformedURLException e ) {
            return null;
        }
    }

    /**
     * Get the application help URL, or null if the URL text is not
     * configured or is invalid.
     */
    public static URL getHelpURL() {
        try {
            return new URL( m_properties.getString( "help-URL" ) );
        }
        catch (MalformedURLException e) {
            return null;
        }
    }

    ////////// private ////////////////////////////////////////////////////////

    /**
     * Reads a given resource.
     *
     * @param name The name of the resource file to read.
     * @return Returns the contents of saif resource file as a string.
     */
    private static String readResource( String name ) {
        InputStream in = null;
        try {
            final URL url = Version.class.getResource( "resources/" + name );
            if ( url == null )
                throw new FileNotFoundException( "Revision resource" );
            in = url.openStream();
            final BufferedReader reader =
                new BufferedReader( new InputStreamReader( in ) );
            final StringBuilder sb = new StringBuilder();
            String line;
            do {
                line = reader.readLine();
                if ( line != null ) {
                    sb.append( line );
                    sb.append( '\n' );
                }
            } while ( line != null );
            return sb.toString();
        }
        catch ( Throwable t ) {
            System.err.println( "Failed to read " + name + " resource" );
        }
        finally {
            if ( in != null )
                try {
                    in.close();
                }
                catch ( IOException e ) {
                    // ignore
                }
        }
        return null;
    }

    /**
     * This is where the actual labels for the tags are.
     */
    private static final ResourceBundle m_properties =
        ResourceBundle.getBundle( "com.lightcrafts.utils.resources.Version" );

    private static DateFormat ChangeDateFormat =
        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");

    // The date pattern from "svn info" looks like
    // "Last Changed Date: 2005-09-26 13:06:44 -0700 (Mon, 26 Sep 2005)":
    private static Pattern ChangeDatePattern = Pattern.compile(
        ".*^Last Changed Date:\\s*([^(]+).*",
        Pattern.DOTALL | Pattern.MULTILINE
    );

    /**
     * The output of the <code>svn info</code> command.
     */
    private static String SVNInfo;

    private static String Version;  // Contents of "version.txt"

    // The revision number from "svn info" looks like "Revision: 1000":
    private static Pattern RevisionPattern = Pattern.compile(
        ".*^Revision:\\s*([0-9]+).*", Pattern.DOTALL | Pattern.MULTILINE
    );

    // The URL pattern from "svn info" looks like "URL: svn+ssh://skippy...":
    private static Pattern UrlPattern = Pattern.compile(
        ".*^URL:\\s*([^\\s]+)$.*", Pattern.DOTALL | Pattern.MULTILINE
    );

    static {
        SVNInfo = readResource( "Revision" );
        Version = readResource( "Version" );
        if ( Version != null )
            Version = Version.trim();
    }

    ////////// main() for testing /////////////////////////////////////////////

    public static void main( String[] args ) throws Exception {
        System.out.println( getApplicationName() );
        System.out.println( getUri() );
        System.out.println( getRevisionNumber() );
        System.out.println( getChangeDate() );
    }
}
/* vim:set et sw=4 ts=4: */
