package dummy.test;

import org.apache.ldap.common.filter.ExprNode;
import org.apache.ldap.common.message.ArrayNamingEnumeration;
import org.apache.ldap.server.partition.AbstractContextPartition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.naming.*;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.directory.*;
import java.util.*;
import java.io.File;
import java.io.FileInputStream;

/**
 * Dummy proxy to test double escaping problem.
 */
public class DummyProxyPartition extends AbstractContextPartition {
    private static final Logger log = LoggerFactory.getLogger(DummyProxyPartition.class);

    private boolean broken = false;

    public static class SearchResultWrapper extends SearchResult
    {
        public SearchResultWrapper(String name, String className, Object obj,
                Attributes attrs)
        {
            super(name, className, obj, attrs);
        }

        public SearchResultWrapper(String name, String className, Object obj,
                Attributes attrs, boolean isRelative)
        {
            super(name, className, obj, attrs, isRelative);
        }

        public SearchResultWrapper(String name, Object obj, Attributes attrs)
        {
            super(name, obj, attrs);
        }

        public SearchResultWrapper(String name, Object obj, Attributes attrs,
                boolean isRelative)
        {
            super(name, obj, attrs, isRelative);
        }
    }

    /**
     *   ApacheDS seems to have a bug where SearchResult s with relative DNs
     * have URL encoding applied twice, so blanks come out as %20.
     */
    public static final class AvoidEscapingNamingEnumeration
            implements NamingEnumeration
    {
        private final String                baseDN;
        private final NamingEnumeration     ne;

        public AvoidEscapingNamingEnumeration(final String baseDN,
                final NamingEnumeration ne)
        {
            this.baseDN = baseDN;
            this.ne = ne;
        }

        public void close() throws NamingException
        {
            ne.close();
        }

        public boolean hasMore() throws NamingException
        {
            return ne.hasMore();
        }

        public Object next() throws NamingException
        {
            final SearchResult      sr = (SearchResult)ne.next();
            final String            fullDN;
            final String            name = sr.getName();

            if (!sr.isRelative() || (name == null) || "".equals(name))
                return sr;
            fullDN = name + "," + baseDN;
            sr.setName(fullDN);
            sr.setRelative(false);
            return sr;
        }

        public boolean hasMoreElements()
        {
            try
            {
                return hasMore();
            }
            catch (NamingException e)
            {
                log.error(this.getClass().getName()
                        + ": error in hasMoreElements", e);
                return false;
            }
        }

        public Object nextElement()
        {
            try
            {
                return next();
            }
            catch (NamingException e)
            {
                log.error(this.getClass().getName()
                        + ": error in nextElement", e);
                return null;
            }
        }
    }

    public void doInit() throws NamingException
    {
        final String    name = this.getConfiguration().getName();

        log.debug("-------------------------------------------------------------------------------");
        log.info("Initializing "+name+" partition ...");
    }

    public void delete(final Name dn) throws NamingException {
        log.info("Deleting \""+dn+"\"");
    }

    public void add(final String upName, final Name normName,
            final Attributes attributes) throws NamingException
    {
        log.info("Adding \""+upName+"\"");
    }

    public void modify(final Name dn, final int mod_op,
            final Attributes attributes)
            throws NamingException
    {
        log.info("Modifying \""+dn+"\"");
    }

    public void modify(final Name dn,
            final ModificationItem[] modificationItems)
            throws NamingException
    {
        log.info("Modifying \""+dn+"\"");
    }

    public NamingEnumeration list(final Name dn) throws NamingException
    {
        log.info("Listing \""+dn+"\"");
        return null;
    }

    public NamingEnumeration search(Name base, final Map env,
            final ExprNode filter, final SearchControls searchControls)
            throws NamingException
    {
        final String            baseName = base.toString();
        final SearchResult      sr = new SearchResultWrapper("cn=test space", null, null,
                new BasicAttributes());
        NamingEnumeration       ne = new ArrayNamingEnumeration(new Object[] { sr });
        if (! broken)
            ne = new AvoidEscapingNamingEnumeration(baseName, ne);
        broken = !broken;
        return ne;
    }

    public Attributes lookup(final Name dn) throws NamingException {
        log.debug("Looking up \""+dn+"\"");
        return null;
    }

    public Attributes lookup(final Name dn, final String[] attrIds)
            throws NamingException
    {
        log.debug("Looking up \""+dn+"\"");
        return null;
    }

    public boolean hasEntry(final Name name) throws NamingException
    {
        final Attributes        attrs;

        log.info("Checking \""+name+"\"");
        return true;
    }

    public void modifyRn(final Name name, final String newRn,
            final boolean deleteOldRn) throws NamingException
    {
    }

    public void move(final Name oriChildName, final Name newParentName)
            throws NamingException
    {
    }

    public void move(final Name oriChildName, final Name newParentName,
            final String newRn, final boolean deleteOldRn)
            throws NamingException
    {
    }

    public void sync() throws NamingException {
        //log.info("sync();");
    }

    public void close() throws NamingException {
    }

    public boolean isClosed() {
        //Logger log = Logger.getLogger(LDAPProxyPartition.class);
        //log.info("isClosed();");
        return false;
    }
}
