package com.bayer.edam.migration.mam.categories;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.univocity.parsers.csv.CsvParser;
import com.univocity.parsers.csv.CsvParserSettings;

/**
 * Reads the MAM categories (https://service.media-assistant.animalhealth.bayer.com/rest/migration/category) from a JSON file and converts
 * them into a tree structure.
 */
public class CategoryTree {
	
	private static final Logger log = LoggerFactory.getLogger(CategoryTree.class);
	
	public static class Node implements Comparable<Node> {
		public int id;
		public String name;
		public Node parent;
		public int parentId;
		public List<Node> children = new ArrayList<Node>();
		
		public String action;
		public String parameter;
		
		@Override
		public int compareTo(Node o) {
			return this.name.compareTo(o.name);
		}
		
	}
	
	static class JsonCategory {
		public int id;
		public int parent;
		public Map<String, String> name;
		
		public JsonCategory() {}
	}
	
	static class JsonCategoryList {
		public List<JsonCategory> nodes;
		
		public JsonCategoryList() {}
	}
	
	
	public HashMap<Integer, Node> nodeMap = new HashMap<Integer, Node>();
	public Node root; // technical root
	public static int ROOT_NODE_ID = 1; // ID of logical root "Intern"
	
	public CategoryTree(String jsonFile, String mappingsFile) throws IOException {
		log.info("Reading categories from file " + jsonFile);
		readTree(jsonFile);
		
		log.info("Reading category mappings from file " + mappingsFile);
		readMappings(mappingsFile);
		
//		printTree();
	}
	
	public Node getNode(int id) {
		return nodeMap.get(id);
	}
	
	private void readMappings(String mappingsFile) {
		CsvParserSettings parserSettings = new CsvParserSettings();
		parserSettings.getFormat().setLineSeparator("\r\n");
		parserSettings.getFormat().setDelimiter(';');
		parserSettings.getFormat().setCharToEscapeQuoteEscaping('"');
		parserSettings.setHeaderExtractionEnabled(false);

		CsvParser parser = new CsvParser(parserSettings);

		List<String[]> inputRows = parser.parseAll(new File(mappingsFile));
		int rowNum = 0;
		String[] currentPath = new String[7];
		for (String[] row : inputRows) {
			rowNum++;
			
			if (row[0] == null || row[0].equals("Action")) {
				log.info(rowNum + " - skipping, first cell ist empty or heading");
				continue;
			}
			
			int rowLevel = 3;
			while (row[rowLevel] == null)
				rowLevel++;
			rowLevel = rowLevel - 3;
			
			if (currentPath[rowLevel] != null) {
				for (int i = rowLevel; i < currentPath.length; i++)
					currentPath[i] = null;
			}
			currentPath[rowLevel] = row[rowLevel + 3].trim();
			
			/* // print node
			int i = 1;
			System.out.print("[" + currentPath[0]);
			while (i < currentPath.length && currentPath[i] != null) {
				System.out.print(", " + currentPath[i]);
				i++;
			}
			System.out.println("]");
			*/
			
			Node node = getNode(currentPath);
			
			node.action = row[0];
			node.parameter = row[1];
			
		}
		
	}


	private Node getNode(String[] currentPath) {
		Node currentNode = nodeMap.get(ROOT_NODE_ID);
		
		int level = 0;
		while (level < currentPath.length && currentPath[level] != null) {
			
			Node next = null;
			
			for (Node node : currentNode.children) {
				if (node.name.equals(currentPath[level])) {
					next = node;
					break;
				}
			}
			
			if (next == null) {
				String path = "[" + currentPath[0];
				int i = 1;
				while (i < currentPath.length && currentPath[i] != null) {
					i++;
					path += ", " + currentPath[i] ;
				}
				path += "]";
				
				log.error("No match for " + path);
				break;
			}

			currentNode = next;
			level++;
		}
		
		return currentNode;
	}

	private void readTree(String jsonFile) throws IOException {
		ObjectMapper jsonMapper = new ObjectMapper();
		
		JavaType type = jsonMapper.getTypeFactory().constructCollectionType(List.class, JsonCategory.class);
		List<JsonCategory> categoryList = jsonMapper.readValue(new File(jsonFile), type);
		
		for (JsonCategory cat : categoryList) {
			Node node = new Node();
			node.id = cat.id;
			node.parentId = cat.parent;
			node.name = cat.name.get("en");
			if (node.name != null)
				node.name = node.name.trim();
			nodeMap.put(node.id, node);
			
			if (cat.id == 0) {
				root = node;
			}
		}
		
		for (Entry<Integer,Node> entry : nodeMap.entrySet()) {
			Node node = entry.getValue();
			node.parent = nodeMap.get(node.parentId);
			
			if (node != node.parent) {
				node.parent.children.add(node);
			}
		}
	}
	
	private void printTree() {
		Node startNode = nodeMap.get(ROOT_NODE_ID);
		java.util.Collections.sort(startNode.children);
		for (Node node : startNode.children) {
			iterate(node, 0);
		}
	}
	
	private void iterate(Node node, int depth) {
		for (int i = 0; i < depth; i++) {
			System.out.print(";");
		}
		System.out.println(node.name + ": " + node.action + ", " + node.parameter);
		
		if (node.children.size() > 0) {
			java.util.Collections.sort(node.children);
			for (Node child : node.children) {
				iterate(child, depth+1);
			}
		}
	}

	public static void main(String[] args) {
		try {
			new CategoryTree("C:\\Users\\gexce\\git\\mam-migration\\AH MAM Migration\\resources\\2017-10-19_categories.json", "C:\\Users\\gexce\\git\\mam-migration\\AH MAM Migration\\resources\\Media_Assistant_Categories_131017_EDITED.csv");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
}
