/*
 * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.jndi.ldap;

import javax.naming.*;
import javax.naming.directory.*;
import java.util.Hashtable;
import com.sun.jndi.toolkit.dir.HierMemDirCtx;

/**
 * This is the class used to implement LDAP's GetSchema call.
 *
 * It subclasses HierMemDirContext for most of the functionality. It
 * overrides functions that cause the schema definitions to change.
 * In such a case, it write the schema to the LdapServer and (assuming
 * there are no errors), calls it's superclass's equivalent function.
 * Thus, the schema tree and the LDAP server's schema attributes are
 * always in sync.
 */

final class LdapSchemaCtx extends HierMemDirCtx {

    static private final boolean debug = false;

    private static final int LEAF = 0;  // schema object (e.g. attribute type defn)
    private static final int SCHEMA_ROOT = 1;   // schema tree root
    static final int OBJECTCLASS_ROOT = 2;   // root of object class subtree
    static final int ATTRIBUTE_ROOT = 3;     // root of attribute type subtree
    static final int SYNTAX_ROOT = 4;        // root of syntax subtree
    static final int MATCHRULE_ROOT = 5;     // root of matching rule subtree
    static final int OBJECTCLASS = 6;   // an object class definition
    static final int ATTRIBUTE = 7;     // an attribute type definition
    static final int SYNTAX = 8;        // a syntax definition
    static final int MATCHRULE = 9;     // a matching rule definition

    private SchemaInfo info= null;
    private boolean setupMode = true;

    private int objectType;

    static DirContext createSchemaTree(Hashtable<String,Object> env,
            String subschemasubentry, LdapCtx schemaEntry,
            Attributes schemaAttrs, boolean netscapeBug)
        throws NamingException {
            try {
                LdapSchemaParser parser = new LdapSchemaParser(netscapeBug);

                SchemaInfo allinfo = new SchemaInfo(subschemasubentry,
                    schemaEntry, parser);

                LdapSchemaCtx root = new LdapSchemaCtx(SCHEMA_ROOT, env, allinfo);
                LdapSchemaParser.LDAP2JNDISchema(schemaAttrs, root);
                return root;
            } catch (NamingException e) {
                schemaEntry.close(); // cleanup
                throw e;
            }
    }

    // Called by createNewCtx
    private LdapSchemaCtx(int objectType, Hashtable<String,Object> environment,
                          SchemaInfo info) {
        super(environment, LdapClient.caseIgnore);

        this.objectType = objectType;
        this.info = info;
    }

    // override HierMemDirCtx.close to prevent premature GC of shared data
    public void close() throws NamingException {
        info.close();
    }

    // override to ignore obj and use attrs
    // treat same as createSubcontext
    final public void bind(Name name, Object obj, Attributes attrs)
        throws NamingException {
        if (!setupMode) {
            if (obj != null) {
                throw new IllegalArgumentException("obj must be null");
            }

            // Update server
            addServerSchema(attrs);
        }

        // Update in-memory copy
        LdapSchemaCtx newEntry =
            (LdapSchemaCtx)super.doCreateSubcontext(name, attrs);
    }

    final protected void doBind(Name name, Object obj, Attributes attrs,
        boolean useFactory) throws NamingException {
        if (!setupMode) {
            throw new SchemaViolationException(
                "Cannot bind arbitrary object; use createSubcontext()");
        } else {
            super.doBind(name, obj, attrs, false); // always ignore factories
        }
    }

    // override to use bind() instead
    final public void rebind(Name name, Object obj, Attributes attrs)
        throws NamingException {
        try {
            doLookup(name, false);
            throw new SchemaViolationException(
                "Cannot replace existing schema object");
        } catch (NameNotFoundException e) {
            bind(name, obj, attrs);
        }
    }

    final protected void doRebind(Name name, Object obj, Attributes attrs,
        boolean useFactory) throws NamingException {
        if (!setupMode) {
            throw new SchemaViolationException(
                "Cannot bind arbitrary object; use createSubcontext()");
        } else {
            super.doRebind(name, obj, attrs, false); // always ignore factories
        }
    }

    final protected void doUnbind(Name name) throws NamingException {
        if (!setupMode) {
            // Update server
            try {
                // Lookup entry from memory
                LdapSchemaCtx target = (LdapSchemaCtx)doLookup(name, false);

                deleteServerSchema(target.attrs);
            } catch (NameNotFoundException e) {
                return;
            }
        }
        // Update in-memory copy
        super.doUnbind(name);
    }

    final protected void doRename(Name oldname, Name newname)
        throws NamingException {
        if (!setupMode) {
            throw new SchemaViolationException("Cannot rename a schema object");
        } else {
            super.doRename(oldname, newname);
        }
    }

    final protected void doDestroySubcontext(Name name) throws NamingException {
        if (!setupMode) {
            // Update server
            try {
                // Lookup entry from memory
                LdapSchemaCtx target = (LdapSchemaCtx)doLookup(name, false);

                deleteServerSchema(target.attrs);
            } catch (NameNotFoundException e) {
                return;
            }
        }

        // Update in-memory copy
        super.doDestroySubcontext(name);
     }

    // Called to create oc, attr, syntax or matching rule roots and leaf entries
    final LdapSchemaCtx setup(int objectType, String name, Attributes attrs)
        throws NamingException{
            try {
                setupMode = true;
                LdapSchemaCtx answer =
                    (LdapSchemaCtx) super.doCreateSubcontext(
                        new CompositeName(name), attrs);

                answer.objectType = objectType;
                answer.setupMode = false;
                return answer;
            } finally {
                setupMode = false;
            }
    }

    final protected DirContext doCreateSubcontext(Name name, Attributes attrs)
        throws NamingException {

        if (attrs == null || attrs.size() == 0) {
            throw new SchemaViolationException(
                "Must supply attributes describing schema");
        }

        if (!setupMode) {
            // Update server
            addServerSchema(attrs);
        }

        // Update in-memory copy
        LdapSchemaCtx newEntry =
            (LdapSchemaCtx) super.doCreateSubcontext(name, attrs);
        return newEntry;
    }

    final private static Attributes deepClone(Attributes orig)
        throws NamingException {
        BasicAttributes copy = new BasicAttributes(true);
        NamingEnumeration<? extends Attribute> attrs = orig.getAll();
        while (attrs.hasMore()) {
            copy.put((Attribute)attrs.next().clone());
        }
        return copy;
    }

    final protected void doModifyAttributes(ModificationItem[] mods)
        throws NamingException {
        if (setupMode) {
            super.doModifyAttributes(mods);
        } else {
            Attributes copy = deepClone(attrs);

            // Apply modifications to copy
            applyMods(mods, copy);

            // Update server copy
            modifyServerSchema(attrs, copy);

            // Update in-memory copy
            attrs = copy;
        }
    }

    // we override this so the superclass creates the right kind of contexts
    // Default is to create LEAF objects; caller will change after creation
    // if necessary
    final protected HierMemDirCtx createNewCtx() {
        LdapSchemaCtx ctx = new LdapSchemaCtx(LEAF, myEnv, info);
        return ctx;
    }


    final private void addServerSchema(Attributes attrs)
        throws NamingException {
        Attribute schemaAttr;

        switch (objectType) {
        case OBJECTCLASS_ROOT:
            schemaAttr = info.parser.stringifyObjDesc(attrs);
            break;

        case ATTRIBUTE_ROOT:
            schemaAttr = info.parser.stringifyAttrDesc(attrs);
            break;

        case SYNTAX_ROOT:
            schemaAttr = info.parser.stringifySyntaxDesc(attrs);
            break;

        case MATCHRULE_ROOT:
            schemaAttr = info.parser.stringifyMatchRuleDesc(attrs);
            break;

        case SCHEMA_ROOT:
            throw new SchemaViolationException(
                "Cannot create new entry under schema root");

        default:
            throw new SchemaViolationException(
                "Cannot create child of schema object");
        }

        Attributes holder = new BasicAttributes(true);
        holder.put(schemaAttr);
        //System.err.println((String)schemaAttr.get());

        info.modifyAttributes(myEnv, DirContext.ADD_ATTRIBUTE, holder);

    }

    /**
      * When we delete an entry, we use the original to make sure that
      * any formatting inconsistencies are eliminated.
      * This is because we're just deleting a value from an attribute
      * on the server and there might not be any checks for extra spaces
      * or parens.
      */
    final private void deleteServerSchema(Attributes origAttrs)
        throws NamingException {

        Attribute origAttrVal;

        switch (objectType) {
        case OBJECTCLASS_ROOT:
            origAttrVal = info.parser.stringifyObjDesc(origAttrs);
            break;

        case ATTRIBUTE_ROOT:
            origAttrVal = info.parser.stringifyAttrDesc(origAttrs);
            break;

        case SYNTAX_ROOT:
            origAttrVal = info.parser.stringifySyntaxDesc(origAttrs);
            break;

        case MATCHRULE_ROOT:
            origAttrVal = info.parser.stringifyMatchRuleDesc(origAttrs);
            break;

        case SCHEMA_ROOT:
            throw new SchemaViolationException(
                "Cannot delete schema root");

        default:
            throw new SchemaViolationException(
                "Cannot delete child of schema object");
        }

        ModificationItem[] mods = new ModificationItem[1];
        mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, origAttrVal);

        info.modifyAttributes(myEnv, mods);
    }

    /**
      * When we modify an entry, we use the original attribute value
      * in the schema to make sure that any formatting inconsistencies
      * are eliminated. A modification is done by deleting the original
      * value and adding a new value with the modification.
      */
    final private void modifyServerSchema(Attributes origAttrs,
        Attributes newAttrs) throws NamingException {

        Attribute newAttrVal;
        Attribute origAttrVal;

        switch (objectType) {
        case OBJECTCLASS:
            origAttrVal = info.parser.stringifyObjDesc(origAttrs);
            newAttrVal = info.parser.stringifyObjDesc(newAttrs);
            break;

        case ATTRIBUTE:
            origAttrVal = info.parser.stringifyAttrDesc(origAttrs);
            newAttrVal = info.parser.stringifyAttrDesc(newAttrs);
            break;

        case SYNTAX:
            origAttrVal = info.parser.stringifySyntaxDesc(origAttrs);
            newAttrVal = info.parser.stringifySyntaxDesc(newAttrs);
            break;

        case MATCHRULE:
            origAttrVal = info.parser.stringifyMatchRuleDesc(origAttrs);
            newAttrVal = info.parser.stringifyMatchRuleDesc(newAttrs);
            break;

        default:
            throw new SchemaViolationException(
                "Cannot modify schema root");
        }

        ModificationItem[] mods = new ModificationItem[2];
        mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, origAttrVal);
        mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE, newAttrVal);

        info.modifyAttributes(myEnv, mods);
    }

    final static private class SchemaInfo {
        private LdapCtx schemaEntry;
        private String schemaEntryName;
        LdapSchemaParser parser;
        private String host;
        private int port;
        private boolean hasLdapsScheme;

        SchemaInfo(String schemaEntryName, LdapCtx schemaEntry,
            LdapSchemaParser parser) {
            this.schemaEntryName = schemaEntryName;
            this.schemaEntry = schemaEntry;
            this.parser = parser;
            this.port = schemaEntry.port_number;
            this.host = schemaEntry.hostname;
            this.hasLdapsScheme = schemaEntry.hasLdapsScheme;
        }

        synchronized void close() throws NamingException {
            if (schemaEntry != null) {
                schemaEntry.close();
                schemaEntry = null;
            }
        }

        private LdapCtx reopenEntry(Hashtable<?,?> env) throws NamingException {
            // Use subschemasubentry name as DN
            return new LdapCtx(schemaEntryName, host, port,
                                env, hasLdapsScheme);
        }

        synchronized void modifyAttributes(Hashtable<?,?> env,
                                           ModificationItem[] mods)
            throws NamingException {
            if (schemaEntry == null) {
                schemaEntry = reopenEntry(env);
            }
            schemaEntry.modifyAttributes("", mods);
        }

        synchronized void modifyAttributes(Hashtable<?,?> env, int mod,
            Attributes attrs) throws NamingException {
            if (schemaEntry == null) {
                schemaEntry = reopenEntry(env);
            }
            schemaEntry.modifyAttributes("", mod, attrs);
        }
    }
}
