/*
 * Galatea Dialog Manager:
 * (c)2004 Takuya NISHIMOTO (nishi@hil.t.u-tokyo.ac.jp)
 * Based on Phoenix By Takuya NISHIMOTO and Mitsuhiro KIZU
 *
 * $Id: NetUtil.java,v 1.2 2008/02/14 02:00:07 nishi Exp $
 */
package galatea.httpclient;

import galatea.document.DocError;
import galatea.util.Util;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

public class NetUtil 
{
	private NetUtil() {
	}

    private static CookieManager cookieManager;
    
    public static void createCookieManager() {
    	//System.out.println("NetUtil:createCookieManager");
    	for (INetUtilListener l : listeners) {
    		l.addNetUtilEvent("createCookieManager");
    	}
        cookieManager = new CookieManager();
        cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
        CookieHandler.setDefault(cookieManager);
	}
	
	private static ArrayList<INetUtilListener> 
		listeners = new ArrayList<INetUtilListener>();
	
	public static void addListener(INetUtilListener ls) {
		listeners.add(ls);
	}
	
	public static String getTopName(Element elem) {
		String topName;
		if (elem.getNodeType() == Node.ELEMENT_NODE) {
			topName = elem.getNodeName();
		} else {
			topName = "";
		}
		return topName;
	}
	
	/**
	// http の場合はまずファイル全体をバイナリ列として取得する
	// バイト列をスキャンして ?> が出現するまでをディレクティブと見なし、
	// encoding を取得する。デフォルトは UTF-8 とする。
	// 以降の文字列は encoding に基づいて解釈し、
	// 内部的には UTF-8 に変換して DOM Parser に解釈させる
	*/
	public static Element loadXMLFile(
			String filename, boolean isPost, String postdata) 
		throws Exception
	{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document root;
		if (filename.startsWith("http:")) {
			URL url = new URL(filename);
			HttpURLConnection uc;
			uc = (HttpURLConnection)url.openConnection();

			if (isPost && postdata != null) {
				uc.setDoOutput(true);
				DataOutputStream outStream = new DataOutputStream(uc.getOutputStream());
				byte [] bytBuff = postdata.getBytes();
				outStream.write(bytBuff, 0, bytBuff.length);
				uc.connect();
			} else {
				uc.setRequestMethod("GET");
			}
			InputStream is = uc.getInputStream();
			ByteArrayOutputStream os = new ByteArrayOutputStream();
			final int SIZE = 8196;
			byte[] buf = new byte[SIZE];
			while (true) {
				int n = is.read(buf,0,SIZE);
				if (n == -1) break;
				os.write(buf,0,n);
			}
			byte[] bytes = os.toByteArray();
			os.close();
			is.close();
			uc.disconnect();

		    // Cookie の表示
	        CookieStore store = cookieManager.getCookieStore();
	        List<HttpCookie> cookies = store.getCookies();
            //System.out.println("Cookies:");
	        for (int i = 0; i < cookies.size(); i++) {
	            HttpCookie cookie = cookies.get(i);
	            //System.out.println("Cookie[" + i + "]: " + cookie);
		        //System.out.flush();
	        	for (INetUtilListener l : listeners) {
	        		l.addNetUtilEvent("Cookie[" + i + "]: " + cookie);
	        	}
	        }
	        
			String encoding = "UTF-8"; // default
			int pos = 0;
			for (int i=0; i < bytes.length; i++) {
				if (bytes[i] == '>' && i > 0 && bytes[i-1] == '?') {
					String line = new String(bytes,0,i+1);
					if (line.startsWith("<?xml ")) {
						String s = line.replaceAll("\"", "'");
						// encoding='xxx'
						String e = Util.getFirstGroup(".*encoding[\\s]*=[\\s]*'([^']+)'.*", s);
						if (e != null) {
							encoding = e;
						}
					}
					pos = i+1;
					break;
				}
			}
			int len = bytes.length - pos;
			String content = new String(bytes, pos, len, encoding);
			InputStream is2 = new ByteArrayInputStream(content.getBytes("UTF-8"));
			root = builder.parse(is2);
        	for (INetUtilListener l : listeners) {
        		l.addNetUtilEvent("fetched and parsed " + filename 
        				+ (isPost ? " [POST]" : " [GET]") );
        	}
		} else {
			root = builder.parse(filename);
        	for (INetUtilListener l : listeners) {
        		l.addNetUtilEvent("parsed " + filename);
        	}
		}
		Element elem = root.getDocumentElement();
		return elem;
	}
	
	public static Element loadXMLFile(String filename) throws Exception
	{
		return loadXMLFile(filename, false, null);
	}
	
	
	public static String loadTextFile(String filename) throws Exception
	{
		String doc = Util.readURL(filename);
		if (Util.getError().equals("")) {
			return doc;
		}
		throw new DocError(Util.getError());
	}
	
	public static String makeString(Element element) {
		TransformerFactory factory = TransformerFactory.newInstance();
		Transformer transformer;
		try {
			transformer = factory.newTransformer();
		} catch (TransformerConfigurationException e) {
			return e.toString(); // e.printStackTrace();
		}
		DOMSource src = new DOMSource(element);
		StringWriter writer = new StringWriter();
		StreamResult target = new StreamResult(writer);
		try {
			transformer.transform(src, target);
		} catch (Exception e) {
			return e.toString(); // e.printStackTrace();
		}
		String ws = new String(writer.getBuffer());
		return ws;
	}
	
	public static void main(String args[]) throws Exception
	{
		String s;
		// s = loadXMLFile("/data/workspace/gdm/tests/vxml/form.vxml").toString();
		s = loadXMLFile("http://localhost/bento/vxml/vxml-begin.php").toString();
		System.err.println(s);
	}
	
}
