/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/tools/repairer/XHttpClient.java,v 1.4 2004/12/15 10:38:27 pnever Exp $
 * $Revision: 1.4 $
 * $Date: 2004/12/15 10:38:27 $
 *
 * ====================================================================
 *
 * 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.repairer;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringWriter;
import java.net.URL;
import java.util.Enumeration;
import java.util.Vector;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.slide.util.XException;
import org.apache.slide.util.XUri;
import org.apache.webdav.lib.BaseProperty;
import org.apache.webdav.lib.WebdavState;
import org.apache.webdav.lib.methods.MkcolMethod;
import org.apache.webdav.lib.methods.PropFindMethod;
import org.apache.webdav.lib.methods.VersionControlMethod;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

/**
 * Http Client.
 *
 * @author Juergen.Pill@softwareag.com
 *
 * @version $Revision: 1.4 $
 */
public class XHttpClient extends HttpClient {
    private final Class classForResources;
    
    private final String SEP = XUri.SEP;
    
    private final String pathPrefix;
    
    public XHttpClient(String host, int port, String user, String password)  {
        this(null, "", host, port, user, password);
    }
    
    public XHttpClient(Class classForResources, String pathPrefix, String host, int port, String user, String password)  {
        super();
        
        this.classForResources = classForResources;
        WebdavState state = new WebdavState();
        Credentials cred = new UsernamePasswordCredentials(user, password);
        state.setCredentials(null, host, cred);
        this.setState(state);
        this.getHostConfiguration().setHost(host, port);
        this.pathPrefix = pathPrefix;
    }
    
    public void versionControl(String path) throws IOException, XException {
        HttpMethod vc = new VersionControlMethod(pathPrefix+path);
        int sc = executeMethod(vc);
        if (sc != 200) {
            throw new XException("Version control for path="+path+" failed");
        }
    }
    
    /**
     * Create a new document via the HttpClient. Uses PUT and MKCOL methods.
     */
    public void create(String path) throws IOException {
        String fileName;
        int lastSlashIndex;
        int result;
        
        lastSlashIndex = path.lastIndexOf(SEP);
        fileName = path.substring(lastSlashIndex + 1);
        System.out.println("Create correct test data via HTTPClient: " + path);
        String ppp = "";
        HttpMethod method;
        
        //If starts with "/" then a structure to create otherwise PUT
        if ( path.startsWith(SEP ) ) {
            //MKCol first, create the correct data Structure.
            int start = 1;
            int end = 1;
            
            while (start >= 0) {
                start = path.indexOf(SEP,(start + 1));
                if (start > 0) {
                    ppp = path.substring(end,start);
                    method = createMkcolMethod(ppp);
                    result = executeMethod(method);
                    if (result / 100 != 2) {
                        if (result == 405) {
                            // TODO: server is not restarted after wipeDatabase
                            System.out.println("warning: mkcol " + method.getPath() + " exists");
                        } else {
                            throw new IOException("mkcol " + method.getPath() + " failed: " + result);
                        }
                    }
                }
            }
        }
        method = createPutMethod(ppp + SEP, fileName);
        result = executeMethod(method);
        if (result / 100 != 2) {
            throw new IOException("put " + method.getPath() + " failed: " + result);
        }
    }
    
    public String getResourceId(String uri) throws IOException {
        String path;
        PropFindMethod propfind;
        Vector props;
        Enumeration en;
        int result;
        BaseProperty property;
        
        if (uri.startsWith("/")) {
            uri = uri.substring(1);
        }
        path = pathPrefix + uri;
        props = new Vector();
        props.add("resource-id");
        propfind = new PropFindMethod(path);
        propfind.setPropertyNames(props.elements());
        propfind.setType(PropFindMethod.BY_NAME);
        result = executeMethod(propfind);
        if (result != 207) {
            throw new IOException("propfind " + path + " failed: " + result);
        }
        en = propfind.getResponseProperties(path);
        if (!en.hasMoreElements()) {
            throw new IOException("no result in propfind " + path);
        }
        property = (BaseProperty) en.nextElement();
        return getText(getChild(property.getElement(), "href"));
    }
    
    private static Element getChild(Element parent, String name) {
        NodeList lst;
        
        lst = parent.getElementsByTagNameNS(parent.getNamespaceURI(), name);
        if (lst.getLength() == 1) {
            return (Element) lst.item(0);
        } else {
            throw new IllegalStateException("" + lst.getLength());
        }
    }
    
    private static String getText(Element element) {
        StringBuffer buffer;
        Node current;
        
        buffer = new StringBuffer();
        for (current = element.getFirstChild(); current != null; current = current.getNextSibling()) {
            if (current instanceof Text) {
                buffer.append(((Text) current).getData());
            } else {
                throw new IllegalStateException("not a text: " + current.getClass());
            }
        }
        return buffer.toString();
    }
    
    private HttpMethod createMkcolMethod(String path) throws IOException {
        return new MkcolMethod (pathPrefix+path);
    }
    
    private HttpMethod createPutMethod(String path, String fileName) throws IOException {
        URL contentURL = classForResources.getResource(fileName);
        if (contentURL == null) {
            throw new IOException("resource not found: " + fileName);
        }
        String testDir = (new File (contentURL.getFile())).getParent();
        File file = new File ( testDir + File.separatorChar + fileName );
        FileReader reader = new FileReader( file );
        StringWriter writer = new StringWriter();
        int c;
        while ((c = reader.read()) != -1) {
            writer.write(c);
        }
        String content = writer.toString();
        PutMethod put = new PutMethod (pathPrefix + path + file.getName());
        put.setRequestBody( content );
        put.addRequestHeader( "Content-Type", "text/xml; charset=\"utf-8\"" );
        return put;
    }
}

