package eu.dnetlib.data.claims.parser;

import eu.dnetlib.data.claims.entity.Organization;
import eu.dnetlib.data.claims.entity.Project;
import eu.dnetlib.data.claims.entity.Result;
import eu.dnetlib.data.claims.utils.ClaimUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;

/**
 * Created by kiatrop on 5/2/2016.
 */
public class OafParser {
    /**
     * For external url: returns http://dx.doi.org/ +doi else the first url from websource
     *
     * @param oaf
     * @return
     * @throws ParserConfigurationException
     * @throws IOException
     * @throws SAXException
     * @throws XPathExpressionException
     * @throws TransformerException
     */

    private static final Logger logger = LogManager.getLogger(OafParser.class);

    public static Result oaf2Result(String oaf) throws ParserConfigurationException, IOException, SAXException, XPathExpressionException, TransformerException {
        Result result = null;
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        InputSource is = new InputSource(new StringReader(oaf));
        Document document= dBuilder.parse(is);
        XPathFactory xPathfactory= XPathFactory.newInstance();
        XPath xpath = xPathfactory.newXPath();

        String size = null;
        NodeList nl = (NodeList) xpath.compile("/response/header/total/text()").evaluate(document, XPathConstants.NODESET);
        if (nl.getLength() > 0) {
            size= nl.item(0).getNodeValue();
        }else{
            nl = (NodeList) xpath.compile("//objIdentifier/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
//                result.setOpenaireId(nl.item(0).getNodeValue());
                size="1";
            }
        }
        if(size!=null && Integer.parseInt(size)>0){
            result = new Result();
            nl = (NodeList) xpath.compile("//objIdentifier/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setOpenaireId(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//resulttype/@classid").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setResultType(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//bestlicense/@classid").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setBestLicense(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//bestaccessright/@classid").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setBestLicense(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//embargoenddate/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setEmbargoEndDate(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//title/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setTitle(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//pid[@classid='doi']/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setDoi(nl.item(0).getNodeValue());
                result.setExternalUrl("http://dx.doi.org/" + result.getDoi());
            }
            if(result.getExternalUrl()==null){
//                nl = (NodeList) xpath.compile("//webresource/url/text()").evaluate(document, XPathConstants.NODESET);
//                if (nl.getLength() > 0) {
//                    result.setExternalUrl(nl.item(0).getNodeValue());
//                }
                nl = (NodeList) xpath.compile("//children/instance/licence[@classid='OPEN']").evaluate(document, XPathConstants.NODESET);
                if (nl.getLength() > 0) {
                    NodeList list = (NodeList) xpath.compile("./webresource/url/text()").evaluate(nl.item(0).getParentNode(), XPathConstants.NODESET);
                    if (list.getLength() > 0) {
                        result.setExternalUrl(list.item(0).getNodeValue());
                    }
                }else{
                    nl = (NodeList) xpath.compile("//children/instance/licence[@classid='EMBARGO']").evaluate(document, XPathConstants.NODESET);
                    if (nl.getLength() > 0) {
                        NodeList list = (NodeList) xpath.compile("./webresource/url/text()").evaluate(nl.item(0).getParentNode(), XPathConstants.NODESET);
                        if (list.getLength() > 0) {
                            result.setExternalUrl(list.item(0).getNodeValue());
                        }
                    }else{
                        nl = (NodeList) xpath.compile("//children/instance/licence[@classid='CLOSED']").evaluate(document, XPathConstants.NODESET);
                        if (nl.getLength() > 0) {
                            NodeList list = (NodeList) xpath.compile("./webresource/url/text()").evaluate(nl.item(0).getParentNode(), XPathConstants.NODESET);
                            if (list.getLength() > 0) {
                                result.setExternalUrl(list.item(0).getNodeValue());
                            }
                        }
                    }
                }
            }
            nl = (NodeList) xpath.compile("//pid[@classid='pmc']/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setPmcid(nl.item(0).getNodeValue());

            }
            nl = (NodeList) xpath.compile("//pid[@classid='orcidworkid']/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setOrcidworkid(nl.item(0).getNodeValue());

            }
            nl = (NodeList) xpath.compile("//pid[@classid='oai']/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setOai(nl.item(0).getNodeValue());

            }
            nl = (NodeList) xpath.compile("//provenanceaction[@classid='user:claim:datacite']/@classid").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setProvenanceaction(nl.item(0).getNodeValue());

            }
            nl = (NodeList) xpath.compile("//response/header").evaluate(document, XPathConstants.NODESET);
            if(nl.getLength()>0){
                    nl.item(0).getParentNode().removeChild(nl.item(0));
            }

            nl = (NodeList) xpath.compile("//rel[@class='hasAuthor']").evaluate(document, XPathConstants.NODESET);
            System.out.println("Author length"+nl.getLength());
            if (nl.getLength() > 0) {
                for (int i = 0; i < nl.getLength(); i++) {
                    String ranking = ((Element)(nl.item(i).getParentNode())).getElementsByTagName("ranking").item(0).getTextContent();
                    String fullname =  (((Element)(nl.item(i).getParentNode())).getElementsByTagName("fullname").item(0).getTextContent().replace(",", " "));
                    result.getAuthors().put(ranking,fullname);
                }

            }
            nl = (NodeList) xpath.compile("//creator/text()").evaluate(document, XPathConstants.NODESET);
            System.out.println("Creator length"+nl.getLength());
            if (nl.getLength() > 0) {
                for (int i = 0; i < nl.getLength(); i++) {
                    String ranking = ((Element)(nl.item(i).getParentNode())).getAttribute("rank");
                    String fullname =  (((Element)(nl.item(i).getParentNode())).getTextContent().replace(",", " "));
                    result.getAuthors().put(ranking,fullname);
                }

            }

            DOMSource domSource = new DOMSource(document);
            StringWriter writer = new StringWriter();
            StreamResult streamResult = new StreamResult(writer);
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.transform(domSource, streamResult);
             result.setMetadataRecord(writer.toString());
            result.setCollectedFrom(ClaimUtils.COLLECTED_FROM_OPENAIRE);
            result.setRecordFormat(ClaimUtils.FORMAT_XML);
//            result.setFound(true);

        }
        return result;
    }


    public static Project oaf2Project(String oaf) throws Exception {
        Project project = null;
        if(oaf == null ){
            return null;

        }
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = null;
        try {
            dBuilder = dbFactory.newDocumentBuilder();


        InputSource is = new InputSource(new StringReader(oaf));
        Document document = dBuilder.parse(is);
        XPathFactory xPathfactory= XPathFactory.newInstance();
        XPath xpath = xPathfactory.newXPath();

        String size = null;
        NodeList nl = (NodeList) xpath.compile("/response/header/total/text()").evaluate(document, XPathConstants.NODESET);
        if (nl.getLength() > 0) {
            size= nl.item(0).getNodeValue();
        }
        if(size!=null && Integer.parseInt(size)>0){
            project = new Project();
            nl = (NodeList) xpath.compile("//objIdentifier/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                project.setOpenaireId(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//title/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                project.setName(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//acronym/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                project.setAcronym(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//funder/name/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                project.setFunderName(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//funder/id/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                project.setFunderId(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//funder/shortname/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                project.setFunderShortName(nl.item(0).getNodeValue());
            }else{
                project.setFunderShortName(project.getFunderId().split("::")[0]);
            }
            nl = (NodeList) xpath.compile("//funding_level_0/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                project.setFundingStreamLevel0(nl.item(0).getNodeValue());
            }

            nl = (NodeList) xpath.compile("//code/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                project.setCode(nl.item(0).getNodeValue());
            }

            nl = (NodeList) xpath.compile("//rels/rel/to[@class='hasContact']").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                project.setContactEmails(new ArrayList<String>());
                for (int i = 0; i < nl.getLength(); i++) {
                    if(((Element)(nl.item(i).getParentNode())).getElementsByTagName("email").getLength() > 0) {
                        String email = ((Element) (nl.item(i).getParentNode())).getElementsByTagName("email").item(0).getTextContent();
                        project.getContactEmails().add(email);
                    }
                }
            }
            logger.debug("AAAAAA");
            logger.debug(project);
//            project.setFound(true);

        }
        } catch (Exception e) {
           logger.error("Error while parsing project",e);
            throw new Exception(e);
        }

        return project;

    }

    public static Organization oaf2Organization(String oaf) throws Exception {
        Organization organization = null;
        if (oaf == null) {
            return null;

        }
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = null;
        try {
            dBuilder = dbFactory.newDocumentBuilder();
            InputSource is = new InputSource(new StringReader(oaf));
            Document document = dBuilder.parse(is);
            XPathFactory xPathfactory = XPathFactory.newInstance();
            XPath xpath = xPathfactory.newXPath();
            NodeList nl = (NodeList) xpath.compile("/response/header/total/text()").evaluate(document, XPathConstants.NODESET);
            organization = new Organization();
            nl = (NodeList) xpath.compile("//objIdentifier/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                organization.setOpenaireId(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//legalname/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                organization.setName(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//legalshortname/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                organization.setShortName(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//websiteurl/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                organization.setUrl(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//country/@classid").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                organization.setCountry(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//pid[@classid='ROR']/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                organization.setRORId(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//pid[@classid='GRID']/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                organization.setGRIDId(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//originalId/text()").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                organization.setOriginalId(nl.item(0).getNodeValue());
            }

        } catch (Exception e) {
            logger.error("Error while parsing organization", e);
            throw new Exception(e);
        }

        return organization;

    }
    public static Result oaf2Software(String oaf) throws ParserConfigurationException, IOException, SAXException, XPathExpressionException, TransformerException {
        Result result = null;
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        InputSource is = new InputSource(new StringReader(oaf));
        Document document= dBuilder.parse(is);
        XPathFactory xPathfactory= XPathFactory.newInstance();
        XPath xpath = xPathfactory.newXPath();

        String size = null;
        NodeList nl = (NodeList) xpath.compile("/response/header/total/text()").evaluate(document, XPathConstants.NODESET);
        if (nl.getLength() > 0) {
            size= nl.item(0).getNodeValue();
        }
        System.out.println("size:"+size);
        if(size!=null && Integer.parseInt(size)>0){
            result = new Result();
            nl = (NodeList) xpath.compile("//field[@name = \"resultId\"]/@value").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setOpenaireId(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//field[@name = \"resulttypeid\"]/@value").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setResultType(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//field[@name = \"bestaccessright\"]/@value").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setBestLicense(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//field[@name = \"embargoenddate\"]/@value").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setEmbargoEndDate(nl.item(0).getNodeValue());
            }
            nl = (NodeList) xpath.compile("//field[@name = \"title\"]/@value").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                result.setTitle(nl.item(0).getNodeValue());
            }
            //
            nl = (NodeList) xpath.compile("//field[@name = \"pid\"]").evaluate(document, XPathConstants.NODESET);
            System.out.println("size: pid"+nl.getLength());
            if (nl.getLength() > 0) {
                for (int i = 0; i < nl.getLength(); i++) {
                    NodeList list = (NodeList) xpath.compile("./field[@name = \"classid\"]/@value").evaluate(nl.item(i), XPathConstants.NODESET);
                    System.out.println("size: classid"+list.getLength());

                    if (list.getLength() > 0 && list.item(0).getNodeValue() !=null ) {

                        if (list.item(0).getNodeValue().equals("doi")) {
                            list = (NodeList) xpath.compile("./field[@name = \"value\"]/@value").evaluate(nl.item(i), XPathConstants.NODESET);
                            result.setDoi(list.item(0).getNodeValue());
                            result.setExternalUrl("http://dx.doi.org/" + result.getDoi());


                        } else if (list.item(0).getNodeValue().equals("pmc")) {
                            list = (NodeList) xpath.compile("./field[@name = \"value\"]/@value").evaluate(nl.item(i), XPathConstants.NODESET);
                            result.setDoi(list.item(0).getNodeValue());
                            result.setExternalUrl("http://dx.doi.org/" + result.getDoi());


                        }else if (list.item(0).getNodeValue().equals("orcidworkid")) {
                            list = (NodeList) xpath.compile("./field[@name = \"value\"]/@value").evaluate(nl.item(i), XPathConstants.NODESET);
                            result.setDoi(list.item(0).getNodeValue());
                            result.setExternalUrl("http://dx.doi.org/" + result.getDoi());


                        }else if (list.item(0).getNodeValue().equals("oai")) {
                            list = (NodeList) xpath.compile("./field[@name = \"value\"]/@value").evaluate(nl.item(i), XPathConstants.NODESET);
                            result.setDoi(list.item(0).getNodeValue());
                            result.setExternalUrl("http://dx.doi.org/" + result.getDoi());


                        }
                    }
                }
            }
            nl = (NodeList) xpath.compile("//rels/rel/to[@class='hasAuthor']").evaluate(document, XPathConstants.NODESET);
            if (nl.getLength() > 0) {
                for (int i = 0; i < nl.getLength(); i++) {
                    String ranking = ((Element)(nl.item(i).getParentNode())).getElementsByTagName("ranking").item(0).getTextContent();
                    String fullname =  (((Element)(nl.item(i).getParentNode())).getElementsByTagName("fullname").item(0).getTextContent().replace(",", " "));
                    result.getAuthors().put(ranking,fullname);
                }

            }
            if(result.getExternalUrl()==null){
//                nl = (NodeList) xpath.compile("//webresource/url/text()").evaluate(document, XPathConstants.NODESET);
//                if (nl.getLength() > 0) {
//                    result.setExternalUrl(nl.item(0).getNodeValue());
//                }
                nl = (NodeList) xpath.compile("//children/instance/licence[@classid='OPEN']").evaluate(document, XPathConstants.NODESET);
                if (nl.getLength() > 0) {
                    NodeList list = (NodeList) xpath.compile("./webresource/url/text()").evaluate(nl.item(0).getParentNode(), XPathConstants.NODESET);
                    if (list.getLength() > 0) {
                        result.setExternalUrl(list.item(0).getNodeValue());
                    }
                }else{
                    nl = (NodeList) xpath.compile("//children/instance/licence[@classid='EMBARGO']").evaluate(document, XPathConstants.NODESET);
                    if (nl.getLength() > 0) {
                        NodeList list = (NodeList) xpath.compile("./webresource/url/text()").evaluate(nl.item(0).getParentNode(), XPathConstants.NODESET);
                        if (list.getLength() > 0) {
                            result.setExternalUrl(list.item(0).getNodeValue());
                        }
                    }else{
                        nl = (NodeList) xpath.compile("//children/instance/licence[@classid='CLOSED']").evaluate(document, XPathConstants.NODESET);
                        if (nl.getLength() > 0) {
                            NodeList list = (NodeList) xpath.compile("./webresource/url/text()").evaluate(nl.item(0).getParentNode(), XPathConstants.NODESET);
                            if (list.getLength() > 0) {
                                result.setExternalUrl(list.item(0).getNodeValue());
                            }
                        }
                    }
                }
            }


            nl = (NodeList) xpath.compile("//response/header").evaluate(document, XPathConstants.NODESET);
            if(nl.getLength()>0){
                nl.item(0).getParentNode().removeChild(nl.item(0));
            }



            DOMSource domSource = new DOMSource(document);
            StringWriter writer = new StringWriter();
            StreamResult streamResult = new StreamResult(writer);
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.transform(domSource, streamResult);
            result.setMetadataRecord(writer.toString());
            result.setCollectedFrom(ClaimUtils.COLLECTED_FROM_OPENAIRE);
            result.setRecordFormat(ClaimUtils.FORMAT_XML);
//            result.setFound(true);

        }
        return result;
    }


}
