/*******************************************************************************
 * Copyright (c) 2000, 2004 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.update.tests.mirror;

import java.io.*;
import java.util.ArrayList;
import java.util.StringTokenizer;

import org.eclipse.core.runtime.*;
import org.eclipse.update.configurator.*;
import org.eclipse.update.internal.core.UpdateCore;
import org.eclipse.update.tests.UpdateManagerTestCase;


public class MirrorManagerTestCase extends UpdateManagerTestCase{
	public static int exitValue=-1;
	public static StringBuffer errOutput;
	
	public MirrorManagerTestCase(String arg0){
		super(arg0);
	}
	
	//WatchDog thread to kill mirroring process if it hangs (or takes too long)
	public static class Timer extends Thread{
		private Process proc;
		
		public Timer(Process proc){
			super();
			this.setDaemon(true);
			this.proc = proc;
		}
		
		public void run(){
			try {
				// Note: normal test on 2.2Ghz P4 is 2.9s 
				//:. giving 100x leeway to complete process before killing it
				sleep(300000); 
				proc.destroy();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	// structure to hold category definition names and descriptions
	class CategoryDefinition {
		private String name;
		private String desc;
		public void setName(String name) {
			this.name = name;
		}
		public void setDesc(String desc) {
			this.desc = desc;
		}
		public String getName() {
			return name;
		}
		public String getDesc() {
			return desc;
		}
	}
	
	// structure to hold feature IDs and their category names
	public class FeatureCategory{
		private String featureId;
		private ArrayList category;
		
		public FeatureCategory(){
			category = new ArrayList();
		}
		
		public void setFeatureID(String fid){
			featureId = fid;
		}
		
		public void addCategory(String cat){
			category.add(cat);
		}
		
		public String getFeatureID(){
			return featureId;
		}
		
		public String[] getCategories(){
			return (String[])category.toArray(new String[category.size()]);
		}
	}
	
	// StreamConsumer to display output to output files or console
	public static class StreamConsumer extends Thread {
		private BufferedReader bReader;

		public StreamConsumer(InputStream inputStream) {
			super();
			setDaemon(true);
			bReader = new BufferedReader(new InputStreamReader(inputStream));
		}

		public void run() {
			try {
				String line;
				while (null != (line = bReader.readLine())) {
					System.out.println(line);
					errOutput.append(line);
					errOutput.append("\n");
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Returns a string array consisting of commands and their arguments to
	 * be run.
	 * @param remoteLoc - path of remote site (site being mirrored)
	 * @param toLocalSiteUrl - path of local site (new mirror site)
	 * @param fid - feature id of featuring being mirror (optional - can be null)
	 * @param ver - version of feature to be mirrored (optional - can be null)
	 * @param mirUrl - directory location of policy.xml (optional - can be mull)
	 * @return
	 */
	public String[] getCommand(
		String remoteLoc,
		String toLocalSiteUrl,
		String fid,
		String ver,
		String mirUrl) {
		final String classpath = "startup.jar";
		final String launcher = "org.eclipse.core.launcher.Main";
		final String command = "mirror";
		final String application = "org.eclipse.update.core.standaloneUpdate";
		final String FLAG_CP = "-cp";
		final String FLAG_APP = "-application";
		final String FLAG_CMD = "-command";
		final String FLAG_FID = "-featureId";
		final String FLAG_DATA = "-data";
		final String FLAG_VERSION = "-version";
		final String FLAG_FROM = "-from";
		final String FLAG_TO = "-to";
		final String FLAG_URL = "-mirrorURL";
		final String FLAG_SPLASH = "-nosplash";
		final String FLAG_CONSOLELOG = "-consolelog";
		final String data =
			UpdateCore.getPlugin().getStateLocation().toOSString();
		String[] cmd =
			new String[] {
				getJavaVMPath(),
				FLAG_CP,
				classpath,
				launcher,
				FLAG_APP,
				application,
				FLAG_CMD,
				command,
				FLAG_FROM,
				(remoteLoc !=null ? remoteLoc : ""),
				FLAG_TO,
				toLocalSiteUrl,
				(fid != null ? FLAG_FID : ""),
				(fid != null ? fid : ""),
				(ver != null ? FLAG_VERSION : ""),
				(ver != null ? ver : ""),
				(mirUrl != null ? FLAG_URL : ""),
				(mirUrl != null ? mirUrl : ""),
				FLAG_SPLASH,
				FLAG_DATA,
				data,
				FLAG_CONSOLELOG};
		return cmd;
	}
	
	public boolean checkFeatureInSiteXMLExists(String url, String fid, String ver){
		File site = new File(url + "/site.xml");
		assertTrue(site.exists());
		BufferedReader breader;
		FileReader freader;
		String text = new String();
		String jarName = fid + "_" + ver + ".jar";
		String feature = "<feature url=\"" +
			"features/" + jarName + 
			"\" id=\"" + fid + 
			"\" version=\"" + ver+"\">";
		try {
			freader = new FileReader(site);
			breader = new BufferedReader(freader);
		} catch (FileNotFoundException e) {
			// would have been caught by assert above
			return false;
		}
		try {
			while ((text = breader.readLine()) != null) {
				text = text.trim();
				if (text.equals(feature)){
					breader.close();
					freader.close();
					return true;
				}
			}

			breader.close();
			freader.close();
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
	}

	public void checkSiteXML(String url) throws Exception {
		File mirror = new File(url);
		File site = new File(url + "/site.xml");
		assertTrue(mirror.isDirectory());
		assertTrue(mirror.exists());
		assertTrue(site.exists());
	}

	public void checkPolicyXML(String url) throws Exception {
		File mirror = new File(url);
		File site = new File(url + "/policy.xml");
		assertTrue(mirror.isDirectory());
		assertTrue(mirror.exists());
		assertTrue(site.exists());
	}
	public boolean checkPolicyURL(String url, String mirrorUrl){
		File site = new File(url + "/policy.xml");
		assertTrue(site.exists());
		BufferedReader breader;
		FileReader freader;
		String text = new String();

		try {
			freader = new FileReader(site);
			breader = new BufferedReader(freader);
		} catch (FileNotFoundException e) {
			// would have been caught by assert above
			return false;
		}

		try {
			while ((text = breader.readLine()) != null) {
				if (text.indexOf(mirrorUrl)!=-1){
					breader.close();
					freader.close();	
					return true;
				}
			}

			breader.close();
			freader.close();
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
	}

	public boolean doesCategoryDefinitionExist(String url) {
		File site = new File(url + "/site.xml");
		assertTrue(site.exists());
		BufferedReader breader;
		FileReader freader;
		String text = new String();

		try {
			freader = new FileReader(site);
			breader = new BufferedReader(freader);
		} catch (FileNotFoundException e) {
			// would have been caught by assert above
			return false;
		}

		try {
			while ((text = breader.readLine()) != null) {
				if (text.indexOf("category-def")!=-1)
					return true;
			}

			breader.close();
			freader.close();
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}

	}
	
	public String getEclipseRoot() {
		return ConfiguratorUtils.getInstallURL().toExternalForm().replaceFirst(
			"file:",
			"");
	}
	
	public FeatureCategory[] getFeatureCategories(String url){
		File site = new File(url + "/site.xml");
		assertTrue(site.exists());
		BufferedReader breader;
		FileReader freader;
		String text = new String();
		ArrayList featureCategories = new ArrayList();
		
		try {
			freader = new FileReader(site);
			breader = new BufferedReader(freader);
		} catch (FileNotFoundException e) {
			// would have been caught by assert above
			return new FeatureCategory[0];
		}

		try {
			FeatureCategory currTok = new FeatureCategory();
			boolean add = false;
			while((text =breader.readLine())!=null){
				StringTokenizer strTok = new StringTokenizer(text);
				while (strTok.hasMoreTokens()){
					String temp = strTok.nextToken();
					if (temp.equals("</feature>")){
						add = true;
					} else if (temp.startsWith("id")){
						currTok.setFeatureID(temp.split("\"")[1]);
					} else if (temp.startsWith("name")){
						currTok.addCategory(temp.split("\"")[1]);
					}
				}
				if (add){
					featureCategories.add(currTok);
					currTok = new FeatureCategory();
					add = false;
				}
			}

			breader.close();
			freader.close();
			return (FeatureCategory[])featureCategories.toArray(new FeatureCategory[featureCategories.size()]);
		} catch (IOException e) {
			System.err.println(e);
			return new FeatureCategory[0];
		}
	}
	
	public String getJavaVMPath() {
		// Create command string for launching the process
		String vm = System.getProperty("java.vm.name");
		String executable = "J9".equals(vm) ? "j9" : "java";
		if (org.eclipse.osgi.service.environment.Constants.OS_WIN32.equals(Platform.getOS()))
			executable += "w.exe";

		String javaInstallDir =
			System.getProperty("java.home") + File.separator + "bin";
		return javaInstallDir + File.separator + executable;
	}
	
	public CategoryDefinition[] getCategoryDefinitions(String url) {
		File site = new File(url + "/site.xml");
		assertTrue(site.exists());
		BufferedReader breader;
		FileReader freader;
		String text = new String();
		ArrayList catDef = new ArrayList();

		try {
			freader = new FileReader(site);
			breader = new BufferedReader(freader);
		} catch (FileNotFoundException e) {
			// would have been caught by assert above
			return new CategoryDefinition[0];
		}

		try {
			boolean add = false;
			boolean isDesc = false;
			CategoryDefinition temp = new CategoryDefinition();
			while ((text = breader.readLine()) != null) {
				if (text.trim().startsWith("<category-def")
					&& text.indexOf("name") != -1) {
					temp.setName(text.split("\"")[1]);
					add = false;
				} else if (text.trim().equals("<description>")) {
					isDesc = true;
				} else if (text.trim().equals("</description>")) {
					isDesc = false;
				} else if (isDesc) {
					temp.setDesc(text.trim());
				} else if (text.trim().equals("</category-def>")) {
					add = true;
				}
				if (add) {
					catDef.add(temp);
					add = false;
					temp = new CategoryDefinition();
				}
			}

			breader.close();
			freader.close();
			return (CategoryDefinition[])catDef.toArray(new CategoryDefinition[catDef.size()]);
		} catch (IOException e) {
			System.err.println(e);
			return new CategoryDefinition[0];
		}

	}
	
	public int performMirror(String[] cmd_mirror) {
		File file = new File(getEclipseRoot());
		try {
			System.out.println("Launching:");
			for(int i=0; i<cmd_mirror.length; i++){
				System.out.print(cmd_mirror[i]+" ");
			}
			System.out.println();
			Process proc =
				Runtime.getRuntime().exec(cmd_mirror, (String[]) null, file);

			StreamConsumer outputs = new StreamConsumer(proc.getInputStream());
			outputs.start();
			StreamConsumer errors = new StreamConsumer(proc.getErrorStream());
			errors.start();
			Timer timer = new Timer(proc);
			timer.start();

			return proc.waitFor();
		} catch (IOException e) {
			System.err.println(e);
		} catch (InterruptedException e) {
			System.err.println(e);
		} catch (Exception e) {
			System.err.println(e);
		}
		return -1;
	}

	// ensure exit without problems
	public void testExitValue() throws Exception {
		assertEquals(exitValue, 0);
	}
	
	// ensure output string buffer ends with "Mirror command completed
	// successfully."
	// note: output may instead by "Command completed successfully."
	public void testMirrorSuccess() throws Exception {
		StringTokenizer tokenizer =
			new StringTokenizer(
				errOutput.toString(),
				"\n");
		String lastLine = new String();
		while (tokenizer.hasMoreTokens()){
			lastLine = tokenizer.nextToken();
		}
		assertTrue(
			lastLine.equals("Mirror command completed successfully.")
				|| lastLine.equals("Command completed successfully."));
	}
}
