package com.ibm.teamcity.tools;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class WASDriverLoader {

	private static String PropWasBuildRoot 			= "was.build.root";
	private static String WasBuildRootDefault 		= "\\\\ausgsa.ibm.com\\projects\\w\\was.build";
	
	private enum Options {
		property, 					p, 					// customer property file location
		help, 						h,					// help
		
		unknown, 					u, 					// 
		lastcommitted, 				lc,
		lastgood, 					lg,
		latest, 					lt,
		level,						lvl,
		
		fe,
		buildfile,					f,
	};

	private enum BuildOptions {
		LastCommitted,
		LastGood,
		Latest,
		Specified
	};
	BuildOptions buildOption = BuildOptions.LastCommitted;
	String buildLevel;
	
	Comparator<File> descendOrderComparator;
	String[] options;
	String fe = "WASX.IWAS";
	String bFile = "build.xml";
	StringBuilder target = new StringBuilder();
	
	Properties props;
	
	public WASDriverLoader(String[] options) {
		props = new Properties();
		
		boolean needToPrintHelp = false;
		descendOrderComparator = new Comparator<File>() {
			public int compare(final File f1, final File f2) {
				final long t1 = f1.lastModified();
				final long t2 = f2.lastModified();
				return (t1 > t2) ? -1 : ((t1 < t2) ? 1 : 0);
			}
		};
		
		this.options = options;
		for (int i = 0 ; i < options.length ; ++i) {
			String option = options[i];
			switch (getOption(option)) {
			case property:
			case p:
				if ((i + 1) < options.length && !options[i+1].startsWith("-")) {
					try {
						props.load((new FileInputStream(options[++i])));
					} catch (IOException ioe) {
						System.err.println("**Error: Unable to load properties from '" + options[i] + "'.");
						needToPrintHelp = true;
					}
				} else {
					System.err.println("**Error: Missing value for -property option.");
					needToPrintHelp = true;
				}
				props.list(System.out);
				break;
				
			case lastcommitted:
			case lc:
				buildOption = BuildOptions.LastCommitted;
				buildLevel = null;
				break;

			case lastgood:
			case lg:
				buildOption = BuildOptions.LastGood;
				buildLevel = null;
				break;

			case latest:
			case lt:
				buildOption = BuildOptions.Latest;
				buildLevel = null;
				break;

			case level:
			case lvl:
				if ((i + 1) < options.length && !options[i+1].startsWith("-")) {
					buildOption = BuildOptions.Specified;
					buildLevel = options[++i];
				} else {
					System.err.println( "**Error: Missing value for -level option.");
					needToPrintHelp = true;
				}
				break;

			case fe:
				if ((i + 1) < options.length && !options[i+1].startsWith("-")) {
					fe = options[++i];
				} else {
					System.err.println( "**Error: Missing value for -fe option.");
					needToPrintHelp = true;
				}
				break;

			case buildfile:
			case f:
				if ((i + 1) < options.length && !options[i+1].startsWith("-")) {
					bFile = options[++i];
				} else {
					System.err.println( "**Error: Missing value for -buildfile option.");
					needToPrintHelp = true;
				}
				break;

			case unknown:
			case u:
				target.append(' ')
				.append(option);
				// fall through to help
				break;
			case help:
			case h:
				needToPrintHelp = true;
			}
		}
		if( needToPrintHelp ) {
			printHelp();
			System.exit(1);
		}
	}

	private void printHelp() {
		System.out.println("Usage: .....");
		System.out.println("Options:");
		System.out.println("  ...");
	}

	private Options getOption(String option) {
		option = option.trim();
		if (option.startsWith("-")) {
			option = option.substring(1);
			for (Options opt : Options.values()) {
				if (opt.toString().equals(option.toLowerCase())) {
					return opt;
				}
			}
		}
		return Options.unknown;
	}

	public void run() throws IOException {
		String fileRoot = getBuildLevel();
		File root = new File(fileRoot);
		System.out.println( root.toString() );

		StringBuilder cmd = new StringBuilder();
		cmd.append("ant -f ")
		.append(bFile)
		.append(" -Dbuild.target=")
		.append(root.toString())
		.append(' ')
		.append(target.toString());
		
		execCmd(cmd.toString());
	}

	/**
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {

		File[] xf = (new File("b:\\")).listFiles();
//		for( File xx : xf )
//			System.out.println(xx);
//		System.exit(0);
		
		WASDriverLoader loader = new WASDriverLoader(args);
		loader.run();
		System.exit(0);
		
		// On linux:
		// smbmount //ausgsa.ibm.com/projects/w /tmp/botp -o username=leealber
		// password=.....
		// smbumount /tmp/botp
		// 

		// URL url = new
		// URL("ftp://leealber:e307llis@ausgsa.ibm.com/projects/w/was.build/botp");
		URL url = new URL("https://ausgsa.ibm.com/projects/w/was.build/botp/WASX.IWAS/test/");
		Authenticator.setDefault(new SimpleAuthenticator("leealber", "e307llis"));
		URLConnection conn = url.openConnection();

		// if (conn instanceof HttpURLConnection) {
		/* Http */URLConnection httpConn = /* (HttpURLConnection) */conn;

		System.out.println("Type:\t" + httpConn.getContentType());
		System.out.println("Len:\t" + httpConn.getContentLength());
		// System.out.println("RespCode:\t" + httpConn.getResponseCode());
		// System.out.println("RespMsg:\t" + httpConn.getResponseMessage());
		System.out.println("Date:\t" + httpConn.getDate());
		System.out.println("expire:\t" + httpConn.getExpiration());
		System.out.println("ModSince:\t" + httpConn.getIfModifiedSince());
		System.out.println("LastMod:\t" + httpConn.getLastModified());
		System.out.println("ReadTmo:\t" + httpConn.getReadTimeout());
		// System.out.println("ReqMethod:\t" + httpConn.getRequestMethod());
		Map<String, List<String>> map = httpConn.getHeaderFields();
		Set<String> keys = map.keySet();
		for (String key : keys) {
			System.out.println(key + ":" + map.get(key));
		}
		// System.out.println( "Content:\t" + httpConn.getContent());

		BufferedReader in = new BufferedReader(new InputStreamReader(httpConn
				.getInputStream()));
		String inputLine;

		while ((inputLine = in.readLine()) != null)
			System.out.println(inputLine);
		in.close();
	}

	private boolean isGoodFitness(File file) {
		boolean rtnVal = false;
		BufferedReader fitnessReader = null;
		try {
			File buildFitness = new File(file.getCanonicalPath()
					+ "\\linux\\zipper\\build_fitness.xml");
			fitnessReader = new BufferedReader(new FileReader(
					buildFitness));
			String line;
			while (!rtnVal && (line = fitnessReader.readLine()) != null) {
				rtnVal = line.indexOf("<status build=\"good\"") != -1;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if( fitnessReader != null) {
				try {
				fitnessReader.close();
				} catch (Exception e) {
				}
			}
		}
		return rtnVal;
	}

	private String getBuildLevel() throws IOException {
		String buildRoot = props.getProperty(PropWasBuildRoot,
				WasBuildRootDefault);
		File[] fCombines = new File[0];
		File[] fGoodLatests = new File[0];
		File[] fCommitteds = new File[0];
		switch (buildOption) {
		case Specified:
		case LastGood:
		case Latest:
			File fGoodLatest = new File(buildRoot + "\\botp\\" + fe + "\\daily");
			System.out.println("**" + fGoodLatest.isDirectory());
			System.out.println("**" + fGoodLatest.isFile());
			fGoodLatests = fGoodLatest.listFiles();
			if (fGoodLatests == null) {
				System.out.println("**Warning: " + fGoodLatest
						+ " is an invalid path.");
			}

			// falls through
		case LastCommitted:
			File fCommitted = new File(buildRoot + "\\botp\\" + fe + "\\test");
			fCommitted = new File("b:\\");
			System.out.println("** isDir =" + fCommitted.isDirectory());
			System.out.println("** isFile=" + fCommitted.isFile());
			System.out.println("** exists=" + fCommitted.exists());
			System.out.println( "fCommitted=" + fCommitted);
			
			fCommitteds = fCommitted.listFiles();
			if (fCommitteds == null) {
				System.out.println("**Warning: " + fCommitted
						+ " is an invalid path.");
			}
			fCombines = new File[fGoodLatests.length + fCommitteds.length];
			System.arraycopy(fCommitteds, 0, fCombines, 0, fCommitteds.length);
			System.arraycopy(fGoodLatests, 0, fCombines, fCommitteds.length,
					fGoodLatests.length);
			break;

		}
		String rtnFName = null;
		if (fCombines.length > 0) {
			Arrays.sort(fCombines, descendOrderComparator);
			File rtnFile = fCombines[0];
			switch (buildOption) {
			case Latest:
			case LastCommitted:
				rtnFile = fCombines[0];
				break;
			case Specified:
				for (File file : fCombines) {
					String thisLevel = file.getName().substring(0,
							file.getName().indexOf(".linux"));
					if (thisLevel.equals(buildLevel)) {
						rtnFile = file;
						break;
					}
				}
				break;
			case LastGood:
				for (File file : fCombines) {
					if (isGoodFitness(file))
						rtnFile = file;
					break;
				}
				break;
			}
			rtnFName = rtnFile.getCanonicalPath()
					+ "/linux/zipper/externals/installables/";
			System.out.println("build level = " + rtnFName);
		}
		return rtnFName;
	}
	
	private void execCmd(String command) throws IOException {
		if (true) {
			System.out.println("cmd:'" + command + "'");
		} else {
			Runtime.getRuntime().exec(command);
		}
	}
}

class SimpleAuthenticator extends Authenticator {
	private String username, password;

	public SimpleAuthenticator(String username, String password) {
		this.username = username;
		this.password = password;
	}

	protected PasswordAuthentication getPasswordAuthentication() {
		return new PasswordAuthentication(username, password.toCharArray());
	}
}