package eu.dnetlib.resolver.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.dli.DLIUtils;
import eu.dnetlib.dli.resolver.model.*;
import eu.dnetlib.pid.resolver.model.ObjectRelation;
import eu.dnetlib.pid.resolver.model.ObjectType;
import eu.dnetlib.pid.resolver.model.PID;
import eu.dnetlib.pid.resolver.model.SubjectType;
import eu.dnetlib.pid.resolver.parser.AbstractResolverParser;
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;

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

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

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

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

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

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

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

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


            final DLIObjectProvenance provenance = new DLIObjectProvenance();
            provenance.setDatasourceId(DLIUtils.getIdFromDataSourcePrefix(datasourcePrefix));
            provenance.setDatasource(DLIUtils.getNameFromDataSourcePrefix(datasourcePrefix));
            provenance.setCompletionStatus(completionStatus);
            if (!StringUtils.isEmpty(publisher))
                provenance.setPublisher(publisher);
            provenance.setProvisionMode(provisionMode);
			parsedObject.setDatasourceProvenance(Lists.newArrayList(provenance));





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

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


            List<String> descs = VtdUtilityParser.getTextValue(ap, vn,"//*[local-name()='description']" );
            if (descs!=null && descs.size()>0)
            parsedObject.setDescription(descs.get(0));


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

			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 relatedEntityType = relationMap.getAttributes().get("entityType");
					final String relatedPid = relationMap.getTextValue();
                    final DLIObjectRelation currentRelation = new DLIObjectRelation();
                    if (relatedEntityType == null)
                        currentRelation.setTargetType(ObjectType.unknown);
                    else
                        currentRelation.setTargetType(ObjectType.valueOf(relatedEntityType));
                    currentRelation.setTargetPID(new PID(relatedPid, relatedIdentifierType));
					currentRelation.setRelationSemantics(relationType);
                    currentRelation.setInverseRelation(inverseRelationType);
                    currentRelation.setCompletionStatus(CompletionStatus.incomplete.toString());
					if (!StringUtils.isBlank(currentRelation.getTargetPID().getId()))
						relationsResult.add(currentRelation);
				});
				parsedObject.setRelations(relationsResult);
			}


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


            if (hostedBy!= null) {
                hostedBy.stream().map(it->new OAFHostedBy(it.getAttributes().get("id"),it.getAttributes().get("name") )).forEach(parsedObject::setHostedBy);
            }



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

            extractSubject(parsedObject, subjects);

			parsedObject.setCompletionStatus(completionStatus);

            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);
			}

            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) {
				parsedObject.setDate(dates.get(0));
			}
			return parsedObject;
		} catch (Throwable e) {
			log.error("Error on parsing record " + record, e);
			return null;
		}
	}


}

