package com.backfire.socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;

import com.backfire.utils.Log;

public class SocketConnectBase {
	private volatile Socket mSocket;
	private volatile OutputStream mOutStream;
	private volatile InputStream mInStream;
	
	private int lengthRead;
	private int lengthSum;
	
	public static final int FLAG_NEED_CONNECT 	= 0x01;
	public static final int FLAG_SET_TIMEOUT	= 0x02;
	public static final int FLAG_OPEN			= 0x04;
	
	private byte[] syncLock = new byte[0];
	private int flag;
	
	protected void addFlag(int add) {
		synchronized(syncLock) {
			flag |= add;
		}
	}
	
	protected void removeFlag(int remove) {
		synchronized (syncLock) {
			flag &= ~remove;
		}
	}

	protected boolean testFlag(int test) {
		synchronized (syncLock) {
			return (flag & test) > 0;
		}
	}
	
	protected void clearFlag() {
		synchronized (syncLock) {
			flag = 0;
		}
	}
	
	public SocketConnectBase() {
		mSocket = null;
		mInStream = null;
		mOutStream = null;
	}
	
	protected boolean canUse() {
		if (mSocket == null)
			return false;
		if (!mSocket.isClosed() && mSocket.isConnected())
			return true;
		
		return false;
	}
	
	protected void canUseRemote() throws IOException {
		
	}
	
	protected void write(byte[] buffer, int length) throws IOException {
		mOutStream.write(buffer, 0, length);
		mOutStream.flush();
	}
	
	protected boolean openSocket(String ip, int port, int timeout) {
		try {
			SocketAddress addr = new InetSocketAddress(ip, port);
			mSocket = new Socket();
			mSocket.connect(addr, timeout);
			
			mSocket.setTcpNoDelay(true);
			mSocket.setOOBInline(true);
			mSocket.setSoLinger(false, 0);
			
			mInStream = mSocket.getInputStream();
			mOutStream = mSocket.getOutputStream();
		} catch (Exception e) {
			Log.e(0, this, e);
			return false;
		}
		
		return true;
	}
	
	protected int readBytes(byte[] buffer, int offset, int length) {
		if (mInStream == null) {
			return 0;
		}
		
		try {
			lengthSum = 0;
			while (true) {
				if (lengthSum == length) {
					return 1;
				}
				
				lengthRead = mInStream.read(buffer, offset + lengthSum, length - lengthSum);
				
				if (lengthRead == -1) {
					return -1;
				} else {
					lengthSum += lengthRead;
				}
			}
		} catch (SocketTimeoutException e) {
			e.printStackTrace();
			return 0;
		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		}
	}
	
	protected void closeSocket() {
		Log.d(0, this, "closeSocket");
		if (mSocket != null) {
			try {
				Log.d(0, this, "shutdownInput");
				mSocket.shutdownInput();
			} catch (Exception e) {
				Log.e(0, this, e);
				e.printStackTrace();
			} finally {
			}
			
			try {
				Log.d(0, this, "shutdownOutput");
				mSocket.shutdownOutput();
			} catch (Exception e) {
				Log.e(0, this, e);
				e.printStackTrace();
			} finally {
			}
			
			if (mInStream != null) {
				try {
					Log.d(0, this, "inStream close");
					mInStream.close();
				} catch (Exception e) {
					Log.e(0, this, e);
					e.printStackTrace();
					
				} finally {
					mInStream = null;
				}
			}
			
			if (mOutStream != null) {
				try {
					Log.d(0, this, "outStream close");
					mOutStream.close();
				} catch (Exception e) {
					Log.e(0, this, e);
					e.printStackTrace();
				} finally {
					mOutStream = null;
				}
			}
			
			try {
				Log.d(0, this, "socket close");
				mSocket.close();
			} catch (Exception e) {
				Log.e(0, this, e);
				e.printStackTrace();
			} finally {
				mSocket = null;
			}
			
		}
	}
}
