/*
 *  Copyright 2004 The Apache Software Foundation 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package org.apache.slide.util;

import org.apache.slide.common.Namespace;
import org.apache.slide.common.NamespaceConfig;
import org.apache.slide.content.Content;
import org.apache.slide.content.ContentImpl;
import org.apache.slide.lock.Lock;
import org.apache.slide.lock.LockImpl;
import org.apache.slide.macro.Macro;
import org.apache.slide.macro.MacroImpl;
import org.apache.slide.search.Search;
import org.apache.slide.search.SearchImpl;
import org.apache.slide.security.ACLSecurityImpl;
import org.apache.slide.security.Security;
import org.apache.slide.security.SecurityImpl;
import org.apache.slide.security.SecurityImplAllGrant;
import org.apache.slide.structure.Structure;
import org.apache.slide.structure.StructureImpl;
import org.apache.slide.util.logger.Logger;

/**
 * Static methods to aid in accessing a {@link NamespaceConfig}
 */
public class NamespaceConfigUtil {
    
    private static final String LOG_CHANNEL = NamespaceConfigUtil.class.toString();
    
    // Parameter names from Domain configuration file
    private static String ACL_SEMANTICS                  = "acl_semantics";
    private static String ALL_GRANT_BEFORE_DENY          = "all-grant-before-any-deny";
    private static String LEGACY_ALL_GRANT_BEFORE_DENY   = "legacy-all-grant-before-any-deny";
    
    private static String LOCK_IMPLEMENTATION_PARAM      = "lock-implementation-class";
    private static String STRUCTURE_IMPLEMENTATION_PARAM = "structure-implementation-class";
    private static String CONTENT_IMPLEMENTATION_PARAM   = "content-implementation-class";
    private static String SEARCH_IMPLEMENTATION_PARAM    = "search-implementation-class";
    private static String MACRO_IMPLEMENTATION_PARAM     = "macro-implementation-class";
    
    /**
     * NamespaceConfigUtil cannot be instantiated.
     */
    private NamespaceConfigUtil() {}
    
    /**
     * Returns a new instance of the {@link Security} implementation for the given {@link Namespace}.
     * 
     * @param namespace the {@link Namespace} to interogate
     * @return the {@link Security} implementation for the namespace
     */
    public static Security getSecurityImplementation(Namespace namespace) {
        Security securityHelper = null;
        NamespaceConfig config = namespace.getConfig();
        if (config != null) {
            String acl_semantics = config.getParameter(ACL_SEMANTICS);
            if ((acl_semantics != null) && (acl_semantics.equals(LEGACY_ALL_GRANT_BEFORE_DENY ))) {
                securityHelper = new SecurityImpl(namespace, namespace.getConfig());
            } else if((acl_semantics != null) && (acl_semantics.equals(ALL_GRANT_BEFORE_DENY ))) {
                securityHelper = new SecurityImplAllGrant(namespace, namespace.getConfig());
            } else if (acl_semantics != null) {
                try {
                    securityHelper = (Security) Class.forName(acl_semantics).newInstance();
                    if (securityHelper != null) {
                        securityHelper.init(namespace, namespace.getConfig());
                    }
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        // Default implementation
        if (securityHelper == null) {
            securityHelper = new ACLSecurityImpl(namespace, namespace.getConfig());
        }
        return securityHelper;
    }
    
    /**
     * Returns a new instance of the {@link Lock} implementation for the given {@link Namespace}.
     * 
     * @param namespace the {@link Namespace} to interogate
     * @return the {@link Lock} implementation for the namespace
     */
    public static Lock getLockImplementation(Namespace namespace) {
        return getLockImplementation(namespace, getSecurityImplementation(namespace));
    }

    /**
     * Returns a new instance of the {@link Lock} implementation for the given {@link Namespace}.
     * 
     * @param namespace the {@link Namespace} to interogate
     * @param security the {@link Security} implementation used to initialize the {@link Lock}
     * @return the {@link Lock} implementation for the namespace
     */
    public static Lock getLockImplementation(Namespace namespace, Security security) {
        Lock lockHelper = null;
        NamespaceConfig config = namespace.getConfig();
        if (config != null) {
            String lockImplemenation = config.getParameter(LOCK_IMPLEMENTATION_PARAM);
            if (lockImplemenation != null) {
                try {
                    lockHelper = (Lock) Class.forName(
                            lockImplemenation).getConstructor(
                                    new Class[] {
                                            namespace.getClass(),
                                            config.getClass(),
                                            Security.class}
                                    ).newInstance(
                                            new Object[] {
                                                    namespace,
                                                    config,
                                                    security});
                } catch (Exception e) {
                    namespace.getLogger().log(
                            "Cannot create Lock instance of type: " + lockImplemenation,
                            e, LOG_CHANNEL, Logger.ERROR);
                }
            }
        }
        // Default implementation
        if (lockHelper == null) {
            lockHelper = new LockImpl(namespace, namespace.getConfig(), security);
        }
        return lockHelper;
    }
    
    /**
     * Returns a new instance of the {@link Structure} implementation for the given {@link Namespace}.
     * 
     * @param namespace the {@link Namespace} to interogate
     * @return the {@link Structure} implementation for the namespace
     */
    public static Structure getStructureImplementation(Namespace namespace) {
        Security security = getSecurityImplementation(namespace);
        Lock lock = getLockImplementation(namespace, security);
        return getStructureImplementation(namespace, security, lock);
    }

    /**
     * Returns a new instance of the {@link Structure} implementation for the given {@link Namespace}.
     * 
     * @param namespace the {@link Namespace} to interogate
     * @param security the {@link Security} implementation used to initialize the {@link Structure}
     * @param lock the {@link Lock} implementation used to initialize the {@link Structure}
     * @return the {@link Structure} implementation for the namespace
     */
    public static Structure getStructureImplementation(Namespace namespace, Security security, Lock lock) {
        Structure structureHelper = null;
        NamespaceConfig config = namespace.getConfig();
        if (config != null) {
            String structureImplemenation = config.getParameter(STRUCTURE_IMPLEMENTATION_PARAM);
            if (structureImplemenation != null) {
                try {
                    structureHelper = (Structure) Class.forName(
                            structureImplemenation).getConstructor(
                                    new Class[] {
                                            namespace.getClass(),
                                            config.getClass(),
                                            Security.class,
                                            Lock.class}
                                    ).newInstance(
                                            new Object[] {
                                                    namespace,
                                                    config,
                                                    security,
                                                    lock});
                } catch (Exception e) {
                    namespace.getLogger().log(
                            "Cannot create Structure instance of type: " + structureImplemenation,
                            e, LOG_CHANNEL, Logger.ERROR);
                }
            }
        }
        // Default implementation
        if (structureHelper == null) {
            structureHelper = new StructureImpl(namespace, namespace.getConfig(), security, lock);
        }
        return structureHelper;
    }
    
    /**
     * Returns a new instance of the {@link Content} implementation for the given {@link Namespace}.
     * 
     * @param namespace the {@link Namespace} to interogate
     * @return the {@link Content} implementation for the namespace
     */
    public static Content getContentImplementation(Namespace namespace) {
        Security security = getSecurityImplementation(namespace);
        Lock lock = getLockImplementation(namespace, security);
        Structure structure = getStructureImplementation(namespace, security, lock);
        return getContentImplementation(namespace, security, structure, lock);
    }

    /**
     * Returns a new instance of the {@link Content} implementation for the given {@link Namespace}.
     * 
     * @param namespace the {@link Namespace} to interogate
     * @param security the {@link Security} implementation used to initialize the {@link Content}
     * @param structure the {@link Structure} implementation used to initialize the {@link Content}
     * @param lock the {@link Lock} implementation used to initialize the {@link Content}
     * @return the {@link Content} implementation for the namespace
     */
    public static Content getContentImplementation(Namespace namespace, Security security, Structure structure, Lock lock) {
        Content contentHelper = null;
        NamespaceConfig config = namespace.getConfig();
        if (config != null) {
            String contentImplemenation = config.getParameter(CONTENT_IMPLEMENTATION_PARAM);
            if (contentImplemenation != null) {
                try {
                    contentHelper = (Content) Class.forName(
                            contentImplemenation).getConstructor(
                                    new Class[] {
                                            namespace.getClass(),
                                            config.getClass(),
                                            Security.class,
                                            Structure.class,
                                            Lock.class}
                                    ).newInstance(
                                            new Object[] {
                                                    namespace,
                                                    config,
                                                    security,
                                                    structure,
                                                    lock});
                } catch (Exception e) {
                    namespace.getLogger().log(
                            "Cannot create Content instance of type: " + contentImplemenation,
                            e, LOG_CHANNEL, Logger.ERROR);
                }
            }
        }
        // Default implementation
        if (contentHelper == null) {
            contentHelper = new ContentImpl(namespace, namespace.getConfig(), security, structure, lock);
        }
        return contentHelper;
    }
    
    /**
     * Returns a new instance of the {@link Search} implementation for the given {@link Namespace}.
     * 
     * @param namespace the {@link Namespace} to interogate
     * @return the {@link Search} implementation for the namespace
     */
    public static Search getSearchImplementation(Namespace namespace) {
        Security security = getSecurityImplementation(namespace);
        Lock lock = getLockImplementation(namespace, security);
        Structure structure = getStructureImplementation(namespace, security, lock);
        Content content = getContentImplementation(namespace, security, structure, lock);
        return getSearchImplementation(namespace, structure, content);
    }

    /**
     * Returns a new instance of the {@link Search} implementation for the given {@link Namespace}.
     * 
     * @param namespace the {@link Namespace} to interogate
     * @param structure the {@link Structure} implementation used to initialize the {@link Search}
     * @param content the {@link Content} implementation used to initialize the {@link Search}
     * @return the {@link Search} implementation for the namespace
     */
    public static Search getSearchImplementation(Namespace namespace, Structure structure, Content content) {
        Search searchHelper = null;
        NamespaceConfig config = namespace.getConfig();
        if (config != null) {
            String searchImplemenation = config.getParameter(SEARCH_IMPLEMENTATION_PARAM);
            if (searchImplemenation != null) {
                try {
                    searchHelper = (Search) Class.forName(
                            searchImplemenation).getConstructor(
                                    new Class[] {
                                            namespace.getClass(),
                                            config.getClass(),
                                            Structure.class,
                                            Content.class}
                                    ).newInstance(
                                            new Object[] {
                                                    namespace,
                                                    config,
                                                    structure,
                                                    content});
                } catch (Exception e) {
                    namespace.getLogger().log(
                            "Cannot create Search instance of type: " + searchImplemenation,
                            e, LOG_CHANNEL, Logger.ERROR);
                }
            }
        }
        // Default implementation
        if (searchHelper == null) {
            searchHelper = new SearchImpl(namespace, namespace.getConfig(), structure, content);
        }
        return searchHelper;
    }
    
    /**
     * Returns a new instance of the {@link Macro} implementation for the given {@link Namespace}.
     * 
     * @param namespace the {@link Namespace} to interogate
     * @return the {@link Macro} implementation for the namespace
     */
    public static Macro getMacroImplementation(Namespace namespace) {
        Security security = getSecurityImplementation(namespace);
        Lock lock = getLockImplementation(namespace, security);
        Structure structure = getStructureImplementation(namespace, security, lock);
        Content content = getContentImplementation(namespace, security, structure, lock);
        return getMacroImplementation(namespace, security, content, structure, lock);
    }

    /**
     * Returns a new instance of the {@link Macro} implementation for the given {@link Namespace}.
     * 
     * @param namespace the {@link Namespace} to interogate
     * @param security the {@link Security} implementation used to initialize the {@link Macro}
     * @param content the {@link Content} implementation used to initialize the {@link Macro}
     * @param structure the {@link Structure} implementation used to initialize the {@link Macro}
     * @param lock the {@link Lock} implementation used to initialize the {@link Macro}
     * @return the {@link Macro} implementation for the namespace
     */
    public static Macro getMacroImplementation(Namespace namespace, Security security, Content content, Structure structure, Lock lock) {
        Macro macroHelper = null;
        NamespaceConfig config = namespace.getConfig();
        if (config != null) {
            String macroImplemenation = config.getParameter(MACRO_IMPLEMENTATION_PARAM);
            if (macroImplemenation != null) {
                try {
                    macroHelper = (Macro) Class.forName(
                            macroImplemenation).getConstructor(
                                    new Class[] {
                                            namespace.getClass(),
                                            config.getClass(),
                                            Security.class,
                                            Content.class,
                                            Structure.class,
                                            Lock.class}
                                    ).newInstance(
                                            new Object[] {
                                                    namespace,
                                                    config,
                                                    security,
                                                    content,
                                                    structure,
                                                    lock});
                } catch (Exception e) {
                    namespace.getLogger().log(
                            "Cannot create Macro instance of type: " + macroImplemenation,
                            e, LOG_CHANNEL, Logger.ERROR);
                }
            }
        }
        // Default implementation
        if (macroHelper == null) {
            macroHelper = new MacroImpl(namespace, namespace.getConfig(), security, content, structure, lock);
        }
        return macroHelper;
    }

}
