/*
 * Paraselene
 * Copyright (c) 2009, 2010  Akira Terasaki
 * このファイルは同梱されている License.txt に定めた条件に同意できる場合にのみ
 * 利用可能です。
 */
package paraselene;

import paraselene.supervisor.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.zip.*;
import java.util.jar.*;

/**
 * Paraseleneのバージョン情報。
 */
public class Version {
	private Version(){}
	/**
	 * Paraseleneのバージョン番号を表す文字列。
	 * 2.2.2.29
	 */
	public static final String VERSION = "2.2.2.29";
	private static final String	SITE = " (http://paraselene.sourceforge.jp/)";
	private static final String	TITLE = "Paraselene2 " + VERSION + SITE;
	private static final String[] CLASS_PATH = new String[] {
		"sun.boot.class.path",
		"java.ext.dirs",
		"java.class.path",
	};
	private static final File JAR_PATH = seekJar();

	/**
	 * バージョン番号の取得。
	 * @return バージョンが 2.3.4 であれば、
	 * new int[]{ 2, 3, 4 }
	 * のような配列を返します。
	 */
	public static int[] getVersion() {
		String[]	ver = VERSION.split( "\\." );
		int[]	ret = new int[ver.length];
		for ( int i = 0; i < ver.length; i++ ) {
			ret[i] = Integer.parseInt( ver[i] );
		}
		return ret;
	}

	/**
	 * Paraseleneのアプリタイトル文字列。
	 * @return アプリタイトル。
	 */
	public static String getTitle() {
		return TITLE;
	}

	/**
	 * Paraseleneの著作権表示。
	 * @return 著作権表示。
	 */
	public static String getCopyRight() {
		return "Copyright 2009 Akira Terasaki";
	}

	private static boolean isHit( File f ) {
		JarFile	file = null;
		try{
			file = new JarFile( f );
			JarEntry	ent = file.getJarEntry( "paraselene/Version.class" );
			return ent != null;
		}
		catch( Exception e ) {}
		finally {
			try {
				file.close();
			}
			catch( Exception e ){}
		}
		return false;
	}

	private static File seekJar( File dir, boolean nest_f ){
		if ( dir.isDirectory() ) {
			if ( nest_f )	return null;
			File[]	next = dir.listFiles();
			for ( int  i = 0; i < next.length; i++ ) {
				File	ret = seekJar( next[i], true );
				if ( ret != null )	return ret;
			}
		}
		else {
			if ( isHit( dir ) )	return dir;
		}
		return null;
	}

	private static File seekJar( String key ) {
		String	prop = System.getProperty( key );
		if ( prop == null )	return null;
		String[]	dir = prop.split( File.pathSeparator );
		for ( int i = 0; i < dir.length; i++ ) {
			File	ret = seekJar( new File( dir[i].trim() ), false );
			if ( ret != null )	return ret;
		}
		return null;
	}

	private static File seekJar() {
		try {
			URL	url = Version.class.getResource( "/paraselene/Version.class" );
			String	path = URIValue.encode( url.toString().split( "!" )[0].substring( 4 ), null, false );
			URI	uri = new URI( path );
			File	file = new File( uri );
			path = URLDecoder.decode( file.getPath(), URIValue.DEFAULT_ENC );
			file = new File( path );
			return file;
		}
		catch( Exception e ) {
			e.printStackTrace();
		}
		for ( int i = 0; i < CLASS_PATH.length; i++ ) {
			File	ret = seekJar( CLASS_PATH[i] );
			if ( ret != null )	return ret;
		}
		return null;
	}

	/**
	 * このjarファイルのフルパス。
	 * @return jarファイルのフルパス。
	 */
	public static File getJarPath() {
		return JAR_PATH;
	}

	private static String fixName( String name ) {
		String[]	test = name.split( "\\\\" );
		StringBuilder	buf = new StringBuilder( test[0] );
		for ( int i = 1; i < test.length; i++ ) {
			buf = buf.append( "/" );
			buf = buf.append( test[i] );
		}
		return seekTop( buf.toString() );
	}

	private static final String[] top_dir = new String[] {
		"css", "image", "js"
	};

	private static String seekTop( String name ) {
		String[]	dir = name.split( "/" );
		int	top = dir.length - 1;
		for ( ; top > 0; top-- ) {
			boolean	flag = false;
			for ( int i = 0; i < top_dir.length; i++ ) {
				if ( dir[top].equals( top_dir[i] ) ) {
					flag = true;
					break;
				}
			}
			if ( flag )	break;
		}
		StringBuilder	buf = new StringBuilder( dir[top] );
		for ( top++; top < dir.length; top++ ) {
			buf = buf.append( "/" );
			buf = buf.append( dir[top] );
		}
		return buf.toString();
	}

	/**
	 * リソースの更新時間の取得。
	 * @param name リソースの名前。
	 * @return 更新時間。
	 */
	public static HTTPDate getLastModified( String name ) {
		JarFile	file = null;
		name = fixName( name );
		try {
			file = new JarFile( getJarPath() );
			return new HTTPDate( new Date( file.getEntry( name ).getTime() ) );
		}
		catch( Exception e ) {
			Option.debug( e );
		}
		finally {
			try {
				file.close();
			}
			catch( Exception e ) {}
		}
		return new HTTPDate( new Date( getJarPath().lastModified() ) );
	}

	private static InputStream jarConvert( JarFile file, String name ) {
		InputStream	in = null;
		try {
			JarEntry	entry = file.getJarEntry( name );
			byte[]	buf = new byte[(int)entry.getSize()];
			in = file.getInputStream( entry );
			in.read( buf );
			return new ByteArrayInputStream( buf );
		}
		catch( Exception e ) {
			Option.debug( e );
		}
		finally {
			try {
				in.close();
			}
			catch( Exception e ) {}
		}
		return null;
	}

	/**
	 * リソースの取得。
	 * @param name リソースの名前。
	 * @return リソース。取得に失敗すると null を返します。
	 */
	public static InputStream getResource( String name ) {
		name = fixName( name );

		ClassLoader	ld = Version.class.getClassLoader();
		if ( ld != null ) {
			InputStream	is = ld.getResourceAsStream( name );
			if ( is != null )	return is;
		}
		JarFile	file = null;
		try {
			file = new JarFile( getJarPath() );
			return jarConvert( file, name );
		}
		catch( Exception e ){
			Option.debug( e );
		}
		finally {
			try {
				file.close();
			}
			catch( Exception e ) {}
		}
		return null;
	}
}

