/* Copyright (c) 2001 Sinby, Inc.
   All Rights Reserved 

   This project is covered by the E-Sinby Embedded System Public License. 
   */

/* $Id: Application.java,v 1.10 2001/10/08 08:17:09 ryos Exp $ */

package com.sinby.kaffe_ecos;

import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.io.*;
import java.net.*;
import java.util.*;
import java.text.*;

public class Application {
	final public static String defaultPropertyFile = "/java/kaffe_ecos.props";

	final public static String classpathKey = "kaffe_ecos.classpath";
	final public static String backgroundKey = "kaffe_ecos.background";
	final public static String mainKey = "kaffe_ecos.main";
	final public static String mainArgsKey = "kaffe_ecos.main.args";
	final public static String netDriverKey = "kaffe_ecos.net.driver";
	final public static String inetKey = "kaffe_ecos.inet";
	final public static String inetIpaddrKey = "ipaddr";
	final public static String inetNetmaskKey = "netmask";
	final public static String inetBroadcastKey = "broadcast";
	final public static String inetGatewayKey = "gateway";
	final public static String inetServerKey = "server";

	public Application() {
	}

	public static Method getMainMethod(String prog) {
		Class clazz;
		Method method;

		try { 
			clazz = Class.forName(prog);
		} catch ( ClassNotFoundException ex ) {
			System.err.println("class not found:" + prog);
			return null;
		}
		try {
			method = clazz.getDeclaredMethod("main",new Class[]{String[].class});
		} catch ( NoSuchMethodException ex ) {
			System.err.println("No Such Method :" + prog + "#main(String[])");
			return null;
		} catch ( SecurityException ex ) {
			System.err.println("Security Exception :" + prog + "#main(String[]) " + ex.getMessage());
			return null;
		}

		return method;
	}

	public static String[] buildArgs(String arg) {
		String args[];

		if (arg != null ) {
			Vector v;
			StringTokenizer starg;
			starg = new StringTokenizer(arg);
			v = new Vector();
			while(starg.hasMoreTokens()) {
				v.addElement(starg.nextToken());
			}
			args = new String[v.size()];
			v.copyInto(args);
		} else {
			args = new String[0];
		}

		return args;
	}

	static boolean checkIpAddr(String addr) throws UnknownHostException {
		if ( addr == null ) {
			return false;
		}

		StringTokenizer st;

		st = new StringTokenizer(addr,".");
		for( int i = 0 ; i < 4 ; i++ ) {
			if (!st.hasMoreTokens()) {
				throw new UnknownHostException("delimiter error");
			}
			try {
				int v;
				v = Integer.parseInt(st.nextToken());
				if ((v < 0) || ( v > 255 )) {
					throw new UnknownHostException("ip number format error:" + v);
				}
			} catch ( NumberFormatException ex ) {
				throw new UnknownHostException("number format error");
			}
		}

		return true;
	}

	public static void setNetwork(String driver,Properties props) {
		if ( !driver.equals("eth0") && !driver.equals("eth1")) {
			System.out.println("driver name is failed:" + driver );
			System.out.println("\tYou can use the driver name, 'eth0' or 'eth1'");
			return;
		}
		String ipaddr,netmask,broadcast,gateway,server;
		StringBuffer inet_driver_ ;
		inet_driver_ = new StringBuffer(48);
		inet_driver_.append(inetKey);
		inet_driver_.append(".");
		inet_driver_.append(driver);
		inet_driver_.append(".");
		int len = inet_driver_.length();

		try {
			inet_driver_.append(inetIpaddrKey);
			ipaddr = props.getProperty(inet_driver_.toString());
			if (!checkIpAddr(ipaddr)) {
				System.out.println("You must set ipaddr :" + 
					inet_driver_.toString() 
					+ ":" +
					props.getProperty(inet_driver_.toString()));
				return;
			}

			inet_driver_.setLength(len);
			inet_driver_.append(inetNetmaskKey);
			netmask = props.getProperty(inet_driver_.toString());
			checkIpAddr(netmask);

			inet_driver_.setLength(len);
			inet_driver_.append(inetBroadcastKey);
			broadcast = props.getProperty(inet_driver_.toString());
			checkIpAddr(broadcast);

			inet_driver_.setLength(len);
			inet_driver_.append(inetGatewayKey);
			gateway = props.getProperty(inet_driver_.toString());
			checkIpAddr(gateway);

			inet_driver_.setLength(len);
			inet_driver_.append(inetServerKey);
			server = props.getProperty(inet_driver_.toString());
			checkIpAddr(server);

			if (!SystemResources.re_init_net(driver,ipaddr,netmask,broadcast,gateway,server)) {
				System.out.println("re_inet_net error");
			}
		} catch ( UnknownHostException ex ) {
			System.out.println("you must set currect ipaddr :" + 
				inet_driver_.toString() 
				+ ":" +
				props.getProperty(inet_driver_.toString()));
		}
	}

	public static void doBackground(String background,Properties props) {
		StringTokenizer st;

		st = new StringTokenizer(background,", \t");
		while(st.hasMoreTokens()) {
			final String prog;
			String key;
			final Method method;
			final String args[];

			prog = st.nextToken();

			method = getMainMethod(prog);
			if ( method == null ) {
				continue;
			}
			key = backgroundKey + "." + prog + ".args";

			args = buildArgs(props.getProperty(key));

			Thread thread;

			thread = new Thread(new Runnable() {
				public void run() {
					try {
						method.invoke(null,new Object[]{args});
					} catch ( InvocationTargetException ex ) {
						Throwable target;

						target = ex.getTargetException();
						System.err.println("Invoke Target Exception :" + prog + "#main(String[]) " + target.getMessage());
						target.printStackTrace();
						if ( target instanceof ExceptionInInitializerError ) {
							Throwable deep;
							deep = ((ExceptionInInitializerError)target).getException();
							System.err.println("ExceptionInInitializerError :" + deep.getMessage());
							deep.printStackTrace();
						}
					} catch ( Exception ex ) {
						System.err.println("Invoke Exception :" + prog + "#main(String[]) " + ex.getMessage());
					}
				}
			});
			thread.start();
		}
	}

	public static boolean addClasspath(String classpath) {
		StringTokenizer st;

		st = new StringTokenizer(classpath,":");
		while(st.hasMoreTokens()) {
			if (!SystemResources.addClasspath(st.nextToken())) {
				return false;
			}
		}
		return true;
	}

	public static void hello() {
		System.out.println();
		System.out.println("Welcome to Kaffe/eCos world");
		if ( true ) {
			System.out.println("now loading locale...");
			Locale loc = Locale.getDefault();
			System.out.println("\t" + loc);
			System.out.println("now loading date format...");
			SimpleDateFormat formatter = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss ",loc);
			System.out.println("\t" + formatter.format(new Date()));
		}
		System.out.println("start applications");
	}

	public static void goodbye() {
		System.out.println("Good bye Kaffe/eCos world");
	}

	public static void main(String args[]) {
		Properties props;

		hello();
		props = new Properties();
		try {
			InputStream is;
			if ( args.length == 0 ) {
				is = new FileInputStream(defaultPropertyFile);
			} else {
				URL url;
				url = new URL(args[0]);
				is = url.openStream();
			}
			props.load(is);
		} catch ( IOException ex ) {
			System.err.println("loading error:" + ex.getMessage());
			System.exit(1);
			return;
		}

		/* set class path */
		String classpath;
		classpath = props.getProperty(classpathKey);
		if ( classpath != null ) {
			if ( addClasspath(classpath)) {
				System.out.println("add classpath success:" + classpath );
			} else {
				System.out.println("add classpath failed:" + classpath );
			}
		}

		/* set network */
		StringTokenizer drivers = new StringTokenizer(props.getProperty(netDriverKey,"")); 
		while ( drivers.hasMoreTokens() ) {
			String driver;
			driver = drivers.nextToken();
			System.out.println("network driver:" + driver);
			setNetwork(driver,props);
		}

		/* execute background */
		String background;

		background = props.getProperty(backgroundKey);
		if ( background != null ) {
			doBackground(background,props);
		}

		String mainProg;
		mainProg = props.getProperty(mainKey);

		Method mainMethod;
		String mainArgs[];
		mainMethod = getMainMethod(mainProg);
		if ( mainMethod != null ) {
			mainArgs = buildArgs(props.getProperty(mainArgsKey));
			try {
				mainMethod.invoke(null,new Object[]{mainArgs});
			} catch ( InvocationTargetException ex ) {
				Throwable target;

				target = ex.getTargetException();
				System.err.println("Invoke Target Exception :" + mainProg + "#main(String[]) " + target.getMessage());
				target.printStackTrace();
				if ( target instanceof ExceptionInInitializerError ) {
					Throwable deep;
					deep = ((ExceptionInInitializerError)target).getException();
					System.err.println("ExceptionInInitializerError :" + deep.getMessage());
					deep.printStackTrace();
				}
			} catch ( Exception ex ) {
				System.err.println("Invoke Exception :" + mainProg + "#main(String[]) " + ex.getMessage());
				ex.printStackTrace();
			}
		}
		goodbye();
	}
}
