/**
 * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
 * This file is part of CSipSimple.
 *
 *  CSipSimple is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  If you own a pjsip commercial license you can also redistribute it
 *  and/or modify it under the terms of the GNU Lesser General Public License
 *  as an android library.
 *
 *  CSipSimple is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with CSipSimple.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.csipsimple.utils.bluetooth;


import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothClass.Device;
import android.bluetooth.BluetoothClass.Service;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;

import com.csipsimple.utils.Log;

import java.util.Set;

@TargetApi(8)
public class BluetoothUtils8 extends BluetoothWrapper {

	private static final String THIS_FILE = "BT8";
	private AudioManager audioManager;
	
	private boolean isBluetoothConnected = false;
	
	private BroadcastReceiver mediaStateReceiver = new BroadcastReceiver() {
		
        @SuppressWarnings("deprecation")
        @Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			Log.d(THIS_FILE, ">>> BT SCO state changed !!! ");
			if(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED.equals(action)) {
				int status = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, AudioManager.SCO_AUDIO_STATE_ERROR );
				Log.d(THIS_FILE, "BT SCO state changed : " + status + " target is " + targetBt);
				audioManager.setBluetoothScoOn(targetBt);
				
				if(status == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
					isBluetoothConnected = true;
				}else if(status == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
					isBluetoothConnected = false;
				}
				
				if(btChangesListener != null) {
				    btChangesListener.onBluetoothStateChanged(status);
				}
			}
		}
	};
	
	protected BluetoothAdapter bluetoothAdapter;

	@Override
	public void setContext(Context aContext){
		super.setContext(aContext);
		audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
		if(bluetoothAdapter == null) {
    		try {
    			bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    		}catch(RuntimeException e) {
    			Log.w(THIS_FILE, "Cant get default bluetooth adapter ", e);
    		}
		}
	}
	
	public boolean canBluetooth() {
		// Detect if any bluetooth a device is available for call
		if (bluetoothAdapter == null) {
		    // Device does not support Bluetooth
			return false;
		}
		boolean hasConnectedDevice = false;
		//If bluetooth is on
		if(bluetoothAdapter.isEnabled()) {
			
			//We get all bounded bluetooth devices
			// bounded is not enough, should search for connected devices....
			Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
			for(BluetoothDevice device : pairedDevices) {
				BluetoothClass bluetoothClass = device.getBluetoothClass();
                if (bluetoothClass != null) {
                	int deviceClass = bluetoothClass.getDeviceClass();
                	if(bluetoothClass.hasService(Service.RENDER) ||
                		deviceClass == Device.AUDIO_VIDEO_WEARABLE_HEADSET ||
                		deviceClass == Device.AUDIO_VIDEO_CAR_AUDIO ||
                		deviceClass == Device.AUDIO_VIDEO_HANDSFREE ) {
	                    	//And if any can be used as a audio handset
	                    	hasConnectedDevice = true;
	                    	break;
                	}
				}
			}
		}
		boolean retVal = hasConnectedDevice && audioManager.isBluetoothScoAvailableOffCall();
		Log.d(THIS_FILE, "Can I do BT ? "+retVal);
		return retVal;
	}
	
	private boolean targetBt = false;
	public void setBluetoothOn(boolean on) {
		Log.d(THIS_FILE, "Ask for "+on+" vs "+audioManager.isBluetoothScoOn());
		targetBt = on;
		if(on != isBluetoothConnected) {
		    // BT SCO connection state is different from required activation
			if(on) {
			    // First we try to connect
				Log.d(THIS_FILE, "BT SCO on >>>");
                audioManager.startBluetoothSco();
			}else {
				Log.d(THIS_FILE, "BT SCO off >>>");
				// We stop to use BT SCO
				audioManager.setBluetoothScoOn(false);
				// And we stop BT SCO connection
				audioManager.stopBluetoothSco();
			}
		}else if(on != audioManager.isBluetoothScoOn()) {
		    // BT SCO is already in desired connection state
		    // we only have to use it
		    audioManager.setBluetoothScoOn(on);
		}
	}
	
	public boolean isBluetoothOn() {
		return isBluetoothConnected;
	}
	
	@SuppressWarnings("deprecation")
    public void register() {
		Log.d(THIS_FILE, "Register BT media receiver");
		context.registerReceiver(mediaStateReceiver , new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED));
	}

	public void unregister() {
		try {
			Log.d(THIS_FILE, "Unregister BT media receiver");
			context.unregisterReceiver(mediaStateReceiver);
		}catch(Exception e) {
			Log.w(THIS_FILE, "Failed to unregister media state receiver",e);
		}
	}

    @Override
    public boolean isBTHeadsetConnected() {
        return canBluetooth();
    }
}