/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/datastore/schema/XKnownPropertyHelper.java,v 1.4 2004/09/15 14:58:26 pnever Exp $
 * $Revision: 1.4 $
 * $Date: 2004/09/15 14:58:26 $
 *
 * ====================================================================
 *
 * Copyright 1999-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.store.tamino.datastore.schema;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.store.tamino.common.XGlobals;
import org.apache.slide.util.XAssertionFailed;
import org.jdom.Namespace;

/**
 * contains a static list of properties with their datatype, that should get
 * their own elements in the metadata schema.
 *
 * @author martin.wallmer@softwareag.com
 *
 * @version $Revision: 1.4 $
 */
public class XKnownPropertyHelper implements KnownPropertyList {


    private static final Namespace  DEFAULT_NAMESPACE =
        Namespace.getNamespace ("D", NodeProperty.DEFAULT_NAMESPACE);

    private static final Namespace TAMINO_NAMESPACE =
        Namespace.getNamespace (XGlobals.TAMINO_NAMESPACE_PREFIX, XGlobals.TAMINO_NAMESPACE_URI);

    private static XKnownProperty [] propArray =  {

        // WebDAV properties
        new XKnownProperty ("creationdate", DEFAULT_NAMESPACE, "xs:dateTime"),
            new XKnownProperty ("modificationdate", DEFAULT_NAMESPACE, "xs:dateTime"),
            new XKnownProperty ("getcontentlanguage", DEFAULT_NAMESPACE, "xs:string"),
            new XKnownProperty ("getcontentlength", DEFAULT_NAMESPACE, "xs:long"),
            new XKnownProperty ("getcontenttype", DEFAULT_NAMESPACE, "xs:string"),
            new XKnownProperty ("getetag", DEFAULT_NAMESPACE, "xs:string", false, false),
            new XKnownProperty ("resourcetype", DEFAULT_NAMESPACE, "xs:string", true, true),
            new XKnownProperty ("supportedlock", DEFAULT_NAMESPACE, "xs:string"),
            // as getlastmodified is in a weird microsoft specific date format, handle as string
            new XKnownProperty ("getlastmodified", DEFAULT_NAMESPACE, "xs:string"),
            new XKnownProperty ("lockdiscovery", DEFAULT_NAMESPACE, "xs:string"),
            new XKnownProperty ("source", DEFAULT_NAMESPACE, "xs:string"),

            // ACL properties
            new XKnownProperty ("alternate-URI-set", DEFAULT_NAMESPACE, "xs:string"),
            new XKnownProperty ("owner", DEFAULT_NAMESPACE, "xs:string"),
            new XKnownProperty ("creationuser", DEFAULT_NAMESPACE, "xs:string"),
            new XKnownProperty ("modificationuser", DEFAULT_NAMESPACE, "xs:string"),
            new XKnownProperty ("supported-privilege-set", DEFAULT_NAMESPACE, "xs:string"),
            new XKnownProperty ("current-user-privilege-set", DEFAULT_NAMESPACE, "xs:string"),
            new XKnownProperty ("acl", DEFAULT_NAMESPACE, "xs:string"),
            new XKnownProperty ("acl-semantics", DEFAULT_NAMESPACE, "xs:string"),
            new XKnownProperty ("principal-collection-set", DEFAULT_NAMESPACE, "xs:string"),
            new XKnownProperty ("ace", DEFAULT_NAMESPACE, "xs:string"),

            // Bind properties
            new XKnownProperty ("resource-id", DEFAULT_NAMESPACE, "xs:string"),
            new XKnownProperty ("parent-set", DEFAULT_NAMESPACE, "xs:string"),

            // DeltaV properties
            new XKnownProperty ("version-history", DEFAULT_NAMESPACE, "xs:string"),
            
            // xdav properties
            new XKnownProperty ("xdavContentId", TAMINO_NAMESPACE, "xs:string"),
            new XKnownProperty ("isXml", TAMINO_NAMESPACE, "xs:boolean")
    };

    /** key: namespace. value: set of propertynames */
    private Map propMap;

    /** key: namespaceUri, value: prefix */
    private Map namespaceMap;

    /** dummy set to return an empty Iterator */
    private Set emptySet;

    private boolean useKnowProperties;

    /** a singleton instance for each schema language */
    private static Map singletonMap = new HashMap ();

    /**
     * prevent from instantiating
     *
     */
    private XKnownPropertyHelper (String tsdLanguage) {
        if (tsdLanguage.equals (XGlobals.TSD4_SCHEMA_VERSION))
            useKnowProperties = true;
        else
            useKnowProperties = false;

        Map tmpPropMap = new HashMap();
        Map tmpNamespaceMap = new HashMap();
        for (int i = 0; i < propArray.length; i++) {
            Namespace namespace = propArray [i].getNamespace();
            tmpNamespaceMap.put (namespace.getURI(), namespace.getPrefix());
            Set propList = (Set)tmpPropMap.get (namespace);
            if (propList == null) {
                propList = new HashSet();
                tmpPropMap.put (namespace, propList);
            }
            propList.add (propArray [i]);
        }
        propMap = Collections.unmodifiableMap (tmpPropMap);
        namespaceMap = Collections.unmodifiableMap (tmpNamespaceMap);
        emptySet = Collections.unmodifiableSet (new HashSet (0));
    }

    /**
     * Method knownPropertyIterator
     *
     * @return   iterator over all indexed properties in given namespace
     *
     */
    public Iterator knownPropertyIterator (Namespace namespace) {
        Iterator result;

        if (useKnowProperties) {
            Set propSet = (Set)propMap.get (namespace);
            if (propSet == null) throw new XAssertionFailed();
            result = propSet.iterator();
        }
        else {
            result = emptySet.iterator();
        }
        return result;
    }

    /**
     * Method getNamespaceIterator
     *
     * @return   iterator of the namespaces of all known properties
     *
     */
    public Iterator getNamespaceIterator() {
        if (useKnowProperties)
            return propMap.keySet().iterator();
        else
            return emptySet.iterator();
    }

    /**
     * checks, if a NodeProperty is a known property
     *
     * @param    nodeProperty        a  NodeProperty
     *
     * @return   a boolean
     *
     */
    public boolean isKnown (NodeProperty nodeProperty) {
        return isKnown (nodeProperty.getName(), nodeProperty.getNamespace());
    }

    /**
     * checks, if a property identified by name and namespace is a known
     * property.
     *
     * @param    name                a  String
     * @param    namespace           a  String
     *
     * @return   a boolean
     *
     */
    public boolean isKnown (String name, String namespace) {
        Namespace ns = Namespace.getNamespace (namespace);
        return isKnown (name, ns);
    }

    public boolean isKnown (String name, Namespace ns) {
        boolean result = false;

        if (useKnowProperties) {
            Set props = (Set) propMap.get (ns);
            result = props != null && props.contains(new XKnownProperty(name, ns, null));
        }
        return result;
    }

    public String getPrefix (String namespace) {
        if (useKnowProperties)
            return (String) namespaceMap.get (namespace);
        else
            return "";
    }

    /**
     * only way to get an instance. There is an instance for each tsd language
     *
     * @param    schemaLanguage      a  String
     *
     * @return   a KnownPropertyList
     *
     */
    public static KnownPropertyList getKnownPropertyList (String schemaLanguage) {
        XKnownPropertyHelper helper = (XKnownPropertyHelper)singletonMap.get (schemaLanguage);
        if (helper == null) {
            helper = new XKnownPropertyHelper (schemaLanguage);
            singletonMap.put (schemaLanguage, helper);
        }
        return helper;
    }
}


/**
 * describes a property and how the tamino schema shall be generated for it.
 * By default, standard index = true, text index = false
 */
class XKnownProperty implements KnownProperty {


    private String name;
    private Namespace namespace;
    private String dataType;
    private boolean standardIndex;
    private boolean textIndex;

    /**
     * Constructor
     *
     * @param    name                a  String
     * @param    namespace           a  String
     * @param    dataType            as defined in xml schema, with (xs:) namespaceprefix
     *
     */
    public XKnownProperty (String name, Namespace namespace, String dataType) {
        this (name, namespace, dataType, true, false);
    }

    XKnownProperty (String name, Namespace namespace, String dataType,
                    boolean isStandardIndex,
                    boolean isTextIndex) {
        this.name = name;
        this.namespace = namespace;
        this.dataType = dataType;
        this.standardIndex = isStandardIndex;
        this.textIndex = isTextIndex;
    }

    /**
     * Method getNamespace
     *
     * @return   a String
     *
     */
    public Namespace getNamespace() {
        return namespace;
    }

    /**
     * Method getDataType
     *
     * @return   a String
     *
     */
    public String getDataType() {
        return dataType;
    }

    /**
     * Method getName
     *
     * @return   a String
     *
     */
    public String getName() {
        return name;
    }

    /**
     * Method isStandardIndexed
     *
     * @return   true, if for this property a standardIndex shall be produced
     *
     */
    public boolean isStandardIndexed() {
        return standardIndex;
    }

    /**
     * Method isTextIndexed
     *
     * @return   true, if for this property a textIndex shall be produced
     *
     */
    public boolean isTextIndexed() {
        return textIndex;
    }

    public String toString () {
        return name + ":" + namespace.toString() + "@" + dataType + "@standard: " + standardIndex + "@text: " + textIndex;
    }


    public boolean equals(Object that) {
        return (that instanceof KnownProperty) && ((KnownProperty)that).getName().equals(this.getName());
    }

    public int hashCode() {
        return this.getName().hashCode();
    }


}
