package eu.dnetlib.data.graph.model;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.protobuf.Descriptors;
import com.google.protobuf.GeneratedMessage;
import eu.dnetlib.data.proto.*;

import java.util.Arrays;
import java.util.Set;

/**
 * Created by sandro on 12/13/16.
 */
public class DNGFUtils {

    public static Set<String> entities() {
        return Sets.newHashSet(Iterables.transform(Lists.newArrayList(TypeProtos.Type.values()), t -> t.toString()));
    }

    public static Predicate<DNGFProtos.DNGF> relationFilter() {
        return dngf -> dngf.getKind().equals(KindProtos.Kind.relation);
    }

    public static Predicate<DNGFProtos.DNGF> entityFilter() {
        return dngf -> dngf.getKind().equals(KindProtos.Kind.entity);
    }

    public static Function<DNGFDecoder, String> idDecoder() {
        return input -> input.getEntityId();
    }

    public static Predicate<FieldTypeProtos.StructuredProperty> mainTitleFilter() {
        return sp -> (sp.getQualifier() != null) && sp.getQualifier().getClassname().equals("main title");
    }

    public static Set<String> getFieldNames(final Descriptors.Descriptor d, final Integer... tag) {
        return Sets.newHashSet(Iterables.transform(Arrays.asList(tag), i -> {
            final Descriptors.FieldDescriptor fd = d.findFieldByNumber(i);
            if (fd == null) throw new IllegalArgumentException("undefined tag: " + i + " for type: " + d.getFullName());
            return fd.getName();
        }));
    }

    public static FieldTypeProtos.StringField sf(final String value) {
        return FieldTypeProtos.StringField.newBuilder().setValue(value).build();
    }

    public static FieldTypeProtos.StructuredProperty sp(final String value, final String classid, final String schemeid) {
        return sp(value, classid, schemeid, di());
    }

    public static FieldTypeProtos.StructuredProperty sp(final String value, final String classid, final String schemeid, final FieldTypeProtos.DataInfo di) {
        return FieldTypeProtos.StructuredProperty.newBuilder().setValue(value).setQualifier(simpleQualifier(classid, schemeid)).setDataInfo(di).build();
    }

    public static FieldTypeProtos.KeyValue kv(final String k, final String v) {
        return FieldTypeProtos.KeyValue.newBuilder().setKey(k).setValue(v).build();
    }

    public static FieldTypeProtos.Qualifier simpleQualifier(final String classid, final String schemeid) {
        return q(classid, classid, schemeid, schemeid);
    }

    public static FieldTypeProtos.Qualifier q(final String classid, final String classname, final String schemeid, final String schemename) {
        return FieldTypeProtos.Qualifier.newBuilder()
                .setClassid(classid)
                .setClassname(classname)
                .setSchemename(schemeid)
                .setSchemeid(schemename).build();
    }

    public static FieldTypeProtos.DataInfo di(final String trust) {
        return di(false, "", false, simpleQualifier("", ""), trust);
    }

    public static FieldTypeProtos.DataInfo di() {
        return di("");
    }

    public static FieldTypeProtos.DataInfo di(Boolean deletedByInference, String inferenceProvenance, Boolean inferred, FieldTypeProtos.Qualifier provenanceAction, String trust) {
        return FieldTypeProtos.DataInfo.newBuilder()
                .setDeletedbyinference(deletedByInference)
                .setInferenceprovenance(inferenceProvenance)
                .setInferred(inferred)
                .setProvenanceaction(provenanceAction)
                .setTrust(trust).build();
    }

    public static FieldTypeProtos.Context context(final String id) {
        return FieldTypeProtos.Context.newBuilder().setId(id).build();
    }


    public static DNGFDecoder embed(final GeneratedMessage msg,
                                    final KindProtos.Kind kind,
                                    final boolean deletedByInference,
                                    final boolean inferred,
                                    final String provenance,
                                    final String action) {

        final DNGFProtos.DNGF.Builder DNGF = DNGFProtos.DNGF
                .newBuilder()
                .setKind(kind)
                .setLastupdatetimestamp(System.currentTimeMillis())
                .setDataInfo(di(deletedByInference, provenance, inferred, simpleQualifier(action, action), "0.5"));
        switch (kind) {
            case entity:
                DNGF.setEntity((DNGFProtos.DNGFEntity) msg);
                break;
            case relation:
                DNGF.setRel((DNGFProtos.DNGFRel) msg);
                break;
            default:
                break;
        }

        return DNGFDecoder.decode(DNGF.build());
    }

    public static DNGFDecoder embed(final GeneratedMessage msg, final KindProtos.Kind kind) {
        return embed(msg, kind, false, false, "inference_provenance", "provenance_action");
    }


}
