package org.keycloak.federation.ldap.idm.model;

import java.util.Deque;
import java.util.LinkedList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
 */
public class LDAPDn {

    private final Deque<Entry> entries = new LinkedList<>();

    private static final Pattern dnRegex = Pattern.compile("[^,\\\\]*(?:\\\\.[^,\\\\]*)");

    public static LDAPDn fromString(String dnString) {
        LDAPDn dn = new LDAPDn();

        Matcher dnMatches = dnRegex.matcher(dnString);

        while (dnMatches.find()) {
            String[] rdn = dnMatches.group(1).split("=");
            dn.addLast(rdn[0].trim(), rdn[1].trim());
        }

        return dn;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();

        boolean first = true;
        for (Entry rdn : entries) {
            if (first) {
                first = false;
            } else {
                builder.append(",");
            }
            builder.append(rdn.attrName).append("=").append(rdn.attrValue);
        }

        return builder.toString();
    }

    /**
     * @return string like "uid=joe" from the DN like "uid=joe,dc=something,dc=org"
     */
    public String getFirstRdn() {
        Entry firstEntry = entries.getFirst();
        return firstEntry.attrName + "=" + firstEntry.attrValue;
    }

    /**
     * @return string attribute name like "uid" from the DN like "uid=joe,dc=something,dc=org"
     */
    public String getFirstRdnAttrName() {
        Entry firstEntry = entries.getFirst();
        return firstEntry.attrName;
    }

    /**
     *
     * @return string like "dc=something,dc=org" from the DN like "uid=joe,dc=something,dc=org"
     */
    public String getParentDn() {
        return new LinkedList<>(entries).remove().toString();
    }

    public void addFirst(String rdnName, String rdnValue) {
        entries.addFirst(new Entry(rdnName, rdnValue));
    }

    public void addLast(String rdnName, String rdnValue) {
        entries.addLast(new Entry(rdnName, rdnValue));
    }


    private static class Entry {
        private final String attrName;
        private final String attrValue;

        private Entry(String attrName, String attrValue) {
            this.attrName = attrName;
            this.attrValue = attrValue;
        }
    }
}

@@ -323,100 +323,8 @@
 );%0A%0A
-    private static final Pattern dnRegex = Pattern.compile(%22%5B%5E,%5C%5C%5C%5C%5D*(?:%5C%5C%5C%5C.%5B%5E,%5C%5C%5C%5C%5D*)%22);%0A%0A
     
@@ -421,64 +421,66 @@
     
-Matcher dnMatches = dnRegex.matcher(dnString
+String%5B%5D rdns = dnString.split(%22(?%3C!%5C%5C%5C%5C%5C%5C%5C%5C),%22
 );%0A
-%0A
         
 whil
@@ -479,31 +479,35 @@
     
-while (dnMatches.find()
+for (String entryStr : rdns
 ) %7B%0A
@@ -537,34 +537,37 @@
 n = 
-dnMatches.group(1).split(%22
+entryStr.split(%22(?%3C!%5C%5C%5C%5C%5C%5C%5C%5C)
 =%22);

Fix LDAP DN component matching with negative lookbehind RegEx