package ca.uhn.fhir.tinder.parser;

import static org.apache.commons.lang3.StringUtils.isBlank;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.apache.maven.plugin.MojoFailureException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import ca.uhn.fhir.tinder.model.BaseElement;
import ca.uhn.fhir.tinder.model.Resource;
import ca.uhn.fhir.tinder.model.SearchParameter;
import ca.uhn.fhir.tinder.util.XMLUtils;

public class CompartmentParser {

	private String myVersion;
	private Resource myResourceDef;
	private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CompartmentParser.class);

	public CompartmentParser(String theVersion, Resource theResourceDef) {
		myVersion = theVersion;
		myResourceDef = theResourceDef;
	}
	
	public void parse() throws Exception {
		String resName = "/compartment/" + myVersion + "/compartments.xml";
		InputStream nextRes = getClass().getResourceAsStream(resName);
		if (nextRes == null) {
			throw new MojoFailureException("Unknown base resource name: " + resName);
		}

		ourLog.debug("Reading compartment file {}", resName);

		Document file;
		try {
			file = XMLUtils.parse(nextRes, false);
		} catch (Exception e) {
			throw new Exception("Failed during reading: " + resName, e);
		}

		Element resourcesSheet = null;
		for (int i = 0; i < file.getElementsByTagName("Worksheet").getLength() && resourcesSheet == null; i++) {
			resourcesSheet = (Element) file.getElementsByTagName("Worksheet").item(i);
			if (!"resources".equals(resourcesSheet.getAttributeNS("urn:schemas-microsoft-com:office:spreadsheet", "Name"))) {
				resourcesSheet = null;
			}
		}

		if (resourcesSheet == null) {
			throw new Exception("Failed to find worksheet with name 'Data Elements' in spreadsheet: " + resName);
		}

		Element table = (Element) resourcesSheet.getElementsByTagName("Table").item(0);
		NodeList rows = table.getElementsByTagName("Row");
		
		Map<Integer, String> col2compartment = new HashMap<Integer, String>();
		Element headerRow = (Element) rows.item(0);
		for (int i = 1; i < headerRow.getElementsByTagName("Cell").getLength(); i++) {
			Element cellElement = (Element) headerRow.getElementsByTagName("Cell").item(i);
			Element dataElement = (Element) cellElement.getElementsByTagName("Data").item(0);
			col2compartment.put(i, dataElement.getTextContent());
		}
		
		Element row = null;
		for (int i = 1; i < rows.getLength(); i++) {
			Element nextRow = (Element) rows.item(i);
			
			NodeList cells = nextRow.getElementsByTagName("Cell");
			Element cellElement = (Element) cells.item(0);
			Element dataElement = (Element) cellElement.getElementsByTagName("Data").item(0);
			if (dataElement.getTextContent().equals(myResourceDef.getName())) {
				row = nextRow;
				break;
			}
		}
		
		if (row == null) {
			ourLog.debug("No compartments for resource {}", myResourceDef.getName());
			return;
		}
		
		NodeList cells = row.getElementsByTagName("Cell");
		for (int i = 1; i < cells.getLength(); i++) {
			Element cellElement = (Element) cells.item(i);
			int index = i;
			if (cellElement.hasAttribute("Index")) {
				index = Integer.parseInt(cellElement.getAttribute("Index"));
			}
			
			String compartment = col2compartment.get(index);
			
			Element dataElement = (Element) cellElement.getElementsByTagName("Data").item(0);
			String namesUnsplit = dataElement.getTextContent();
			String[] namesSplit = namesUnsplit.split("\\|");
			for (String nextName : namesSplit) {
				nextName = nextName.trim();
				if (isBlank(nextName)) {
					continue;
				}
				
				String[] parts = nextName.split("\\.");
				if (parts[0].equals("{def}")) {
					continue;
				}
				Resource element = myResourceDef;
				SearchParameter sp = element.getSearchParameterByName(parts[0]);
				if (sp == null) {
					throw new MojoFailureException("Can't find child named " + parts[0] + " - Valid names: " + element.getSearchParameterNames());
				}
				
				sp.addCompartment(compartment);
			}
		}
	}
	
}
