package eu.dnetlib.functionality.index.cql;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.z3950.zing.cql.CQLAndNode;
import org.z3950.zing.cql.CQLBooleanNode;
import org.z3950.zing.cql.CQLNode;
import org.z3950.zing.cql.CQLPrefixNode;
import org.z3950.zing.cql.CQLTermNode;
import org.z3950.zing.cql.ModifierSet;

public class CqlGroup {

	public static final String defaultTerm = "cql.filtered";

	public Map<String, CQLNode> group(final CQLNode node, final List<String> fields) {
		return node != null ? doGroup(node, fields, new HashMap<String, CQLNode>()) : new HashMap<String, CQLNode>();
	}

	private Map<String, CQLNode> doGroup(CQLNode node, List<String> fields, Map<String, CQLNode> groups) {
		if (node instanceof CQLBooleanNode) {
			return doGroup((CQLBooleanNode) node, fields, groups);
		}

		if (node instanceof CQLTermNode) {
			return doGroup((CQLTermNode) node, fields, groups);
		}

		if (node instanceof CQLPrefixNode) {
			return groups;
		}

		throw new RuntimeException("error choice for node instanceof " + node.getClass());
	}

	private Map<String, CQLNode> doGroup(CQLBooleanNode node, List<String> fields, Map<String, CQLNode> groups) {

		doGroup(node.left, fields, groups);
		doGroup(node.right, fields, groups);

		return groups;
	}

	private static Map<String, CQLNode> doGroup(CQLTermNode node, List<String> fields, Map<String, CQLNode> groups) {

		if (isTermNodeToGroup(node, fields)) {
			String term = node.getIndex().toLowerCase();

			if (groups.get(term) == null) {
				groups.put(term, node);
			}

			CQLNode group = groups.get(term);
			CQLAndNode andNode = new CQLAndNode(group, node, new ModifierSet("and"));

			if (!groups.containsValue(node)) {
				groups.put(term, andNode);
			}
		}

		return groups;
	}

	private static boolean isTermNodeToGroup(CQLTermNode node, List<String> fields) {
		return fields.contains(node.getIndex().toLowerCase());
	}

}
