package eu.dnetlib.pid.resolver.parser;

import eu.dnetlib.data.transform.VtdUtilityParser;
import eu.dnetlib.pid.resolver.model.ObjectType;
import eu.dnetlib.pid.resolver.model.PID;
import eu.dnetlib.pid.resolver.model.ResolvedObject;
import eu.dnetlib.pid.resolver.model.SubjectType;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.xml.stream.XMLStreamReader;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public abstract class AbstractResolverParser {

    protected static final Log log = LogFactory.getLog(AbstractResolverParser.class);
    final static Pattern pattern = Pattern.compile("10\\.\\d{4,9}/[-._;()/:A-Z0-9]+$", Pattern.CASE_INSENSITIVE);
    private List<String> datasetSubTypes = Arrays.asList("dataset", "software", "film", "sound", "physicalobject", "audiovisual", "collection", "other", "study", "metadata");

    public abstract ResolvedObject parseObject(final String record);

    protected Map<String, String> getAttributes(final XMLStreamReader parser) {
        final Map<String, String> attributesMap = new HashMap<>();
        for (int i = 0; i < parser.getAttributeCount(); i++) {
            attributesMap.put(parser.getAttributeLocalName(i), parser.getAttributeValue(i));
        }
        return attributesMap;
    }

    protected void setType(final ResolvedObject object, final String type) {
        if (!StringUtils.isBlank(type)) {
            if (datasetSubTypes.contains(type.toLowerCase())) {
                object.setType(ObjectType.dataset);
                return;
            } else if (type.toLowerCase().contains("publication")) {
                object.setType(ObjectType.publication);
                return;
            } else {
                object.setType(ObjectType.unknown);
            }
        }
    }

    protected void extractSubject(ResolvedObject parsedObject, List<VtdUtilityParser.Node> subjects) {
        if (subjects != null && subjects.size() > 0) {
            final List<SubjectType> subjectResult = new ArrayList<>();
            subjects.forEach(subjectMap -> {
                final SubjectType subject = new SubjectType(subjectMap.getAttributes().get("subjectScheme"), subjectMap.getTextValue());
                subjectResult.add(subject);
            });
            parsedObject.setSubjects(subjectResult);
        }
    }

    protected boolean extractIdentifier(ResolvedObject parsedObject, List<VtdUtilityParser.Node> identifierType) {
        return extractIdentifier(parsedObject, identifierType, "identifierType");
    }


    protected boolean extractIdentifier(ResolvedObject parsedObject, List<VtdUtilityParser.Node> identifierType, final String fieldName) {
        if (identifierType != null && identifierType.size() > 0) {

            final VtdUtilityParser.Node result = identifierType.get(0);
            parsedObject.setPid(result.getTextValue());
            parsedObject.setPidType(result.getAttributes().get(fieldName));
        } else {
            log.debug("Error on parsing record the identifier should not null ");
            return true;
        }
        return false;
    }

    protected PID inferPid(final PID input) {
        final Matcher matcher = pattern.matcher(input.getId());
        if (matcher.find()) {
            input.setId(matcher.group());
            input.setType("doi");
        }
        return input;
    }

}
