package jp.cssj.cti.resolver;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * java.net.URLを利用してリソースを取得します。
 * 
 * @author <a href="mailto:miyabe at gnn.co.jp">MIYABE Tatsuhiko </a>
 * @version $Id: URISource.java,v 1.5 2005/09/06 23:27:49 harumanx Exp $
 */
public class URISource implements Source {
	private static final Logger LOGGER = Logger.getLogger(URISource.class
			.getName());

	private final String uri, encoding, referer;

	private String mimeType = null;

	private URLConnection conn = null;

	private InputStream in = null;

	public URISource(String uri, String mimeType, String encoding,
			String referer) {
		this.uri = SourceUtils.normalize(uri);
		this.mimeType = mimeType;
		this.encoding = encoding;
		this.referer = referer;
	}

	public URISource(String uri, String mimeType) {
		this(uri, mimeType, null);
	}

	public URISource(String uri, String mimeType, String encoding) {
		this(uri, mimeType, encoding, null);
	}

	public URISource(String uri) {
		this(uri, null);
	}

	public String getURI() {
		return this.uri.toString();
	}

	public String getMimeType() {
		if (this.mimeType == null) {
			if (this.isFile()) {
				String filename = this.getFile().getName();
				int dot = filename.indexOf('.');
				if (dot != -1) {
					String suffix = filename.substring(dot, filename.length());
					if (suffix.equalsIgnoreCase(".html")
							|| suffix.equalsIgnoreCase(".htm")) {
						this.mimeType = "text/html";
					} else if (suffix.equalsIgnoreCase(".xml")
							|| suffix.equalsIgnoreCase(".xhtml")
							|| suffix.equalsIgnoreCase(".xht")) {
						this.mimeType = "text/xml";
					}
					if (this.mimeType != null) {
						return this.mimeType;
					}
				}
			}
			try {
				if (this.conn == null) {
					this.connect();
				}
				return this.mimeType = this.conn.getContentType();
			} catch (IOException e) {
				this.conn = null;
			}
		}
		return this.mimeType;
	}

	public String getEncoding() {
		return this.encoding;
	}

	public boolean isCharacterStream() {
		return this.encoding != null;
	}

	public synchronized InputStream getInputStream() throws IOException {
		if (this.in != null) {
			throw new IllegalStateException("既にアクセスしています");
		}
		if (this.isFile()) {
			return this.in = new FileInputStream(this.getFile());
		}
		if (this.conn == null) {
			this.connect();
		}
		return this.in = this.conn.getInputStream();
	}

	public Reader getReader() throws IOException {
		if (!this.isCharacterStream()) {
			throw new UnsupportedOperationException();
		}
		return new InputStreamReader(this.getInputStream(), this.encoding);
	}

	public synchronized void close() {
		if (this.in != null) {
			try {
				this.in.close();
			} catch (Exception e) {
				LOGGER.log(Level.FINE, "リソースへの接続を中断した際に例外が発生しました", e);
			}
		}
	}

	private void connect() throws IOException {
		this.conn = new URL(this.uri).openConnection();
		// fileプロトコルではリファラを送信しない
		if (this.referer != null && !this.referer.startsWith("file:")) {
			this.conn.setRequestProperty("Referer", this.referer);
		}
	}

	public boolean isFile() {
		try {
			return "file".equals(new URI(this.uri).getScheme());
		} catch (URISyntaxException e) {
			return false;
		}
	}

	public File getFile() {
		try {
			URI uri = new URI(this.uri);
			String path = uri.getPath();
			if (path == null) {
				path = uri.getSchemeSpecificPart();
			}
			return new File(path);
		} catch (URISyntaxException e) {
			throw new RuntimeException(e);
		}
	}
}