package com.lenzhao.framework.protocol;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;

import com.lenzhao.framework.exception.RpcException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *封装请求和响应的桥梁
 */
public class InvokeFuture {
	
	private static final Logger logger = LoggerFactory.getLogger(InvokeFuture.class);
	
	private Channel channel;
	private RpcRequest request;
	private RpcResponse response;
	
	private static Map<String, InvokeFuture> invokeMap = new ConcurrentHashMap<String, InvokeFuture>();
	
	private CountDownLatch cdl = new CountDownLatch(1);
	
	/**
	 * 发送请求
	 */
	public void send() {
		ChannelFuture writeFuture = channel.write(request);
		//阻塞等待,若超时则返回已完成和失败
		boolean ret = writeFuture.awaitUninterruptibly(1000, TimeUnit.MILLISECONDS);
		if (ret && writeFuture.isSuccess()) {
			return;
		} else if(writeFuture.getCause() != null) {
			invokeMap.remove(request.getRequestID());
			throw new RpcException(writeFuture.getCause());
		} else {
			invokeMap.remove(request.getRequestID());
			throw new RpcException("sendRequest error");
		}
	}
	
	public RpcResponse get(long awaitTime) {
		boolean isOverTime = false;
		try {
			isOverTime = cdl.await(awaitTime, TimeUnit.MILLISECONDS);
		} catch (InterruptedException e) {
			invokeMap.remove(request.getRequestID());
			throw new RpcException("InterruptedException", e);
		}
		if(isOverTime) {
			invokeMap.remove(request.getRequestID());
			return response;
		} else {
			invokeMap.remove(request.getRequestID());
			throw new RpcException("sendRequest overtime");
		}
	}
	
	public boolean isDone() {
		return cdl.getCount() == 0;
	}
	
	public void doReceive(RpcResponse response) {
		this.response = response;
		cdl.countDown();
	}
	
	public static void receive(Channel channel, RpcResponse response) {
		InvokeFuture future = invokeMap.remove(response.getRequestID());
		if(null != future) {
			future.doReceive(response);
		} else {
			throw new RpcException("TimeOut");
		}
	}
	
	public InvokeFuture(Channel channel, RpcRequest request) {
		this.channel = channel;
		this.request = request;
		invokeMap.put(request.getRequestID(), this);
	}
	
	public Channel getChannel() {
		return channel;
	}
	public void setChannel(Channel channel) {
		this.channel = channel;
	}
	public RpcRequest getRequest() {
		return request;
	}
	public void setRequest(RpcRequest request) {
		this.request = request;
	}
	public RpcResponse getResponse() {
		return response;
	}
	public void setResponse(RpcResponse response) {
		this.response = response;
	}
	
}