package java.lang;

import java.lang.reflect.*;
import java.util.jar.*;

/**
 * 指定されたクラスの main() メソッドを実行するスレッド
 * （パッケージプライベートクラス）
 */
final class VMMainThread extends Thread {
	
	/**
	 * クラス名またはjarファイル名
	 */
	String className;
	
	/**
	 * プログラムの引数
	 */
	String[] args;
	
	/**
	 * -jar オプションが指定されているか
	 */
	boolean jarOption;
	
	int nonDaemonThreadsCount;
	
	public VMMainThread(String classname, String[] args) {
		this(classname, args, false);
	}
	
	public VMMainThread(String classname, String[] args, boolean jar) {
	
		super(null,					// VMThread
			  "main",				// スレッド名
			  Thread.NORM_PRIORITY,	// プライオリティ
			  false);				// 非デーモンスレッド
		this.group = ThreadGroup.root;
		
		this.className = classname;
		this.args = (String[]) args.clone();
		this.jarOption = jar;
		
	}
	
	/**
	 * 非デーモンスレッドの個数を返す
	 */
	public synchronized int getNonDaemonThreadsCount() {
		return this.nonDaemonThreadsCount;
	}
	
	/**
	 * 非デーモンスレッドの個数が変化した際に、JVMから呼び出される。
	 */
	public synchronized void notifyNonDaemonThreadsCountChanged(int count) {
		this.nonDaemonThreadsCount = count;
		notifyAll();
	}
	
	/**
	 * コンソールを表示する
	 */
	static native void showConsole();
	
	public void run() {
		// ファイナライザスレッドをスタートさせる
		VMFinalizeThread fthread = VMFinalizeThread.getInstance();
		fthread.start();

		// 新しいスレッドを作成して、main()を実行する
		Thread t = new Thread() {
			public void run() {
				// classpathをロードする(Version0.3.6より)
				VMRuntime.nativeLoad("classpath", null);
				String cname = null;
				Method mainMethod = null;
				// システムクラスローダを使用してクラスをロードする
				ClassLoader cl = ClassLoader.getSystemClassLoader();
				try {
					if (jarOption) {
						// jarオプションが指定されている場合、classnameの内容から
						// Main-Classアトリビュートを取得する
						JarFile jarFile = new JarFile(className);
						Manifest mf = jarFile.getManifest();
						if (mf == null) {
							throw new Exception("No manifest in " + jarFile.getName());
						}
						Attributes attr = mf.getMainAttributes();
						cname = attr.getValue(Attributes.Name.MAIN_CLASS);
						if (cname == null) {
							throw new Exception("No Main-Class attribute in " + jarFile.getName());
						}
						
						// ToDo: Class-pathアトリビュートがある場合は、クラスローダに追加する
						
					} else {
						cname = className;
					}
					Class found = cl.loadClass(cname);
					mainMethod = found.getMethod("main", new Class[] { args.getClass() });

					// メインメソッドを起動する
					mainMethod.invoke(null, new Object[] { args } );
					
				} catch (Exception e) {
					e.printStackTrace();
					if (e instanceof RuntimeException) {
						throw (RuntimeException) e;
					}
					// コンソールをオープンする
					showConsole();
				}
			}
		};
		t.start();
		
/*
		// Todo:デーモンスレッドだけになるのを待つ処理を
		// ここに入れる
		synchronized (this) {
			while (getNonDaemonThreadsCount() > 0) {
				wait();
			}
		}

		// シャットダウンフックを実行する
		Runtime.getRuntime().runShutdownHooks();
		
		// デーモンスレッドだけになるまで待つ
		synchronized (this) {
			while (getNonDaemonThreadsCount() > 0) {
				wait();
			}
		}
*/
	}
}
