/*
 * @(#)WebFile.java
 * Copyright 2001 Nomura Research Institute, LTD. All rights reserved.
 * RIDUAL : Web File
 * @author  Intelligent Technology Inc.
 * @version 1.00 2002/08/26
 */
package jp.co.nri.rid.web;

import	java.net.*;
import	java.io.*;
import	java.util.*;


/**
 * Web上のファイルをローカルにダウンロードしたり直接ストリームをオープンできる。
 */
public class WebFile{
//	private	String	myProxyHost	= null;
//	private	int		myProxyPort	= 8080;
	private	File	mySaveDir	= null;
	private	String	myRootPath	= null;
	private	URL		myURL		= null;
	private	File	myFile		= null;
	private	String	myHost		= null;
//	public	String[] DefaultNames = { "index.html" ,"index.htm" ,"index.cgi" ,"index.php" ,"index.jsp" ,"index.asp" };
	public	String[] DefaultNames = { "index.html" ,"index.htm" };
	
	/**
	 * コンストラクタ
	 * @since	1.00
	 */
	public WebFile(String host){ myHost = host; }
	
	public void setSaveDir(File dir){ mySaveDir = dir; }
	public void setRootPath(String path){ myRootPath = path; }
/*
	public void setProxy(String host ,int port){
		myProxyHost = host;
		myProxyPort = port;
	}
*/
	
	
	public	URL	getURL(){ return myURL; }
/*
	private URL	getProxyURL(URL url) throws MalformedURLException {
		return (null==myProxyHost) ? url : new URL(url.getProtocol() ,myProxyHost ,myProxyPort ,url.toExternalForm());
	}
	private URL	getProxyURL() throws MalformedURLException { return getProxyURL(myURL); }
*/	
	public boolean setURL(String str) throws MalformedURLException {
		return setURL(new URL(str));
	}
	
	public boolean setURL(URL from ,String to) throws MalformedURLException {
		return setURL(new URL(from ,to));
	}
	
	private static final char[]	SKIPCHARS = { ':' ,';' ,'*' ,'\"' ,'<' ,'>' ,'|' ,'#' };
	private boolean setURL(URL url) throws MalformedURLException {
		String path		= url.getPath();
		String protocol	= url.getProtocol();
		String host		= url.getHost();
		int port		= url.getPort();

		/* t3-nishimura added start */
		try { path = new URI(path).normalize().toString(); }
		catch (URISyntaxException use) { return false; }
		if (path.startsWith("/../")) {
			/* トップゾーンよりもさらに上を指している場合 */
			return false;
		}
		/* t3-nishimura added end */
		
		// ダウンロードしないホスト/パス?
		if(!host.toLowerCase().equals(myHost))	return false;
		if(null != myRootPath){
			if(!path.startsWith(myRootPath))	return false;
		}
		
		for(int i = SKIPCHARS.length - 1; 0 <= i; i--){
			if(0 <= path.indexOf(SKIPCHARS[i]))	return false;
		}
		
		StringTokenizer tokenizer = new StringTokenizer(path ,"/");
		for(int i = tokenizer.countTokens() - 1; 0 <= i; i--){
			String str = tokenizer.nextToken();
			if(str.startsWith(" "))	return false;
			if(str.startsWith(".")){
				if(str.equals(".."))	continue;
				if(str.equals("."))		continue;
				return false;
			}
		}
		
		if(path.endsWith("/")){
			int mx = DefaultNames.length;
			for(int i=0;i<mx;i++){
				url = new URL(protocol ,host ,port ,path+DefaultNames[i]);
				try{
					URLConnection connection = url.openConnection();
					if(!(connection instanceof HttpURLConnection))	continue;
					if(HttpURLConnection.HTTP_OK != ((HttpURLConnection)connection).getResponseCode())	continue;
				}
				catch(IOException e){ continue; }
				
				myURL = url;
				return true;
			}
			
			myURL = null;
		}else myURL = new URL(protocol ,host ,port ,path);
		
		return true;
	}
	
	/**
	 * セーブする。
	 * @since	1.00
	 */
	public int save() throws IOException{
		File	dir	= myFile.getParentFile();
		if(!dir.exists())	dir.mkdirs();
		return save(myFile);
/*
		OutputStream stream = new FileOutputStream(myFile);
		try{ return save(stream); }finally{ stream.close(); }
*/
	}
	
	public File fusionPath(){
		String path = myURL.getPath();
		
		if(null != myRootPath){
//			if(!path.startsWith(myRootPath))	return null;
			path = path.substring(myRootPath.length());
		}
		
		myFile = new File(mySaveDir ,path);
		return myFile;
	}
	
	/**
	 * セーブする。
	 * @since	1.00
	 */
//	private int save(OutputStream stream) throws IOException{
	private int save(File outFile) throws IOException{
		int		len	= 4096;
		byte[]	buf	= new byte[len];
		
		URLConnection connection = myURL.openConnection();
		if(!(connection instanceof HttpURLConnection))	throw new IOException("HTTP以外の接続");
		int code = ((HttpURLConnection)connection).getResponseCode();
		if(HttpURLConnection.HTTP_OK != code)	return code;
		BufferedInputStream		in	= new BufferedInputStream(connection.getInputStream());

//		BufferedOutputStream	out	= new BufferedOutputStream(stream);
		BufferedOutputStream	out	= new BufferedOutputStream(new FileOutputStream(outFile));
//		BufferedInputStream		in	= new BufferedInputStream(myURL.openStream());
		try{
			int sz;
			while(true){
				sz = in.read(buf ,0 ,len);
				if(0 > sz)	break;
				
				out.write(buf ,0 ,sz);
			}
		}finally{
			out.close();
			in.close();
		}
		
		return code;
	}
}
