package eu.dnetlib.wds.resolver;

import com.ximpleware.AutoPilot;
import com.ximpleware.VTDGen;
import com.ximpleware.VTDNav;
import eu.dnetlib.data.transform.VtdUtilityParser;
import eu.dnetlib.miscutils.collections.Pair;
import eu.dnetlib.pid.resolver.model.SubjectType;
import eu.dnetlib.pid.resolver.parser.AbstractResolverParser;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


/**
 * Created by sandro on 10/3/16.
 */
public class OpenAireParser extends AbstractResolverParser {

    private static final Log log = LogFactory.getLog(OpenAireParser.class);

    @Override
    public WDSResolvedObject parseObject(final String record) {
        try {
            final WDSResolvedObject currentObject = new WDSResolvedObject();
            final VTDGen vg = new VTDGen();
            vg.setDoc(record.getBytes());
            vg.parse(true);

            final VTDNav vn = vg.getNav();
            final AutoPilot ap = new AutoPilot(vn);

            ap.declareXPathNameSpace("oaf", "http://namespace.openaire.eu/oaf");

            final List<VtdUtilityParser.Node> subjectNodes =
                    VtdUtilityParser.getTextValuesWithAttributes(ap, vn, "//*[local-name()='result']//*[local-name()='subject']", Arrays.asList("classname", "schemename"));

            //Setting subjects
            if (subjectNodes != null && subjectNodes.size() > 0) {
                final List<SubjectType> currentSubjects = new ArrayList<>();

                subjectNodes.forEach(it ->
                        currentSubjects.add(new SubjectType(it.getAttributes().get("schemename"), it.getTextValue()))
                );
                currentObject.setSubjects(currentSubjects);
            }

            //Setting Titles
            final List<String> titles = VtdUtilityParser.getTextValue(ap, vn, "//*[local-name()='result']/*[local-name()='title']");

            if (titles != null && titles.size() > 0) {
                currentObject.setTitles(titles);
            }

            //Setting authors
            final List<String> authorNodes = VtdUtilityParser.getTextValue(ap, vn, "//*[local-name()='result']//*[local-name()='fullname']");
            if (authorNodes != null && authorNodes.size() > 0) {
                currentObject.setAuthors(authorNodes);
            }

            //Setting descriptions
            final List<String> descriptions = VtdUtilityParser.getTextValue(ap, vn, "//*[local-name()='result']//*[local-name()='description']");
            if (descriptions != null && descriptions.size() > 0) {
                descriptions.forEach(d -> currentObject.addDescription(new Pair<>("unknown", d)));
            }

            //resulttype classid
            final List<VtdUtilityParser.Node> resutlTypes = VtdUtilityParser.getTextValuesWithAttributes(ap, vn, "//*[local-name()='result']/*[local-name()='resulttype']", Arrays.asList("classid"));
            if (resutlTypes != null && resutlTypes.size() > 0) {
                final String type = resutlTypes.get(0).getAttributes().get("classid");
                setType(currentObject, type);
            }

            ap.selectXPath("//*[local-name()='rel'][./to/@type='project']");
            while (ap.evalXPath() != -1) {
                final List<String> projectTitles = VtdUtilityParser.getTextValue(ap, vn, "./title");
                final List<String> projectAcronym = VtdUtilityParser.getTextValue(ap, vn, "./acronym");
                final List<String> projectCodes = VtdUtilityParser.getTextValue(ap, vn, "./code");
                final List<VtdUtilityParser.Node> funderNames = VtdUtilityParser.getTextValuesWithAttributes(ap, vn, ".//funder", Arrays.asList("name"));

                final List<String> projectfundings = VtdUtilityParser.getTextValue(ap, vn, ".//*[starts-with(name(), 'funding_level_')]");

                final String funderName = funderNames != null ? funderNames.stream().findFirst().get().getAttributes().get("name") : "";

                String funding = projectfundings.size() > 0 ? projectfundings.get(projectfundings.size() - 1) : "";
                funding = funding.length() > 2 ? funding.substring(funding.indexOf("::") + 2) : "";

                currentObject.addProject(new Project().setAcronym((projectAcronym!=null && projectAcronym.size()>0) ?projectAcronym.get(0):"")
                        .setFundingStream(funding)
                        .setFunder(funderName)
                        .setGrantID(projectCodes.get(0))
                        .setName(projectTitles.get(0)));
            }
                return currentObject;
        } catch (Throwable e) {
            log.error("Error on parsing object ", e);
            return null;
        }
    }

}
