/*
 * Copyright (c) 1999, 2003, 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 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);
                parser.LDAP2JNDISchema(schemaAttrs, root);
                return root;
            } catch (NamingException e) {
                schemaEntry.close(); // cleanup
                throw e;
            }
    }

    // Called by createNewCtx
    private LdapSchemaCtx(int objectType, Hashtable 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 attrs = orig.getAll();
        while (attrs.hasMore()) {
            copy.put((Attribute)((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);
        }
    }
}
