package org.biomoby.registry.rdfagent.verifier;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.biomoby.client.CentralImpl;
import org.biomoby.registry.rdfagent.util.CentralDataAccess;
import org.biomoby.registry.rdfagent.util.CentralDataAccessImpl;
import org.biomoby.registry.rdfagent.util.Constants;
import org.biomoby.registry.rdfagent.util.Log;
import org.biomoby.shared.Central;
import org.biomoby.shared.MobyException;
import org.biomoby.shared.MobyService;

/**
 * The point of entry for the RDF agent.
 * 
 * @author Edward Kawas
 * 
 */
@SuppressWarnings("unchecked")
public class Main {

	private static String newline = System.getProperty("line.separator");

	private static HashMap map = new HashMap();

	/**
	 * 
	 * @param key
	 *            the url to obtain a test result from
	 * @return the test result obtained using the url
	 */
	public static String getTestString(String key) {
		if (map.containsKey(key)) {
			return (String) map.remove(key);
		}
		return "";
	}

	/**
	 * 
	 * @param args
	 *            can either be:
	 *            <p>
	 *            an empty string array - agent will look into the registry
	 *            specfied in the config file and process services found
	 *            <p>
	 *            -file <file> - agent will parse the newline delimited file of
	 *            urls and process any services found in the RDF documents found
	 *            at those urls with the registry specified in the config file
	 *            <p>
	 *            -url <url> agent will perform a HTTP GET on the url and
	 *            process any services found in the RDF document found at that
	 *            url. All services found will be told that their signature URL
	 *            is at this location.
	 *            <p>
	 *            -test <url> agent will perform a HTTP GET on the url and parse
	 *            any rdf document located at the url. The agent will then send
	 *            a message to the invoker of the agent. The invoker is assumed
	 *            to have the email address contained in the RDF
	 */
	public static void main(String[] args) {

		// parse any arguments
		if (args.length != 0 && args.length != 2)
			usage();

		boolean useFile = false;
		boolean useURL = false;
		boolean useTest = false;
		String url = "", file = "";
		if (args.length == 2) {
			if (args[0].equals("-file")) {
				useFile = true;
				file = args[1].trim();
				System.err.close();
			} else if (args[0].equals("-url")) {
				useURL = true;
				url = args[1].trim();
				System.err.close();
			} else if (args[0].equals("-test")) {
				System.setErr(System.out);
				useTest = true;
				url = args[1].trim();
			} else {
				usage();
			}
		}

		// create a logger

		Log.start(Constants.LOGFILE_PATH, Constants.LOG_LEVEL, Constants.LOG_ENABLE,
				"RDFAgent Started on " + (new Date()).toString());
		if (useFile) {
			// file based
			processFile(file);
			Log.stop("RDFAgent Stopped on " + (new Date()).toString());
		} else if (useURL) {
			// url based
			int ret = processURL(url);
			Log.info("exit code: " + ret);
			Log.stop("RDFAgent Stopped on " + (new Date()).toString());
			System.exit(ret);
		} else if (useTest) {
			String str = processTest(url);
			map.put(url, str);
			Log.stop("RDFAgent Stopped on " + (new Date()).toString());
		} else {
			// registry based
			processRegistry();
			Log.stop("RDFAgent Stopped on " + (new Date()).toString());
		}
		// stop the logging

		System.exit(0);
	}

	/*
	 * a test process
	 */
	private static String processTest(String url) {
		StringBuffer sb = new StringBuffer();
		sb.append("TEST: Processing URL " + url + "." + System.getProperty("line.separator"));
		Log.info("TEST: Processing URL " + url + ".");
		Processor processor = new Processor();
		sb.append("TEST: Agent will attempt to process the URL: " + url + " now."
				+ System.getProperty("line.separator"));
		Log.info("TEST: Agent will attempt to process the URL: " + url + " now.");
		sb.append(processor.processServicesFromUrlTEST(url) + System.getProperty("line.separator"));
		sb.append("Agent has completed processing the URL." + System.getProperty("line.separator"));
		Log.info("Agent has completed processing the URL.");
		return sb.toString();
	}

	private static void usage() {
		System.out.println("usage: java Main [-file filename | -url www.someURL.com]");
		System.out
				.println("\t-file filename -> process a new line delimited list of signature urls");
		System.out.println("\t-url www.someURL.com -> process a signature url");
		System.out.println("\t-test www.someURL.com -> test the agent on a url");
		System.out
				.println("Note: Invoking without arguments causes the agent to process a registry defined in the config.xml file");
		System.exit(1);
	}

	private static void processFile(String file) {
		// find services containing the newline separated signature urls
		// for each url in file, call processServicesFromURL(url);
		try {

			BufferedReader fileReader = new BufferedReader(new FileReader(file));
			String url;
			while ((url = fileReader.readLine()) != null) {
				/* PRECONDITION: each line is a signatureURL */
				processURL(url);
			}
			fileReader.close();
		} catch (IOException e) {
			Log.exception("org.registry.rdfagent.verifier.Main", "processFile(String)", e);
			Log.severe(e.getMessage());
			return;
		}
	}

	private static int processURL(String url) {
		Log.info("Processing URL " + url + ".");
		Central central = null;
		try {
			Log.info("Connecting to mobycentral (" + Constants.REGISTRY_URL + ","
					 + Constants.REGISTRY_URI + ").");
			central = new CentralImpl(Constants.REGISTRY_URL, Constants.REGISTRY_URI);
			Log.info("Connection made to mobycentral complete.");
		} catch (MobyException e) {
			Log.exception("org.registry.rdfagent.verifier.Main", "processURL(String)", e);
			Log.severe(e.getMessage());
			return 11;
		}
		Processor processor = new Processor();
		Log.info("Agent will attempt to process the URL: " + url + " now.");
		int returnValue = processor.processServicesFromURL(url, central);

		// if the url had issues, then it would have been added to the
		// validation table we will remove it
		try {
			CentralDataAccess cda = new CentralDataAccessImpl();
			cda.deleteErrorCountForURL(url);
			cda.cleanup();
		} catch (MobyException e) {
			return 12;
		}

		if (returnValue != 0 )
			return returnValue;
		
		Log.info("Agent has completed processing the URL.");
		return 0;
	}

	private static void processRegistry() {
		Log.info("Processing all services from the registry.");
		CentralImpl central = null;
		try {
			Log.info("Connecting to mobycentral (" + Constants.REGISTRY_URL + ","
					+ System.getProperty("line.separator") + "\t" + Constants.REGISTRY_URL + ").");
			central = new CentralImpl(Constants.REGISTRY_URL, Constants.REGISTRY_URI);
			Log.info("Connection made to mobycentral complete.");
		} catch (MobyException e) {
			Log.exception("org.registry.rdfagent.verifier.Main", "processRegistry()", e);
			Log.severe(e.getMessage());
			return;
		}

		MobyService[] services = null;
		try {
			Log.info("Getting all services from the registry. Will take some time.");
			MobyService __template__ = new MobyService();
			__template__.setCategory("");
			services = central.findService(__template__);
			__template__ = null;
			Log.info("Successfully retrieved all services from the registry.");
		} catch (MobyException e) {
			Log.exception("org.registry.rdfagent.verifier.Main", "processRegistry()", e.getCause());
			Log
					.severe("There was a problem connecting to the registry and performing a findservice call."
							+ newline
							+ "Make sure that the url is reachable and that the registry is online. Exact message:"
							+ newline + e.getMessage());
			return;
		}

		Log.info("Processing services");
		// create a map of auth,name => MobyService
		Map serviceMap = Collections.synchronizedMap(new HashMap());
		for (int i = 0; i < services.length; i++) {
			serviceMap.put(services[i].getAuthority() + "," + services[i].getName(), services[i]);
		}

		Processor processor = new Processor();
		try {
			Log.info("Agent will start processing the services now.");
			processor.processRegistryServices(serviceMap, new CentralImpl(Constants.REGISTRY_URL,
					Constants.REGISTRY_URI));
		} catch (MobyException e) {
			Log.exception("org.registry.rdfagent.verifier.Main", "processRegistry()", e);
			Log.severe(e.getMessage());
			return;
		}
		Log.info("Agent has processed all services that it has found in the registry.");
	}
}