/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/tools/stores/XStoreAspects.java,v 1.1 2004/03/25 16:18:06 juergen Exp $
 * $Revision: 1.1 $
 * $Date: 2004/03/25 16:18:06 $
 *
 * ====================================================================
 *
 * 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.tools.stores;


import java.util.List;
import org.apache.slide.store.tamino.store.XContentStore;
import org.apache.slide.store.tamino.store.XDescriptorsStore;
import org.apache.slide.store.tamino.store.XPermissionStore;
import org.apache.slide.store.tamino.tools.stores.XDomainConstants;
import org.apache.slide.store.txfile.TxFileContentStore;
import org.apache.slide.store.txfile.TxXMLFileDescriptorsStore;
import org.apache.slide.util.JDom;
import org.apache.slide.util.XAssertionFailed;
import org.apache.slide.util.XException;
import org.jdom.Element;

public class XStoreAspects {
    private static final String[] ASPECTS = {
        "nodestore", "contentstore", "securitystore", "lockstore",
            "revisiondescriptorstore", "revisiondescriptorsstore"
    };
    
    private static final Parameters NO_PARAS = new Parameters();
    
    public static final Integer NODE_REF = new Integer(0);
    
    public static final XStoreAspects TAMINO_ASPECTS = new XStoreAspects(
        XDescriptorsStore.class.getName(), XContentStore.class.getName(), XPermissionStore.class.getName());
    public static final XStoreAspects TXFILE_ASPECTS = new XStoreAspects(
        TxXMLFileDescriptorsStore.class.getName(), TxFileContentStore.class.getName(),
        XStoreAspects.NODE_REF, XStoreAspects.NODE_REF, XStoreAspects.NODE_REF, XStoreAspects.NODE_REF,
        new Parameters().set("rootpath", "${store}/store/metadata").set("workpath", "${store}/work/metadata"),
        new Parameters().set("rootpath", "${store}/store/content").set("workpath", "${store}/work/content"),
        NO_PARAS, NO_PARAS, NO_PARAS, NO_PARAS
    );
    public static final XStoreAspects FILE_ASPECTS = new XStoreAspects(
        XDescriptorsStore.class.getName(), XDomainConstants.FILESTORE, XPermissionStore.class.getName());
    
    //--
    
    /**
     ** Class name or Integer for reference to other store. Parallel to ASPECTS.
     **/
    private final Object[] aspects;
    private final Parameters[] parameters;
    
    public XStoreAspects(String nodeStore) {
        this(nodeStore, NODE_REF, NODE_REF, NODE_REF, NODE_REF, NODE_REF);
    }
    
    public XStoreAspects(String nodeStore, String permissionStore) {
        this(nodeStore, NODE_REF, permissionStore, NODE_REF, NODE_REF, NODE_REF);
    }
    
    public XStoreAspects(String nodeStore, String contentStore, String permissionStore) {
        this(nodeStore, contentStore, permissionStore, NODE_REF, NODE_REF, NODE_REF);
    }
    
    public XStoreAspects(Object nodeStore, Object contentStore, Object securityStore,
                         Object lockStore, Object revisionDescriptorStore, Object revisionDescriptorsStore) {
        this(nodeStore, contentStore, securityStore, lockStore, revisionDescriptorStore, revisionDescriptorsStore,
             NO_PARAS, NO_PARAS, NO_PARAS, NO_PARAS, NO_PARAS, NO_PARAS);
    }
    public XStoreAspects(Object nodeStore, Object contentStore, Object securityStore,
                         Object lockStore, Object revisionDescriptorStore, Object revisionDescriptorsStore,
                         Parameters nodeParas, Parameters contentParas, Parameters securityParas,
                         Parameters lockParas, Parameters rdParas, Parameters rdsParas) {
        this(new Object[] { nodeStore, contentStore, securityStore,
                        lockStore, revisionDescriptorStore, revisionDescriptorsStore },
             new Parameters[] { nodeParas, contentParas, securityParas, lockParas, rdParas, rdsParas });
    }
    
    // TODO
    public XStoreAspects(XStoreAspects orig) {
        int i;
        
        aspects = orig.aspects;  // immutable - we can share them
        parameters = new Parameters[ASPECTS.length];
        for (i = 0; i < ASPECTS.length; i++) {
            parameters[i] = new Parameters(orig.parameters[i]);
        }
    }
    
    public void substitue(String store) {
        int i;
        
        for (i = 0; i < ASPECTS.length; i++) {
            parameters[i].substitute("${store}", store);
        }
    }
    
    public XStoreAspects(Object[] aspects, Parameters[] parameters) {
        int i;
        Object obj;
        
        if (aspects == null) {
            throw new XAssertionFailed();
        }
        if (aspects.length != ASPECTS.length) {
            throw new XAssertionFailed(aspects.length + "!=" + ASPECTS.length);
        }
        if (aspects.length != parameters.length) {
            throw new XAssertionFailed(aspects.length + " != " + parameters.length);
        }
        this.aspects = aspects;
        this.parameters = parameters;
        for (i = 0; i < aspects.length; i++) {
            obj = aspects[i];
            if (obj instanceof String) {
                // ok
            } else if (obj instanceof Integer) {
                // ok
            } else {
                throw new XAssertionFailed("invalid aspect " + ASPECTS[i] + ": " + obj);
            }
        }
    }
    
    public boolean equals(Object obj) {
        int i;
        XStoreAspects a;
        
        if (obj instanceof XStoreAspects) {
            a = (XStoreAspects) obj;
            if (!equalsRaw(a)) {
                return false;
            }
            for (i = 0; i < aspects.length; i++) {
                if (!parameters[i].equals(a.parameters[i])) {
                    return false;
                }
            }
            return true;
        } else {
            return false;
        }
    }
    
    public boolean equalsRaw(XStoreAspects a) {
        int i;
        
        for (i = 0; i < aspects.length; i++) {
            if (!aspects[i].equals(a.aspects[i])) {
                return false;
            }
        }
        return true;
    }

    //-- xml
    
    public void addXml(Element store) {
        int i;
        Element ele;
        Element ref;
        Object obj;
        
        for (i = 0; i < aspects.length; i++) {
            ele = new Element(ASPECTS[i]);
            obj = aspects[i];
            if (obj instanceof String) {
                ele.setAttribute(XDomainConstants.CLAZZNAME, (String) obj);
            } else if (obj instanceof Integer) {
                ref = new Element(XDomainConstants.REFERENCE);
                ref.setAttribute(XDomainConstants.STORE, ASPECTS[((Integer) obj).intValue()]);
                ele.addContent(ref);
            } else {
                throw new XAssertionFailed("" + obj);
            }
            parameters[i].addXml(ele);
            store.addContent(ele);
        }
    }
    
    public static XStoreAspects extractFromXml(Element store) throws XException {
        List lst;
        int i;
        Element e;
        int idx;
        Object[] aspects;
        Parameters[] paras;
        
        aspects = new Object[ASPECTS.length];
        lst = store.getChildren();
        paras = new Parameters[ASPECTS.length];
        for (i = 0; i < lst.size(); i++) {
            e = (Element) lst.get(i);
            idx = lookup(e.getName());
            if (idx != -1) {
                if (aspects[idx] != null) {
                    throw new XException("duplicate aspect: " + ASPECTS[i]);
                }
                aspects[idx] = getOneFromXml(e);
                paras[idx] = Parameters.fromXml(e);
                lst.remove(i);
                i--;
            }
        }
        for (i = 0; i < aspects.length; i++) {
            if (aspects[i] == null) {
                throw new XException("missing aspect: " + ASPECTS[i]);
            }
        }
        return new XStoreAspects(aspects, paras);
    }
    
    private static Object getOneFromXml(Element e) throws XException {
        String name;
        Element reference;
        
        name = e.getAttributeValue(XDomainConstants.CLAZZNAME);
        if (name != null) {
            return name;
        }
        reference = e.getChild(XDomainConstants.REFERENCE);
        if (reference == null) {
            throw new XAssertionFailed("invalid aspect");
        }
        name = JDom.getAttribute(reference, XDomainConstants.STORE);
        return new Integer(get(name));
    }
    
    public static int get(String str) throws XException {
        int idx;
        
        idx = lookup(str);
        if (idx == -1) {
            throw new XAssertionFailed("no such aspect: " + str);
        } else {
            return idx;
        }
    }
    
    public static int lookup(String str) {
        int i;
        
        for (i = 0; i < ASPECTS.length; i++) {
            if (str.equals(ASPECTS[i])) {
                return i;
            }
        }
        return -1;
    }
}


