/*
 * Copyright 2012 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package kr.gmtc.tss.netty;

import java.nio.charset.Charset;
import java.util.Queue;

import javax.net.ssl.SSLException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.handler.timeout.IdleStateHandler;
import kr.gmtc.tss.status.ContextDestroyStatus;
//import kr.gmt.routing.dds.support.ContextDestroyStatus;
//import kr.gmt.routing.netty.server.ObjectEchoServerHandler;

/**
 * Modification of {@link EchoClient} which utilizes Java object serialization.
 */
@Sharable
public class StringClient extends Thread {
	private static Logger logger = LoggerFactory.getLogger(StringClient.class);

	static boolean SSL = System.getProperty("ssl") != null;
	static String HOST = System.getProperty("tcp.server.ip", "127.0.0.1");
	static int PORT = Integer.parseInt(System.getProperty("tcp.server.port", "8030"));
	static int SIZE = Integer.parseInt(System.getProperty("size", "256"));

	private EventLoopGroup eventLoop;
	

	long reconnTime=3000;
	String threadName="";
	
//	Queue<byte[]> dataQueue;

	ChannelFuture channelFuture;
	StringClient client;
	StringClientHandler clientHandler;
//	ContextDestroyStatus contextDestroyStatus;
	
	private boolean isServerStarted=false;
	
	private Bootstrap b;

	public void setServerStarted(boolean isServerStarted) {
		this.isServerStarted = isServerStarted;
	}


	public StringClient(String ip, int port, Queue<String> dataQueue, long reconnTime
//			, 
//			ChannelFuture channelFuture,
//			ContextDestroyStatus contextDestroyStatus
			) {
		this.HOST = ip;
		this.PORT = port;
//		this.dataQueue = dataQueue;
		this.client=this;
		this.reconnTime=reconnTime;
		this.channelFuture=client.channelFuture;
//		this.channelFuture=channelFuture;
//		this.contextDestroyStatus= contextDestroyStatus;
		clientHandler=new StringClientHandler(client,threadName, dataQueue,reconnTime);
	}

	public EventLoopGroup getEventLoop() {
		return eventLoop;
	}
	
	@Override
	public void interrupt() {
		// TODO Auto-generated method stub
		super.interrupt();
		eventLoop.shutdownGracefully();
		
	}
	
	
	@Override
	public void run() {
		this.threadName = Thread.currentThread().getName();
//		startClient(new Bootstrap(),eventLoop,threadName);
//		boolean startStat=true;
//		eventLoop=new NioEventLoopGroup();
		startClient( );
		
	/*	while(!contextDestroyStatus.getShutdownStat()) {
			if(eventLoop!=null)
				eventLoop.shutdownGracefully();
			if (channelFuture==null||!channelFuture.isSuccess()||(!isServerStarted&&eventLoop.isShutdown())) {
				logger.info("서버 연결 시도 - /"+HOST+":"+PORT);
				eventLoop=new NioEventLoopGroup();
//				if(startClient( eventLoop,threadName)) {
				
				if(startClient( )) {} 
//				{
					
//					break;
//				}
				isServerStarted=false;
			}
			
			threadSleep(reconnTime);

			if(contextDestroyStatus.getShutdownStat()) {
				logger.info("ObjectEchoClient Shutdown called");
				break;
			}
		}*/
	}

	private void threadSleep(long mills) {
		try {
			Thread.sleep(mills);
		} catch (InterruptedException e) {
			logger.debug("Sleep Interrupted - "+e.getLocalizedMessage());
		}
	}
	
//	public ChannelFuture getChannelFuture() {
//		return channelFuture;
//	}

	public boolean startClient() {
		return startClient( this.threadName);
	}
	
	public boolean startClient(String threadName) {
		isServerStarted=true;
		boolean rtnVal=false;
//		try {
			eventLoop=new NioEventLoopGroup();
			EventLoopGroup group =eventLoop;
			
//			final SslContext sslCtx;
//			if (SSL) {
//
//				sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
//
//			} else {
//				sslCtx = null;
//			}
//			
//			EventLoopGroup group = new NioEventLoopGroup();
			try {
				b = new Bootstrap();
				
				b.group(group)
				.channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
				.option(ChannelOption.SO_KEEPALIVE, true)
//				.option(ChannelOption.SO_REUSEADDR, true)
				.handler(new ChannelInitializer<SocketChannel>() {
					@Override
					public void initChannel(SocketChannel ch) throws Exception {
						try {
							
						
						ChannelPipeline p = ch.pipeline();
//						if (sslCtx != null) {
//							p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
//						}
//						p.addLast(new ObjectEncoder(), 
//								new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
//								clientHandler);
						p.addLast(
//								new IdleStateHandler(3, 0	, 0),
								new StringEncoder(),
								new StringDecoder(Charset.forName("MS949")),
								clientHandler);
						} catch (Exception e) {
							// TODO: handle exception
							logger.error("init error ",e);
						}
					}
				});
				
				rtnVal=connecServer();
			
			}catch(Exception e) {
				logger.error("서버 연결 실패  - "+e.getLocalizedMessage());
				logger.debug("call stack : ",e);
			} finally {
//				group.shutdownGracefully();
			}
//		} catch (SSLException e) {
//			logger.error("SSLException - ", e);
//		} 
//		finally {
//			logger.info("Client cycle over!");
//		}
		return rtnVal;
	}


	public boolean connecServer() {
		boolean rtnVal=false;
//		group.
		try {
			channelFuture = b.connect(HOST, PORT);
					channelFuture.sync();
					channelFuture.channel().closeFuture().sync();
					rtnVal=true;
//		} catch (InterruptedException e) {	
//			logger.error("서버 연결 실패  - "+e.getLocalizedMessage());
		} catch (Exception e) {
			logger.error("서버 연결 실패  - "+e.getLocalizedMessage());
		}
		return rtnVal;
	}

}
