/*
 * Copyright 2014-2015 Neofect Co., Ltd.
 * 
 * Licensed 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
 * 
 *     http://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 com.neofect.communicator.bluetooth.spp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.bluetooth.BluetoothSocket;
import android.util.Log;

import com.neofect.communicator.bluetooth.BluetoothConnection;

/**
 * This thread is to read data from connected Bluetooth socket with synchronous manner. The read() function in run() is being blocked until any data received.
 * This class also has a logic for writing data to Bluetooth socket, but it's not done in a read thread. The thread is only for read.
 * 
 * @author neo.kim@neofect.com
 */
class BluetoothSppTransferThread extends Thread {

	private static final String LOG_TAG = BluetoothSppTransferThread.class.getSimpleName();
	private static final int BUFFER_SIZE	= 1024;
	
	private BluetoothSppConnection connection;
	
	private BluetoothSocket socket;
	private InputStream inputStream; 
	private OutputStream outputStream;

	private byte[] buffer = new byte[BUFFER_SIZE];
	private boolean isSocketClosed = false;
	
	/**
	 * Constructor for {@link BluetoothSppTransferThread}. This throws IOException when failed to get input / output streams from provided socket.
	 * 
	 * @param connection
	 * @param socket
	 * @throws IOException
	 */
	BluetoothSppTransferThread(BluetoothSppConnection connection, BluetoothSocket socket) throws IOException {
		super("BluetoothSppTransferThread");
		this.connection = connection;
		this.socket = socket;
		inputStream = socket.getInputStream();
		outputStream = socket.getOutputStream();
	}
	
	void cancel() {
		try {
			synchronized(this) {
				if(!isSocketClosed) {
					socket.close();
					isSocketClosed = true;
				}
			}
		} catch (IOException e) {
			Log.e(LOG_TAG, "cancel() Failed to close the socket", e);
		}
	}
	
	void write(byte[] data) {
		if(isSocketClosed) {
			Log.e(LOG_TAG, "write() Connection is closed!");
			return;
		}
		try {
			outputStream.write(data);
			connection.onWroteMessage(data);
		} catch (Exception e) {
			Log.e(LOG_TAG, "write() Failed to write!", e);
			onDisconnected();
		}
	}
	
	private void onDisconnected() {
		synchronized(this) {
			try {
				inputStream.close();
			} catch (IOException e) {
				Log.e(LOG_TAG, "", e);
			}
			try {
				outputStream.close();
			} catch (IOException e) {
				Log.e(LOG_TAG, "", e);
			}
			cancel();
		}
		connection.onDisconnected();
	}
	
	@Override
	public void run() {
		// If it is still trying to connect, wait some time.
		while(connection.getStatus() == BluetoothConnection.Status.CONNECTING) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				Log.e(LOG_TAG, "", e);
			}
		}
		
		// Read loop
		while (connection.isConnected()) {
			try {
				// Read data from the input stream
				int numberOfReadBytes = inputStream.read(buffer, 0, buffer.length);
				
				byte[] readData = new byte[numberOfReadBytes];
				System.arraycopy(buffer, 0, readData, 0, numberOfReadBytes);
				connection.onReadMessage(readData);
			} catch (IOException e) {
				Log.d(LOG_TAG, "run() IOException on read(), device=" + connection.getDescriptionWithAddress());
				onDisconnected();
			}
		}
	}
	
}

@@ -1609,19 +1609,17 @@
 boolean 
-isS
+s
 ocketClo
@@ -2205,19 +2205,17 @@
 %09%09%09%09if(!
-isS
+s
 ocketClo
@@ -2247,19 +2247,17 @@
 );%0A%09%09%09%09%09
-isS
+s
 ocketClo
@@ -2410,29 +2410,65 @@
 %7B%0A%09%09
-if(isSocketClosed
+synchronized(this) %7B%0A%09%09%09if(!connection.isConnected()
 ) %7B%0A
+%09
 %09%09%09L
@@ -2522,16 +2522,17 @@
 %0A%09%09%09
+%09
 return;%0A
 %09%09%7D%0A
@@ -2531,20 +2531,23 @@
 rn;%0A
+%09
 %09%09%7D%0A%09%09
+%09
 try %7B%0A
+%09
 %09%09%09o
@@ -2574,16 +2574,17 @@
 ta);%0A%09%09%09
+%09
 connecti
@@ -2608,16 +2608,17 @@
 (data);%0A
+%09
 %09%09%7D catc
@@ -2630,32 +2630,33 @@
 ception e) %7B%0A%09%09%09
+%09
 Log.e(LOG_TAG, %22
@@ -2689,16 +2689,17 @@
  e);%0A%09%09%09
+%09
 onDiscon
@@ -2704,24 +2704,29 @@
 onnected();%0A
+%09%09%09%7D%0A
 %09%09%7D%0A%09%7D%0A%09%0A%09pr
@@ -2774,24 +2774,76 @@
 zed(this) %7B%0A
+%09%09%09if(!connection.isConnected()) %7B%0A%09%09%09%09return;%0A%09%09%09%7D%0A
 %09%09%09try %7B%0A%09%09%09
@@ -3035,19 +3035,16 @@
 cel();%0A%09
-%09%7D%0A
 %09%09connec
@@ -3062,24 +3062,28 @@
 onnected();%0A
+%09%09%7D%0A
 %09%7D%0A%09%0A%09@Overr

Make some methods be synchronous