package com.zhsoft88.commons;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FilenameFilter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Arrays;

import org.apache.commons.lang.math.NumberUtils;

/**
 * seacat capture
 * @author zhsoft88
 * @since 2008-4-13
 * @update 2008-12-13
 */
public class Seacat {

	public static final int PORT = 5060;
	
	/**
	 * capture result
	 * @author zhsoft88
	 * @since 2008-4-13
	 */
	public static class SeacatResult {
		private int statusCode;
		private String statusText;
		private String scid;
		private String geometry;
		private long elaspedTime;
		private String prefix;
		private String pictureHome;
		private String[] suffixList;

		public SeacatResult() {
			// TODO Auto-generated constructor stub
		}

		public int getStatusCode() {
			return statusCode;
		}

		public String getStatusText() {
			return statusText;
		}

		public String getScid() {
			return scid;
		}

		public String getGeometry() {
			return geometry;
		}

		public long getElaspedTime() {
			return elaspedTime;
		}

		public String getPrefix() {
			return prefix;
		}

		public String getPictureHome() {
			return pictureHome;
		}

		public String[] getSuffixList() {
			return suffixList;
		}

		protected void setStatusCode(int statusCode) {
			this.statusCode = statusCode;
		}

		protected void setStatusText(String statusText) {
			this.statusText = statusText;
		}

		protected void setScid(String scid) {
			this.scid = scid;
		}

		protected void setGeometry(String geometry) {
			this.geometry = geometry;
		}

		protected void setElaspedTime(long elaspedTime) {
			this.elaspedTime = elaspedTime;
		}

		protected void setPrefix(String prefix) {
			this.prefix = prefix;
		}

		protected void setPictureHome(String pictureHome) {
			this.pictureHome = pictureHome;
		}

		protected void setSuffixList(String[] suffixList) {
			this.suffixList = suffixList;
		}

		public void dump() {
			System.out.println("SeacatResult:");
			System.out.println("statusCode="+statusCode);
			System.out.println("statusText="+statusText);
			System.out.println("scid="+scid);
			System.out.println("geometry="+geometry);
			System.out.println("prefix="+prefix);
			System.out.println("suffixList length="+suffixList.length);
			for (int i=0;i<suffixList.length;i++) {
				System.out.println("suffixList["+i+"]="+suffixList[i]);
			}
		}
	}
	
	/**
	 * capture configuration
	 * @author zhsoft88
	 * @since 2008-4-13
	 * @update 2008-12-13
	 */
	public static class SeacatConf {
		private String url;
		private String viewportId;
		private String viewportClass;
		private String viewportXpath;
		private String viewportRect;
		private String thumbSizes;
		private int waitTime;
		private boolean enableFull;
		private String pictureHome;
		private String prefix;
		private String suffix;
		private String postData;
		private boolean keepOrigin;

		public SeacatConf() {
			waitTime = -1;
			enableFull = false;
			keepOrigin = false;
			pictureHome = "/tmp";
		}
		public String getUrl() {
			return url;
		}
		public void setUrl(String url) {
			this.url = url;
		}
		public String getThumbSizes() {
			return thumbSizes;
		}
		public void setThumbSizes(String thumbSizes) {
			this.thumbSizes = thumbSizes;
		}
		public int getWaitTime() {
			return waitTime;
		}
		public void setWaitTime(int waitTime) {
			this.waitTime = waitTime;
		}
		public boolean isEnableFull() {
			return enableFull;
		}
		public void setEnableFull(boolean enableFull) {
			this.enableFull = enableFull;
		}
		public String getPictureHome() {
			return pictureHome;
		}
		public void setPictureHome(String pictureHome) {
			this.pictureHome = pictureHome;
		}
		public String getPrefix() {
			return prefix;
		}
		public void setPrefix(String prefix) {
			this.prefix = prefix;
		}
		public String getSuffix() {
			return suffix;
		}
		public void setSuffix(String suffix) {
			this.suffix = suffix;
		}
		public String getPostData() {
			return postData;
		}
		public void setPostData(String postData) {
			this.postData = postData;
		}
		public String getViewportId() {
			return viewportId;
		}
		public void setViewportId(String viewportId) {
			this.viewportId = viewportId;
		}
		public String getViewportClass() {
			return viewportClass;
		}
		public void setViewportClass(String viewportClass) {
			this.viewportClass = viewportClass;
		}
		public String getViewportXpath() {
			return viewportXpath;
		}
		public void setViewportXpath(String viewportXpath) {
			this.viewportXpath = viewportXpath;
		}
		public String getViewportRect() {
			return viewportRect;
		}
		public void setViewportRect(String viewportRect) {
			this.viewportRect = viewportRect;
		}
		public boolean isKeepOrigin() {
			return keepOrigin;
		}
		public void setKeepOrigin(boolean keepOrigin) {
			this.keepOrigin = keepOrigin;
		}
		
	}
	
	private String host;
	private int port;
	
	public Seacat() {
		this("localhost");
	}
	
	public Seacat(String host) {
		this(host,PORT);
	}
	
	public Seacat(String host,int port) {
		this.host = host;
		this.port = port;
	}
	
	/**
	 * capture web page
	 * @param conf
	 * @return
	 * @throws Exception
	 */
	public SeacatResult capture(SeacatConf conf) throws Exception {
		long t1 = System.currentTimeMillis();
		Socket socket = new Socket(host,port);
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
		if (conf.getUrl()!=null) {
			bw.write("get "+conf.getUrl()+"\r\n");
		}
		if (conf.getViewportId()!=null) {
			bw.write("viewport-id "+conf.getViewportId()+"\r\n");
		}
		if (conf.getViewportClass()!=null) {
			bw.write("viewport-class "+conf.getViewportClass()+"\r\n");
		}
		if (conf.getViewportXpath()!=null) {
			bw.write("viewport-xpath "+conf.getViewportXpath()+"\r\n");
		}
		if (conf.getViewportRect()!=null) {
			bw.write("viewport-rect "+conf.getViewportRect()+"\r\n");
		}
		if (conf.getThumbSizes()!=null) {
			bw.write("thumb-sizes "+conf.getThumbSizes()+"\r\n");
		}
		if (conf.isEnableFull()) {
			bw.write("enable-full\r\n");
		}
		if (conf.getWaitTime()!=-1) {
			bw.write("wait-time "+conf.getWaitTime()+"\r\n");
		}
		if (conf.getPictureHome()!=null) {
			bw.write("picture-home "+conf.getPictureHome()+"\r\n");
		}
		if (conf.getPrefix()!=null) {
			bw.write("prefix "+conf.getPrefix()+"\r\n");
		}
		if (conf.getSuffix()!=null) {
			bw.write("suffix "+conf.getSuffix()+"\r\n");
		}
		if (conf.getPostData()!=null&&conf.getPostData().length()>0) {
			bw.write("content-length "+conf.getPostData().length()+"\r\n");
		}
		if (conf.isKeepOrigin()) {
			bw.write("keep-origin\r\n");
		}
		bw.write("\r\n");
		if (conf.getPostData()!=null&&conf.getPostData().length()>0) {
			bw.write(conf.getPostData());
		}
		bw.flush();
		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"utf-8"));
		String line = br.readLine();
		char[] ca = line.toCharArray();
		int i = 0;
		while (i<ca.length&&ca[i]!=' ') i++;
		while (i<ca.length&&ca[i]==' ') i++;
		// get status code
		StringBuilder sb = new StringBuilder(4);
		while (i<ca.length&&ca[i]!=' ') {
			sb.append(ca[i]);
			i++;
		}
		int statusCode = NumberUtils.toInt(sb.toString());
		// get status text
		while (i<ca.length&&ca[i]==' ') i++;
		String statusText = line.substring(i);
		// get scid & geometry
		String scid = null;
		String geometry = null;
		while ((line=br.readLine())!=null) {
			if (line.length()==0) break;
			if (line.startsWith("SCID: ")) {
				scid = line.substring(6);
			} else if (line.startsWith("Geometry: ")) {
				geometry = line.substring(10);
			}
		}
		socket.close();
		//
		String pictureHome = null;
		String prefix = null;
		String[] suffixList = new String[0];
		if (scid!=null) {
			pictureHome = scid.substring(0,scid.lastIndexOf('/'));
			prefix = scid.substring(scid.lastIndexOf('/')+1);
			final String aPrefix = prefix;
			// get suffix list
			File[] list = new File(conf.getPictureHome()).listFiles(new FilenameFilter(){
				@Override
				public boolean accept(File dir, String name) {
					return name.startsWith(aPrefix);
				}
			});
			suffixList = new String[list.length];
			for (int k=0;k<list.length;k++) {
				suffixList[k] = list[k].getName().substring(prefix.length()+1);
			}
			Arrays.sort(suffixList);
		}
		long t2 = System.currentTimeMillis();
		SeacatResult result = new SeacatResult();
		result.setStatusCode(statusCode);
		result.setStatusText(statusText);
		result.setScid(scid);
		result.setElaspedTime(t2-t1);
		result.setGeometry(geometry);
		result.setPictureHome(pictureHome);
		result.setPrefix(prefix);
		result.setSuffixList(suffixList);
		return result;
	}
	
}
