package bndtools.model.resolution;

import java.util.Comparator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.bndtools.core.ui.resource.R5LabelFormatter;
import org.osgi.framework.Version;
import org.osgi.resource.Capability;
import org.osgi.resource.Namespace;
import org.osgi.resource.Requirement;

public class CapReqComparator implements Comparator<Object> {

    @Override
    public int compare(Object o1, Object o2) {
        if (o1 instanceof Requirement)
            return compareReqToObj((Requirement) o1, o2);

        if (o1 instanceof RequirementWrapper)
            return compareReqToObj(((RequirementWrapper) o1).requirement, o2);

        if (o1 instanceof Capability)
            return compareCapToObj((Capability) o1, o2);

        return 0;
    }

    private int compareReqToObj(Requirement r1, Object o2) {
        if (o2 instanceof Requirement)
            return compareReqToReq(r1, (Requirement) o2);

        if (o2 instanceof RequirementWrapper)
            return compareReqToReq(r1, ((RequirementWrapper) o2).requirement);

        // requirements sort before other things
        return -1;
    }

    private int compareCapToObj(Capability c1, Object o2) {
        if (o2 instanceof Capability)
            return compareCapToCap(c1, (Capability) o2);

        // capabilities sort after other things
        return 1;
    }

    private int compareCapToCap(Capability c1, Capability c2) {
        // Compare namespaces
        String ns1 = c1.getNamespace();
        String ns2 = c2.getNamespace();
        int nsDiff = ns1.compareTo(ns2);
        if (nsDiff != 0)
            return nsDiff;

        // Compare the main attribute
        String attribName = R5LabelFormatter.getMainAttributeName(ns1);
        String attrib1 = c1.getAttributes()
            .get(attribName)
            .toString();
        String attrib2 = c2.getAttributes()
            .get(attribName)
            .toString();
        int attribDiff = attrib1.compareTo(attrib2);
        if (attribDiff != 0)
            return attribDiff;

        // Compare the versions
        String versionAttribName = R5LabelFormatter.getVersionAttributeName(ns1);
        if (versionAttribName == null)
            return 0;
        Version v1 = (Version) c1.getAttributes()
            .get(versionAttribName);
        if (v1 == null)
            v1 = Version.emptyVersion;
        Version v2 = (Version) c2.getAttributes()
            .get(versionAttribName);
        if (v2 == null)
            v2 = Version.emptyVersion;
        return v1.compareTo(v2);
    }

    private int compareReqToReq(Requirement r1, Requirement r2) {
        // Compare namespaces
        String ns1 = r1.getNamespace();
        String ns2 = r2.getNamespace();
        int nsDiff = ns1.compareTo(ns2);
        if (nsDiff != 0)
            return nsDiff;

        // Get the main attribute
        Pattern filterPattern = R5LabelFormatter.getFilterPattern(ns1);
        if (filterPattern == null)
            return 0;
        String filter1 = r1.getDirectives()
            .get(Namespace.REQUIREMENT_FILTER_DIRECTIVE);
        Matcher m1 = filterPattern.matcher(filter1);
        String filter2 = r2.getDirectives()
            .get(Namespace.REQUIREMENT_FILTER_DIRECTIVE);
        Matcher m2 = filterPattern.matcher(filter2);
        if (!m1.find() || !m2.find())
            return 0;
        String attrib1 = m1.group(1);
        String attrib2 = m2.group(1);
        if (attrib1 == null || attrib2 == null)
            return 0;
        return attrib1.compareTo(attrib2);
    }
}