package eu.dnetlib.resolver.parser;

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

import com.ximpleware.AutoPilot;
import com.ximpleware.VTDGen;
import com.ximpleware.VTDNav;
import eu.dnetlib.dli.resolver.model.*;
import eu.dnetlib.data.transform.VtdUtilityParser;
import eu.dnetlib.data.transform.VtdUtilityParser.Node;
import eu.dnetlib.pid.resolver.model.*;
import eu.dnetlib.pid.resolver.parser.AbstractResolverParser;

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

	@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 List<Node> pid = VtdUtilityParser.getTextValuesWithAttributes(ap, vn, "//*[local-name()='pid']", Arrays.asList("type"));

            if (extractIdentifier(parsedObject, pid, "type")) return null;

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

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

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

			final String publisher = VtdUtilityParser.getSingleValue(ap, vn, "//*[local-name()='publisher']");
            final List<ObjectProvenance> provenances = new ArrayList<>();

			if (collectedFromNodes != null && collectedFromNodes.size() > 0) {
				collectedFromNodes.forEach(it -> {
                    final DLIObjectProvenance provenance = new DLIObjectProvenance();
                    provenance.setDatasourceId(it.getAttributes().get("id"));
					provenance.setDatasource(it.getAttributes().get("name"));
					provenance.setProvisionMode(provisionMode);
					provenance.setCompletionStatus(it.getAttributes().get("completionStatus"));
					provenance.setPublisher(publisher);
					provenances.add(provenance);
				});
			}

            if (resolvededFromNodes != null && resolvededFromNodes.size() > 0) {
                resolvededFromNodes.forEach(it -> {
                    final DLIObjectProvenance provenance = new DLIObjectProvenance();
                    provenance.setDatasourceId(it.getAttributes().get("id"));
                    provenance.setDatasource(it.getAttributes().get("name"));
                    provenance.setProvisionMode("resolved");
                    provenance.setCompletionStatus(it.getAttributes().get("completionStatus"));
                    provenances.add(provenance);
                });
            }

			parsedObject.setDatasourceProvenance(provenances);
			parsedObject.setCompletionStatus(VtdUtilityParser.getSingleValue(ap, vn, "//*[local-name()='completionStatus']"));





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

			if (relatedIdentifiers != null && relatedIdentifiers.size() > 0) {
				final List<ObjectRelation> relations = new ArrayList<>();
				relatedIdentifiers.forEach(relation -> {
					final String currentPid = relation.getTextValue();
					final String currentPidType = relation.getAttributes().get("relatedIdentifierType");
					final String currentType = relation.getAttributes().containsKey("entityType") ? relation.getAttributes().get("entityType"):"unknown" ;
                    final DLIObjectRelation currentRelation = new DLIObjectRelation();
                    currentRelation.setTargetPID(new PID(currentPid, currentPidType));
					currentRelation.setCompletionStatus(CompletionStatus.incomplete.toString());
					currentRelation.setSourcePid(parsedObject.getPid());
					currentRelation.setRelationSemantics(relation.getAttributes().get("relationType"));
					currentRelation.setInverseRelation(relation.getAttributes().get("inverseRelationType"));


					currentRelation.setTargetType(ObjectType.valueOf(currentType));
					if (parsedObject.getDatasourceProvenance() != null && parsedObject.getDatasourceProvenance().size() > 0) {
                        final DLIObjectProvenance provenance = (DLIObjectProvenance) parsedObject.getDatasourceProvenance().get(0);

                        final DLIObjectProvenance newProvenance = new DLIObjectProvenance();
                        newProvenance.setCompletionStatus(CompletionStatus.incomplete.toString());
						newProvenance.setDatasourceId(provenance.getDatasourceId());
						newProvenance.setDatasource(provenance.getDatasource());
						newProvenance.setProvisionMode(provenance.getProvisionMode());

						currentRelation.setRelationProvenance(Arrays.asList(newProvenance));
					}

					relations.add(currentRelation);
				});
				parsedObject.setRelations(relations);
			}

			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<String> authorsNode = VtdUtilityParser.getTextValue(ap, vn, "//*[local-name()='creator']");
			parsedObject.setAuthors(authorsNode);
			parsedObject.setTitles(VtdUtilityParser.getTextValue(ap, vn, "//*[local-name()='title']"));

			parsedObject.setDescription(VtdUtilityParser.getSingleValue(ap, vn, "//*[local-name()='description']"));
			parsedObject.setDate(VtdUtilityParser.getSingleValue(ap, vn, "//*[local-name()='date']"));
			List<Node> subjects = VtdUtilityParser.getTextValuesWithAttributes(ap, vn, "//*[local-name()='subject']", Arrays.asList("scheme"));
            extractSubject(parsedObject, subjects);


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

			return parsedObject;
		} catch (Throwable e) {
			log.error("Input record: " + record);
			log.error("Error on parsing record ", e);
			return null;
		}

	}
}
