/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/tools/stores/StoreCommands.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.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import org.apache.slide.store.tamino.tools.Command;
import org.apache.slide.store.tamino.tools.Output;
import org.apache.slide.store.tamino.tools.stores.XDomainFileHandler;
import org.apache.slide.util.XException;
import org.apache.slide.util.XUri;
import org.apache.slide.util.cli.Abort;
import org.jdom.DocType;
import org.jdom.Document;
import org.xml.sax.InputSource;

public class StoreCommands {
    public static abstract class ModifyCommand extends Command {
        private final XDomainFileHandler dfh;
        
        public ModifyCommand(String name, Output out, XDomainFileHandler dfh) {
            super(name, out);
            this.dfh = dfh;
        }
        
        public void run() throws IOException, XException, Abort {
            modify(dfh);
            dfh.save();
        }
        public abstract void modify(XDomainFileHandler dfh) throws XException, Abort;
    }
    
    public static ModifyCommand removeGlobal(Output out, XDomainFileHandler dfh) {
        return new ModifyCommand("remove global parameters", out, dfh) {
            public void modify(XDomainFileHandler dfh) throws XException {
                dfh.clearGlobalConfig();
            }
        };
    }
    public static ModifyCommand removeStore(Output out, XDomainFileHandler dfh, final String namespace, final String store) {
        return new ModifyCommand("remove store '" + store + "' from namespace '" + namespace + "'", out, dfh) {
            public void modify(XDomainFileHandler dfh) throws XException {
                dfh.getDomain().getNamespace(namespace).removeStoreGroup(store);
            }
        };
    }
    
    public static Command setGlobal(Output out, XDomainFileHandler dfh, final String configXml)
        throws Abort
    {
        if (configXml == null) {
            throw new Abort("missing configFile option");
        }
        return new ModifyCommand("set global config", out, dfh) {
            public void modify(XDomainFileHandler dfh) throws XException {
                dfh.setGlobalConfig( new InputSource(configXml) );
            }
        };
    }
    
    public static Command setStore(Output out, final XDomainFileHandler dfh, final String namespace,
                                   final String url, final String configXml) throws Abort {
        if (configXml != null && url != null) {
            throw new Abort("-configFile and -url cannot be used together");
        }
        if (configXml == null && url == null) {
            throw new Abort("-configFile or -url option required");
        }
        if (configXml != null) {
            final String preStore;
            final String store;
            final InputSource src;
            
            src = new InputSource(configXml);
            preStore = new File(configXml).getName();
            if (preStore.endsWith(XUri.XML_SUFF)) {
                store = preStore.substring(0, preStore.length() - XUri.XML_SUFF.length());
            } else {
                store = preStore;
            }
            if( store == null || store.length() == 0 ) {
                throw new Abort("Missing store name");
            }
            return new ModifyCommand("set store '" + store + "' in namespace '" + namespace + "'", out, dfh) {
                public void modify(XDomainFileHandler dfh) throws XException {
                    dfh.setStoreConfig(namespace, store, src);
                }
            };
        } else {
            return new ModifyCommand("set store config for url " + url, out, dfh) {
                public void modify(XDomainFileHandler dfh) throws XException, Abort {
                    Object[] tmp;
                    tmp = createStoreConfig(namespace, XDomain.create().getConfig().createTypes(), url);
                    dfh.setStoreConfig(namespace, (String) tmp[0], ((Document) tmp[1]).getRootElement());
                }
            };
        }
    }
    
    public static Command listStores(Output out, final XDomainFileHandler dfh, final String namespace)
        throws XException
    {
        final XNamespace ns = dfh.getDomain().getNamespace(namespace);
        return new Command("list stores in namespace " + namespace, out) {
            public void run() throws XException {
                Iterator iter;
                XStoreGroup group;
                
                iter = ns.getPublicStoreGroups().iterator();
                if (iter.hasNext()) {
                    do {
                        group = (XStoreGroup) iter.next();
                        out.quiet.println("  " + group.name);
                        group.forAll(new XStoreGroup.Visitor() {
                                    public void visit(XStoreType type, XStore store) {
                                        out.quiet.println("    " + store.getName());
                                    }
                                });
                    } while (iter.hasNext());
                } else {
                    out.normal.println( "  <no entries found>" );
                }
            }
        };
    }
    
    public static Object[] createStoreConfig(String namespace, XStoreGroupTypeList groupTypes, String uriStr)
        throws Abort {
        Parameters p;
        URL full;
        URL tamino;
        XUri uri;
        XStoreGroup store;
        Document doc;
        String name;
        
        try {
            full = new URL(uriStr);
            uri = new XUri(full.getPath());
            if (uri.size() != 3) {
                throw new Abort("invalid path in store uri: 3 segments expected: " + uri);
            }
            if (!"tamino".equals(uri.firstSegment())) {
                throw new Abort("invalid path in store uri: first segments has to be 'tamino': " + uri);
            }
            tamino = new URL(full, "/tamino");
        } catch (MalformedURLException e) {
            throw new Abort("invalid url: " + uriStr);
        }
        
        name = uri.segment(2);
        store = groupTypes.userTamino.create(name);
        p = new Parameters();
        p.set("taminoBase", tamino.toString());
        p.set("database", uri.segment(1));
        p.set("collection", name);
        p.set("allowNonXML", "true");
        p.set("autoCreateXmlSchema", "true");
        store.setParameter(p);
        doc = new Document(store.toConfigXml(namespace));
        doc.setDocType(new DocType(XDomainConstants.CONFIGURATION, XDomainConstants.CONFIG_DTD));
        return new Object[] { name, doc };
    }
}

