package eu.dnetlib.dli.resolver;

import com.google.common.collect.Lists;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import eu.dnetlib.dli.resolver.model.DLIObjectProvenance;
import eu.dnetlib.dli.resolver.model.DLIResolvedObject;
import eu.dnetlib.pid.resolver.model.ObjectType;
import eu.dnetlib.pid.resolver.AbstractPIDResolver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.List;

/**
 * @author sandro
 */
public class PubMedResolver extends AbstractPIDResolver {

	private static final Log log = LogFactory.getLog(PubMedResolver.class); // NOPMD by marko on 11/24/08 5:02 PM

	private static final String query = "http://www.ebi.ac.uk/europepmc/webservices/rest/search/query=%s&format=json";

	private static final String PUBMED_NS_PREFIX = "pubmed______";

	@Override
	protected boolean canResolvePid(final String pidType) {
		return pidType != null && (pidType.toLowerCase().trim().equals("pubmedid") || pidType.toLowerCase().trim().equals("pmcid"));
	}

	@Override
    protected DLIResolvedObject resolve(final String pid, final String pidType) {
        String requestUrl = null;
		String type = null;
		if (pidType.toLowerCase().trim().equals("pubmedid")) {
			requestUrl = String.format(query, "ext_id:" + pid);
			type = "pubmedid";
		} else if (pidType.toLowerCase().trim().equals("pmcid")) {
			requestUrl = String.format(query, "pmcid:" + pid);
			type = "pmcid";
		}
		if (requestUrl == null)
			return null;
		try {
			String result = requestURL(requestUrl);

			return parsingResponse(result, type);
		} catch (Throwable e) {
			log.error(String.format("Error on resolving pid %s type:%s requestUrl:%s", pid, pidType, requestUrl), e);
		}
		return null;
	}

    private DLIResolvedObject parsingResponse(final String response, final String type) {
        if (response == null) return null;
		JsonElement jElement = new JsonParser().parse(response);
		JsonObject jobject = jElement.getAsJsonObject();
		if (jobject.has("hitCount")) {

			long total = jobject.get("hitCount").getAsLong();

			if (total == 0) return null;
            DLIResolvedObject responseObj = new DLIResolvedObject();

			JsonElement hits = ((JsonObject) jobject.get("resultList")).get("result");

			JsonArray hitsObject = hits.getAsJsonArray();

			for (JsonElement elem : hitsObject) {
                String idType;
                if (type.equals("pmcid")) {
					idType = type;
				} else {
					idType = "pmid";
				}

                if (!((JsonObject) elem).has(idType)) {
                    continue;
                }

				String doi = ((JsonObject) elem).get(idType).getAsString();
				responseObj.setPid(doi);
				responseObj.setPidType(type);
				responseObj.setType(ObjectType.publication);
				List<String> authors = Lists.newArrayList();
				List<String> titles = Lists.newArrayList();

				// ADDING TITLES
				JsonElement titleElement = ((JsonObject) elem).get("title");
				if (titleElement != null) {
					String titleString = titleElement.getAsString();
					titles.add(titleString);
				}
				responseObj.setTitles(titles);
				// ADDING AUTHORS
				JsonElement contributorElement = ((JsonObject) elem).get("authorString");
				if (contributorElement != null) {
					String contributorString = contributorElement.getAsString();
					if (contributorString != null) {
						String[] splittedAuthors = contributorString.split(",");

						for (int i = 0; i < splittedAuthors.length; i++) {
							authors.add(splittedAuthors[i]);
						}
					}
				}
				responseObj.setAuthors(authors);

				JsonElement date = ((JsonObject) elem).get("pubYear");

				if (date.isJsonNull() == false) {
					responseObj.setDate(date.getAsString());
				}
                DLIObjectProvenance provenance = new DLIObjectProvenance(PUBMED_NS_PREFIX, "resolved", "complete", null, null, true);
                responseObj.fixContribution(provenance);
				responseObj.setDatasourceProvenance(Lists.newArrayList(provenance));
				return responseObj;

			}

			return null;
		}
		return null;

	}
}
