package eu.dnetlib.data.mdstore.modular;

import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import static eu.dnetlib.data.mdstore.modular.MDStoreConstants.*;

/**
 * This method outperforms SimpleRecordParser by a vast amount, especially since we are just getting stuff in the
 * header.
 * 
 * @author marko
 * 
 */
public class StreamingRecordParser implements RecordParser {

	private static final Log log = LogFactory.getLog(StreamingRecordParser.class);
	private long ts;

	@Override
	public Map<String, String> parseRecord(String record) {

		try {
			XMLInputFactory factory = XMLInputFactory.newInstance();
			XMLStreamReader parser = factory.createXMLStreamReader(new ByteArrayInputStream(record.getBytes()));

			HashMap<String, String> res = new HashMap<String, String>();
			res.put(TIMESTAMP, String.valueOf(getTimestamp()));

			Stack<String> elementStack = new Stack<String>();
			elementStack.push("/");

			while (parser.hasNext()) {
				int event = parser.next();

				if (event == XMLStreamConstants.END_ELEMENT) {
					elementStack.pop();
				} else if (event == XMLStreamConstants.START_ELEMENT) {
					final String localName = parser.getLocalName();
					elementStack.push(localName);

					if (OBJIDENTIFIER.equals(localName)) {
						parser.next();

						res.put(ID, parser.getText().trim());

					} else if ("identifier".equals(localName) && "efgEntity".equals(grandParent(elementStack))) {
						if (!res.containsKey("originalId")) {
							parser.next();
//							log.info("ZZZZZZ OK: found identifier at right depth " + elementStack);
							res.put("originalId", parser.getText().trim());
						}
					}

					else if ("identifier".equals(localName)) {

//						log.info("ZZZZZZ: found identifier not at right depth " + elementStack + " grand parent " + grandParent(elementStack));
					}

					if (res.containsKey(ID) && res.containsKey("originalId"))
						return res;
				}
			}
			return res;
		} catch (XMLStreamException e) {
			throw new IllegalStateException(e);
		}

	}

	private String grandParent(Stack<String> elementStack) {
		if (elementStack.size() <= 3)
			return "";
		return elementStack.get(elementStack.size() - 3);
	}

	@Override
	public void setTimestamp(final long ts) {
		this.ts = ts;
		log.debug("RecordParser date set to "+ts);
	}

	@Override
	public long getTimestamp() {
		return ts;
	}

}
