package eu.dnetlib.data.claims.utils;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.Timestamp;
import java.util.Date;

/**
 * Created by argirok on 20/11/2015.
 */
/*
*Search and Parsing xmls from Search Service
*Search for DOIs
*
 */
public class SearchUtils {
    private static final Logger logger = LogManager.getLogger(SearchUtils.class);
    public static String searchAPIUrl=null;//"http://beta.services.openaire.eu:8480/search/";
    public static String newJsonSearchAPIUrl=null;//"http://beta.services.openaire.eu:8480/search/";
    public static String  newJsonSearchOrganizationAPIUrl = null;
    private static String crossrefUrl=null;
    private static String dataciteUrl=null;
    private static String orcidUrlPrefix=null;
    private static String orcidUrlSuffix=null;
    private static String contextsAPIUrl=null;
    private ClaimValidation claimValidation = null;

    public SearchUtils(){

    }
    public String fetchResultById(String id, String type) throws Exception {
        String json =null;
        String requestUrl = newJsonSearchAPIUrl;
        if(type.equals(ClaimUtils.SOFTWARE) ) {
            requestUrl += "software/" + id;

        }else if(type.equals(ClaimUtils.DATASET)){
            requestUrl += "datasets/" + id;
        }else if (type.equals(ClaimUtils.OTHER)){
            requestUrl += "other/" + id;
        }else{
            requestUrl += "publications/" + id;
        }
        requestUrl +=  "?format=json";
        json = getRequest(requestUrl);
        if (json == null) {
            requestUrl =newJsonSearchAPIUrl +  "datasets/" + id + "?format=json";
            json = getRequest(requestUrl);
        }
        if(json == null){
            return null;
        }
        return json;
    }

    public String fetchProjectById(String id) throws Exception {
        String json = getRequest(newJsonSearchAPIUrl+"projects/" +id + "?format=json");

        if (json == null) {
            return null;
        }
        return json;
    }

    public String fetchOrganizationById(String id) throws Exception {
        String json = getRequest((newJsonSearchOrganizationAPIUrl != null?newJsonSearchOrganizationAPIUrl:newJsonSearchAPIUrl)+"organizations/" +id + "?format=json");
        System.out.println(json);

        if (json == null) {
            return null;
        }
        return json;
    }

    public String fetchProjectXmlFromIndex(String id) throws Exception{
            return getRequest(getProjectApiUrl(id));
    }
    public String fetchOrganizationXmlFromIndex(String id) throws Exception{
        return getRequest(getOrganizationApiUrl(id));
    }
    /**
     *Look up in API, if there is no result,
     * consider that id is a dedup id and search for the objIdentifier id.
     * Then look up again in the API with the objIdentifier
     * @param id
     * @return xml or null
     * @throws Exception
     */
    public static String fetchPublicationXmlFromIndex(String id) throws Exception{

        String xml=getRequest(getPublicationApiUrl(id));
        if(getNumberOfResultsInAPIXML(xml)==0){
            xml=null;
        }
        return xml;
    }

    public static String fetchSoftwareXmlFromIndex(String id) throws Exception{
        String xml=getRequest(getSoftwareApiUrl(id));
         return xml;
    }

    public static String fetchOtherXmlFromIndex(String id) throws Exception{
        String xml=getRequest(getOtherApiUrl(id));
        return xml;
    }
    /**
     *Look up in API, if there is no result,
     * consider that id is a dedup id and search for the objIdentifier id.
     * Then look up again in the API with the objIdentifier
     *
     * @param id
     * @return xml
     * @throws Exception
     */
    public String fetchDatasetXmlFromIndex(String id) throws Exception{

        String xml=getRequest(getDatasetApiUrl(id));
        if(getNumberOfResultsInAPIXML(xml)==0){
            xml=null;
        }
        return xml;

    }

    public String fetchResultXMLFromDatacite(String id) throws Exception{
            return getRequest(getDataciteUrl(id));
    }
    public String fetchResultXMLFromOrcid(String id) throws Exception{

            return getRequest(getOrcidUrl(id.substring(0, 19), id.substring( 20)));
    }
    public String fetchContext(String suffix) throws Exception{

        return getRequest(getContextsAPIUrl()+suffix);
    }

     public String getProjectApiUrl(String id)  {

        return searchAPIUrl+"api/projects?openaireProjectID="+id;
    }
    public String getOrganizationApiUrl(String id)  {

        return searchAPIUrl + "v2/api/organizations/" +id;
    }
    public String getDatasetApiUrl(String id)  {

        return searchAPIUrl+"api/datasets?openaireDatasetID="+id;
    }

    public static String getPublicationApiUrl(String id)  {

        return searchAPIUrl+"api/publications?openairePublicationID="+id;
    }
    public static String  getSoftwareApiUrl(String id)  {
        return searchAPIUrl+"api/software?openaireSoftwareID="+id;
    }
    public static String  getOtherApiUrl(String id)  {
        return searchAPIUrl+"api/other?openaireOtherID="+id;
    }

    private static String getDataciteUrl(String id)  {

        return dataciteUrl+id;
    }

    private static String getOrcidUrl(String id, String putcode)  {

        return orcidUrlPrefix+id+orcidUrlSuffix+putcode;
    }
    private static String getContextsAPIUrl()  {

        return contextsAPIUrl;
    }


    // HTTP GET request
    private static String getRequest(String url) throws Exception {
        URL obj = new URL(url);
        logger.debug(url);
        System.out.println(url);
        HttpURLConnection con = (HttpURLConnection) obj.openConnection();
        int responseCode = con.getResponseCode();
        if(responseCode != 200){
            return null;
        }
        BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
        StringBuffer response = new StringBuffer();
        String inputLine;
        while ((inputLine = in.readLine()) != null) {
            response.append(inputLine).append("\n");
        }
        in.close();
        return response.toString();
    }

    public static String getCrossrefJsonRecord(String doi){
        String url=crossrefUrl+doi;
        URL obj = null;
        String responseStr=null;
        try {
            obj = new URL(url);
            HttpURLConnection con = (HttpURLConnection) obj.openConnection();
            BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
            StringBuffer response = new StringBuffer();
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine).append("\n");
            }
            in.close();
            responseStr=response.toString();
            if(responseStr==null||(!responseStr.contains("\"status\":\"ok\"")||!(responseStr.contains("\"DOI\":\"")))){
                responseStr=null;
            }
        } catch (Exception e) {
            try{
                PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("dois_malformed_urls.txt", true)));
                Date date= new java.util.Date();
                out.println(new Timestamp(date.getTime())+"Doi:"+doi+" Url:"+url);
                out.close();

            }catch (IOException e1) {
                logger.error("Couldn't write to file " + "dois_malformed_urls.txt",e);
            }

        }
        return responseStr;
    }

    /**
     *
     * @param doi
     * @return true  if the given doi request returns a valid answer otherwise false
     * @throws IOException
     */
     public static boolean isDoiValid(String doi) throws IOException {
            boolean found=false;
            String responseStr=getCrossrefJsonRecord(doi);
             if(responseStr!=null){
                found=true;
            }
            return found;
    }

    /**
     *
     * @param xml : API result xml
     * @return number of results Found
     * @throws Exception
     */
    public static Integer getNumberOfResultsInAPIXML(String xml) throws Exception {
        if(xml==null){
            return 0;
        }
        String totalStr=null;
        Integer total=0;
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        InputSource inputSource= new InputSource(new StringReader(xml));
        Document document=dBuilder.parse(inputSource);
        XPathFactory xPathfactory= XPathFactory.newInstance();
        XPath xpath = xPathfactory.newXPath();
        NodeList nl = (NodeList) xpath.compile("//total/text()").evaluate(document, XPathConstants.NODESET);
        if (nl.getLength() > 0) {
            totalStr= nl.item(0).getNodeValue();
        }
        if(totalStr!=null){
            total=Integer.parseInt(totalStr);
        }
        return total;
    }

    public ClaimValidation getClaimValidation() {
        return claimValidation;
    }

    public void setClaimValidation(ClaimValidation claimValidation) {
        this.claimValidation = claimValidation;
    }

    public String getSearchAPIUrl() {
        return searchAPIUrl;
    }

    public void setSearchAPIUrl(String searchAPIUrl) {
        this.searchAPIUrl = searchAPIUrl;
    }

    public static void setContextsAPIUrl(String contextsAPIUrl) {
        SearchUtils.contextsAPIUrl = contextsAPIUrl;
    }

    public static String getCrossrefUrl() {
        return crossrefUrl;
    }

    public static void setCrossrefUrl(String crossrefUrl) {
        SearchUtils.crossrefUrl = crossrefUrl;
    }

    public static String getDataciteUrl() {
        return dataciteUrl;
    }

    public static void setDataciteUrl(String dataciteUrl) {
        SearchUtils.dataciteUrl = dataciteUrl;
    }

    public static String getOrcidUrlPrefix() {
        return orcidUrlPrefix;
    }

    public static void setOrcidUrlPrefix(String orcidUrlPrefix) {
        SearchUtils.orcidUrlPrefix = orcidUrlPrefix;
    }

    public static String getOrcidUrlSuffix() {
        return orcidUrlSuffix;
    }

    public static void setOrcidUrlSuffix(String orcidUrlSuffix) {
        SearchUtils.orcidUrlSuffix = orcidUrlSuffix;
    }

    public static String getNewJsonSearchAPIUrl() {
        return newJsonSearchAPIUrl;
    }

    public static void setNewJsonSearchAPIUrl(String newJsonSearchAPIUrl) {
        SearchUtils.newJsonSearchAPIUrl = newJsonSearchAPIUrl;
    }

    public static String getNewJsonSearchOrganizationAPIUrl() {
        return newJsonSearchOrganizationAPIUrl;
    }

    public static void setNewJsonSearchOrganizationAPIUrl(String newJsonSearchOrganizationAPIUrl) {
        SearchUtils.newJsonSearchOrganizationAPIUrl = newJsonSearchOrganizationAPIUrl;
    }
}


