package cz.softeu.hudson;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Elements;
import nu.xom.Node;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;

public class Hudson {

	public static String	HUDSON_VIEW_PART	= "view/";
	public static String	HUDSON_URL_SUFFIX	= "api/xml";

	public static class MonitorConfiguration {
		public String	password;
		public String	username;

		public String	URL;
		public String	viewPrefix;
		public String	x10Prefix;
		public String	noTestFailSuffix;

		public String getPassword() {
			return password;
		}

		public void setPassword(String password) {
			this.password = password;
		}

		public String getUsername() {
			return username;
		}

		public void setUsername(String username) {
			this.username = username;
		}

		public String getURL() {
			return URL;
		}

		public void setURL(String url) {
			URL = url;
		}

		public String getViewPrefix() {
			return viewPrefix;
		}

		public void setViewPrefix(String viewPrefix) {
			this.viewPrefix = viewPrefix;
		}

		public String getX10Prefix() {
			return x10Prefix;
		}

		public void setX10Prefix(String prefix) {
			x10Prefix = prefix;
		}

		public String getNoTestFailSuffix() {
			return noTestFailSuffix;
		}

		public void setNoTestFailSuffix(String noTestFailSuffix) {
			this.noTestFailSuffix = noTestFailSuffix;
		}
	}

	enum State {
		OK, TESTFAIL, FAIL
	}

	public static class ProjectState {
		boolean	isBuilding;
		State	state;

		public ProjectState(boolean isBuilding, State state) {
			super();
			this.isBuilding = isBuilding;
			this.state = state;
		}

		public boolean isBuilding() {
			return isBuilding;
		}

		public State getState() {
			return state;
		}
	}

	public static Document getUrlAsXML(MonitorConfiguration config, String url) throws Exception {
		HttpClient client = new HttpClient();
		HttpMethod method = new GetMethod(url);

		client.getParams().setAuthenticationPreemptive(true);
		Credentials defaultcreds = new UsernamePasswordCredentials(config.getUsername(), config.getPassword());
		client.getState().setCredentials(AuthScope.ANY, defaultcreds);

		// Provide custom retry handler is necessary
		method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(3, false));
		method.setDoAuthentication(true);

		try {
			int statusCode = client.executeMethod(method);

			if (statusCode != HttpStatus.SC_OK) {
				System.err.println("Method failed: " + method.getStatusLine());
			} else {

				// Read the response body.
				Builder parser = new Builder();
				Document doc = parser.build(method.getResponseBodyAsStream());

				return doc;
			}

		} finally {
			// Release the connection.
			method.releaseConnection();
		}

		return null;
	}

	public static Map<String, ProjectState> getStatus(MonitorConfiguration config, String view) throws Exception {
		String url = config.getURL() + HUDSON_VIEW_PART + view + HUDSON_URL_SUFFIX;

		Map<String, ProjectState> state = new HashMap<String, ProjectState>();

		Document doc = getUrlAsXML(config, url);
		if (doc == null) {
			return state;
		}

		Element result = doc.getRootElement();
		for (int i = 0; i < result.getChildCount(); i++) {
			Node child = result.getChild(i);
			Node name = ((Element) child).getFirstChildElement("name");
			Node color = ((Element) child).getFirstChildElement("color");

			if (name != null && color != null) {
				String col = color.getValue();
				State currStatus = State.FAIL;
				if (col.startsWith("blue")) {
					currStatus = State.OK;
				} else if (col.startsWith("yellow")) {
					currStatus = State.TESTFAIL;
				}

				boolean isBuilding = col.endsWith("_anime");

				state.put(name.getValue().trim(), new ProjectState(isBuilding, currStatus));
			}
		}

		return state;
	}

	public static void pracuj(MonitorConfiguration config, String lampa, String view, boolean failOnTest)
			throws Exception {
		Map<String, ProjectState> currState = getStatus(config, view);

		System.out.print("Doing request " + view + " ... ");

		boolean isOk = false;
		boolean isTestFail = false;
		boolean isFail = false;

		String failedProjects = "";
		String testFailedProjects = "";

		for (Map.Entry<String, ProjectState> projectState : currState.entrySet()) {
			String project = projectState.getKey();
			State state = projectState.getValue().getState();

			if (state == State.OK) {
				isOk = true;
			} else if (state == State.FAIL) {
				failedProjects += "[" + project + "] ";
				isFail = true;
			} else if (state == State.TESTFAIL) {
				testFailedProjects += "[" + project + "] ";
				isTestFail = true;
			}
		}

		if (isFail) {
			System.out.println("FAIL " + lampa + " " + failedProjects);
			Runtime.getRuntime().exec("./switch " + lampa + " fail");
		} else if (isTestFail) {
			System.out.println("TESTFAIL " + (failOnTest ? "(noTestFail) " : "") + lampa + " " + testFailedProjects);

			if (failOnTest) {
				Runtime.getRuntime().exec("./switch " + lampa + " testfail");
			} else {
				Runtime.getRuntime().exec("./switch " + lampa + " ok");
			}
		} else if (isOk) {
			System.out.println("OK " + lampa);
			Runtime.getRuntime().exec("./switch " + lampa + " ok");
		}
	}

	public static Collection<String> getViews(MonitorConfiguration config) throws Exception {
		String url = config.getURL() + HUDSON_URL_SUFFIX;
		Collection<String> views = new ArrayList<String>();

		Document doc = getUrlAsXML(config, url);

		if (doc != null) {

			Element result = doc.getRootElement();

			Elements el = result.getChildElements("view");
			for (int i = 0; i < el.size(); i++) {
				Element n = el.get(i);
				Node nameNode = n.getFirstChildElement("name");

				if (nameNode != null) {
					String name = nameNode.getValue();

					if (name.startsWith(config.getViewPrefix())) {
						views.add(name);
					}
				}
			}
		}

		return views;
	}

	public static void main(String[] args) throws Exception {
		MonitorConfiguration config = new MonitorConfiguration();

		config.setURL("https://hudson-url/hudson/");
		config.setUsername("test");
		config.setPassword("heslo");
		config.setViewPrefix("lampa-");
		config.setNoTestFailSuffix("-t");

		for (int i = 0; i < 500; i++) {

			Collection<String> views = getViews(config);
			for (String view : views) {
				String id = view.substring(config.getViewPrefix().length());

				boolean failOnTest = true;
				if (!config.getNoTestFailSuffix().isEmpty() && id.endsWith(config.getNoTestFailSuffix())) {
					failOnTest = false;
					id = id.substring(0, id.length() - config.getNoTestFailSuffix().length());
				}

				pracuj(config, id, view + "/", failOnTest);
			}

			/* wait some time */
			Thread.sleep(30 * 1000);
		}
	}
}

