/*
 * $Revision: 220 $ $Date: 2007-07-16 19:32:15 +0900 $
 * Copyright (C) 2004-2005 SUGIMOTO Ken-ichi
 * 作成日： 2004/05/18
 */

package feat2.config;

import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletContext;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;

/**
 * Servlet環境でファイル位置を表現するためのクラス。
 * パスはwebアプリケーションのルートからの相対位置。
 */
public class ServletFileLocator implements FileLocator {

    private ServletFileLocator root;
    private ServletContext ctx;
    private URI path;

    /**
     *
     * @param path
     * @param ctx
     * @throws URISyntaxException パスの形式に間違いがある
     * @throws IllegalArgumentException 引数がnull
     */
    public ServletFileLocator(String path, ServletContext ctx) throws URISyntaxException, IllegalArgumentException {
        if ( path == null )
            throw new IllegalArgumentException("path:null");
        if ( ctx == null )
            throw new IllegalArgumentException("ctx:null");

        this.ctx = ctx;
        this.path = new URI(path);
        this.root = this;
    }

    private ServletFileLocator(URI path, ServletContext ctx, ServletFileLocator root) {
        this.ctx = ctx;
        this.path = path;
        this.root = root;
    }

    /* (非 Javadoc)
     * @see feat2.config.FileLocator#openInputStream()
     */
    public InputStream openInputStream() throws IOException {
        return ctx.getResourceAsStream(path.getPath());
    }

    /* (非 Javadoc)
     * @see feat2.config.FileLocator#getURL()
     */
    public String getURL() throws MalformedURLException {
        URL url = getURL_();
        if ( url == null )
            return null;
        else
            return url.toExternalForm();
    }

    private URL getURL_() throws MalformedURLException {
        return ctx.getResource(path.getPath());
    }

    /* (非 Javadoc)
     * @see feat2.config.FileLocator#getURIString()
     */
    public String getURIString() {
        try {
            return getURL();
        }
        catch (MalformedURLException ex) {
            ex.printStackTrace();
            return null;
        }
    }

    /* (非 Javadoc)
     * @see feat2.config.FileLocator#exists()
     */
    public boolean exists() {
        try {
            return getURL_() != null;
        }
        catch (MalformedURLException ex) {
            ex.printStackTrace();
            return false;
        }
    }

    /* (非 Javadoc)
     * @see feat2.config.FileLocator#getFilename()
     */
    public String getFilename() {
        String pathstr = path.getPath();

        // 最後が'/'だったらディレクトリ
        if ( pathstr.endsWith("/") ) {
            return null;
        }

        // 最後の'/'以降の名前がファイル名
        int slashIndex = pathstr.lastIndexOf('/');
        if ( slashIndex == -1 )
            return pathstr;
        else
            return pathstr.substring(slashIndex+1);
    }

    /* (非 Javadoc)
     * @see feat2.config.FileLocator#getLastModified()
     */
    public long getLastModified() throws IOException {
        URL url = getURL_();
        if ( url == null ) {
            return 0L;
        }
        else {
            URLConnection con = url.openConnection();
            con.connect();
            return con.getLastModified();
        }
    }

    /* (非 Javadoc)
     * @see feat2.config.FileLocator#newLocation(java.lang.String)
     */
    public FileLocator newLocation(String relativePath) throws IllegalArgumentException {
        if ( relativePath != null ) {
            if ( relativePath.startsWith("/") )
                throw new IllegalArgumentException("\""+relativePath+"\" '/'で始まるパスは指定できない");
            if ( relativePath.startsWith(".") )
                throw new IllegalArgumentException("\""+relativePath+"\" ディレクトリ名の先頭に'.'は使用できない");
            if ( relativePath.indexOf("..") > -1 )
                throw new IllegalArgumentException("\""+relativePath+"\" 上位のディレクトリは指定できない");

            //URI current = new URI(path.toExternalForm());
            URI newUri = path.resolve(relativePath);
            return new ServletFileLocator(newUri, ctx, root);
        }
        else
            return this;
    }

    /* (非 Javadoc)
     * @see feat2.config.FileLocator#rootLocation()
     */
    public FileLocator rootLocation() {
        return root;
    }

    public String toString() {
        return path.getPath();
    }

    public boolean equals(Object o) {
        ServletFileLocator loc = (ServletFileLocator)o;
        boolean ret = path.getPath().equals(loc.path.getPath());
        if ( root != this )
            ret = ret && root.equals(loc.root);
        return ret;
    }
}
