package eu.dnetlib.wds.parser;

import com.google.common.collect.Lists;
import com.ximpleware.AutoPilot;
import com.ximpleware.VTDGen;
import com.ximpleware.VTDNav;
import eu.dnetlib.data.transform.VtdUtilityParser;
import eu.dnetlib.data.transform.VtdUtilityParser.Node;
import eu.dnetlib.miscutils.collections.Pair;
import eu.dnetlib.pid.resolver.model.*;
import eu.dnetlib.pid.resolver.parser.AbstractResolverParser;
import eu.dnetlib.wds.resolver.WDSObjectRelation;
import eu.dnetlib.wds.resolver.WDSResolvedObject;
import eu.dnetlib.wds.utils.WDSUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

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

/**
 * Created by sandro on 9/13/16.
 */
public class DMFResolverParser extends AbstractResolverParser {

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

    @Override
    public ResolvedObject parseObject(final String record) {
        try {
            final WDSResolvedObject parsedObject = 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("dri", "http://www.driver-repository.eu/namespace/dri");


            final String datasourcePrefix = VtdUtilityParser.getSingleValue(ap, vn, "//dri:datasourceprefix");
            ap.declareXPathNameSpace("oaf", "http://namespace.dnet.eu/oaf");

            final ObjectProvenance provenance = new ObjectProvenance();
            provenance.setDatasourceId(WDSUtils.getIdFromDataSourcePrefix(datasourcePrefix));
            provenance.setDatasource(WDSUtils.getNameFromDataSourcePrefix(datasourcePrefix));
            parsedObject.setDatasourceProvenance(Arrays.asList(provenance));

            final String publisher = VtdUtilityParser.getSingleValue(ap, vn, "//*[local-name()='resource']/*[local-name()='publisher']");

            if (StringUtils.isNotEmpty(publisher))
                parsedObject.setPublisher(publisher);

            final List<Node> identifierType =
                    VtdUtilityParser.getTextValuesWithAttributes(ap, vn, "//*[local-name()='resource']/*[local-name()='identifier']", Lists.newArrayList("identifierType"));

            if (extractIdentifier(parsedObject, identifierType)) return null;

            final List<Node> relations =
                    VtdUtilityParser.getTextValuesWithAttributes(ap, vn, "//*[local-name()='resource']//*[local-name()='relatedIdentifier']", Arrays.asList("relatedIdentifierType", "relationType", "inverseRelationType"));

            if (relations != null && relations.size() > 0) {
                final List<ObjectRelation> relationsResult = new ArrayList<>();
                relations.forEach(relationMap -> {
                    final String relationType = relationMap.getAttributes().get("relationType");
                    final String inverseRelationType = relationMap.getAttributes().get("inverseRelationType");
                    final String relatedIdentifierType = relationMap.getAttributes().get("relatedIdentifierType");
                    final String relatedPid = relationMap.getTextValue();
                    final WDSObjectRelation currentRelation = new WDSObjectRelation();
                    currentRelation.setTargetPID(inferPid(new PID(relatedPid, relatedIdentifierType)));
                    currentRelation.setRelationSemantics(relationType);
                    currentRelation.setInverseRelation(inverseRelationType);
                    relationsResult.add(currentRelation);
                });
                parsedObject.setRelations(relationsResult);
            }

            final List<Node> subjects = VtdUtilityParser.getTextValuesWithAttributes(ap, vn, "//*[local-name()='resource']//*[local-name()='subject']", Arrays.asList("subjectScheme"));

            extractSubject(parsedObject, subjects);


            final List<String> creators = VtdUtilityParser.getTextValue(ap, vn, "//*[local-name()='resource']//*[local-name()='creator']/*[local-name()='creatorName']");
            if (creators != null && creators.size() > 0) {
                parsedObject.setAuthors(creators);
            }
            final List<String> titles = VtdUtilityParser.getTextValue(ap, vn, "//*[local-name()='resource']//*[local-name()='title']");
            if (titles != null && titles.size() > 0) {
                parsedObject.setTitles(titles);
            }
            final List<String> descriptions = VtdUtilityParser.getTextValue(ap, vn, "//*[local-name()='resource']//*[local-name()='description']");
            if (descriptions != null && descriptions.size() > 0) {


                parsedObject.setDescriptions(descriptions.stream().map(it -> new Pair<>("unknwonw", it)).collect(Collectors.toList()));
            }

            List<Node> resourceTypeGeneral = VtdUtilityParser.getTextValuesWithAttributes(ap, vn, "//*[local-name()='resource']/*[local-name()='resourceType']", Arrays.asList("resourceTypeGeneral"));


            if (resourceTypeGeneral != null && !resourceTypeGeneral.isEmpty()) {
                final String type = resourceTypeGeneral.get(0).getAttributes().get("resourceTypeGeneral");
                setType(parsedObject, type);
            }

            if (parsedObject.getType() == ObjectType.unknown) {

                final String type = VtdUtilityParser.getSingleValue(ap, vn, "//*[local-name()='resource']/*[local-name()='resourceType']");
                setType(parsedObject, type);
            }


            final List<String> dates = VtdUtilityParser.getTextValue(ap, vn, "//*[local-name()='resource']/*[local-name()='dates']/*[local-name()='date']");

            if (dates != null && dates.size() > 0) {
                dates.forEach(it -> parsedObject.addDate("unknown", it));
            }
            return parsedObject;
        } catch (Throwable e) {
            log.error("Error on parsing record " + record, e);
            return null;
        }
    }


}

