package biotree;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;


//Need to add library

import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.json.simple.JSONObject;






public class WormsAPI {
	
	public static void main(String[] args) throws IOException, ParseException {
		//small test
		System.out.println(nameToID("Neogobius melanostomus"));
		/*
		TaxonNode[] taxnodes = idToClassification(126916);

		for (int i =0; i < taxnodes.length;i++) {
			System.out.println(taxnodes[i].getTaxonId());
			System.out.println(taxnodes[i].getTaxonType());
			System.out.println(taxnodes[i].getName());
		}
		*/
		
	}
	
	/**
	 * Search the WORMS database by scientific name to return Aphia (taxon) ID.
	 * This must be an exact name or it will fail. Use fuzzyNameToID if the name 
	 * is not exact.
	 * @param scientificName Scientific name of taxon (family, genus, species, etc)
	 * @return Aphia (taxon) ID of given scientific name.
	 * @throws IOException
	 */
	public static int nameToID(String scientificName) throws IOException{
		scientificName = repSpaces(scientificName);
		String resp = makeRequest(String.format("http://marinespecies.org/rest/AphiaIDByName/%s?marine_only=false", scientificName));
		
		return Integer.parseInt(resp);
	}
	
	/**
	 * Search the WORMS database by fuzzy scientific name (a slightly misspelled name).
	 * This has the advantage of being more flexible but it can be less accurate and it
	 * is slower. If you have the actual scientific name, use nameToID() instead.
	 * @param fuzzyName Fuzzy scientific name of taxon (family, genus, species, etc)
	 * @return Aphia (taxon) ID of given scientific name.
	 * @throws IOException
	 */
	public static int fuzzyNameToID(String fuzzyName) throws IOException{
		fuzzyName = repSpaces(fuzzyName);
		String resp = makeRequest(String.format("http://marinespecies.org/rest/AphiaRecordsByMatchNames?scientificnames%5B%5D=%s&marine_only=true", fuzzyName));
		
		//TODO: finish this function.
		return 123123;
	}
	
	/**
	 * Search by taxonId (AphiaID) and return bioclassification of that and above.
	 * 	
	 * /AphiaClassificationByAphiaID/{ID}
	 * @throws IOException 
	 * @throws ParseException 
	 */

	public static TaxonNode[] idToClassification(int taxonId) throws IOException, ParseException {
		String resp = makeRequest(String.format("http://marinespecies.org/rest/AphiaClassificationByAphiaID/%d", taxonId));
		JSONParser parser = new JSONParser();
		JSONObject json = (JSONObject) parser.parse(resp);
		
		//Assume length of 8 based on number of taxontypes
		TaxonNode[] taxnodes = new TaxonNode[8];
		int arraysize = parseIdCall(taxnodes,json,0); 
		TaxonNode[] copiedArray = new TaxonNode[arraysize];

		System.arraycopy(taxnodes, 0, copiedArray, 0, arraysize);
		
		return copiedArray;
		
	}
	
	
	
	/**
	 * Perform a GET request to the given URL and return the content of the response.
	 * @param url The URL to which to make a request.
	 * @return The content returned by the server (if successful).
	 * @throws IOException
	 */
	private static String makeRequest(String url) throws IOException {
		//Request method adapted from http://www.baeldung.com/java-http-request
		//create new URL instance
		URL urll = new URL(url);
		//create and set up connection
		HttpURLConnection con = (HttpURLConnection) urll.openConnection();
		con.setRequestMethod("GET");
		
		int status = con.getResponseCode();
		
		BufferedReader in = new BufferedReader(
				  new InputStreamReader(con.getInputStream()));
		String inputLine;
		StringBuffer content = new StringBuffer();
		while ((inputLine = in.readLine()) != null) {
		    content.append(inputLine);
		}
		in.close();
		con.disconnect();
		
		return content.toString();
	}
	
	/**
	 * Helper to replace a space with the correct one for URLs.
	 * @param in Input string
	 * @return String with spaces replaced by "%20" for spaces in URLs.
	 */
	private static String repSpaces(String in) {
		return in.replaceAll(" ", "%20");
	}

	/**
	 * Parses the json request recursively and also keeping track of the array length
	 * @param nodes the TaxonNode array
	 * @param current current rank level of JSON file
	 * @param n index of where the TaxonNode is being stored at 
	 * @return arraysize number of elements added within array
	 */
	private static int parseIdCall(TaxonNode[] nodes,JSONObject current,int n) {
		boolean checktype = false;
		TaxonNode curNode = null;
		int arraysize = n;
		//Checks if rank matches the TaxonType Enum
		for (TaxonType c : TaxonType.values()) {
			
	        if (c.name().equals((String)current.get("rank"))) {
	            checktype= true;
	            break;
	        }
	        else checktype = false;
	    }
		JSONObject child = (JSONObject) current.get("child");
		
		if (checktype == true) {
			curNode = new TaxonNode((long) current.get("AphiaID"),TaxonType.valueOf((String) current.get("rank")) ,(String) current.get("scientificname"));
			nodes[n]= curNode;
			n++;
		}
		//If child is null, return 
		if ((JSONObject) current.get("child") == null ) 
			return n;
		arraysize = parseIdCall(nodes, child, n);
		return arraysize;
	}
	
}