/*
 * Copyright (C) 2016 Google Inc.
 *
 * 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.googlecode.android_scripting.facade.bluetooth;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable;

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Bundle;

import com.googlecode.android_scripting.ConvertUtils;
import com.googlecode.android_scripting.Log;
import com.googlecode.android_scripting.MainThread;
import com.googlecode.android_scripting.facade.EventFacade;
import com.googlecode.android_scripting.facade.FacadeManager;
import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
import com.googlecode.android_scripting.rpc.Rpc;
import com.googlecode.android_scripting.rpc.RpcParameter;

public class GattServerFacade extends RpcReceiver {
  private final EventFacade mEventFacade;
  private BluetoothAdapter mBluetoothAdapter;
  private BluetoothManager mBluetoothManager;
  private final Service mService;
  private final Context mContext;
  private final HashMap<Integer, BluetoothGattCharacteristic> mCharacteristicList;
  private final HashMap<Integer, BluetoothGattDescriptor> mDescriptorList;
  private final HashMap<Integer, BluetoothGattServer> mBluetoothGattServerList;
  private final HashMap<Integer, myBluetoothGattServerCallback> mBluetoothGattServerCallbackList;
  private final HashMap<Integer, BluetoothGattService> mGattServiceList;
  private final HashMap<Integer, List<BluetoothGattService>> mBluetoothGattDiscoveredServicesList;
  private final HashMap<Integer, List<BluetoothDevice>> mGattServerDiscoveredDevicesList;
  private static int CharacteristicCount;
  private static int DescriptorCount;
  private static int GattServerCallbackCount;
  private static int GattServerCount;
  private static int GattServiceCount;

  public GattServerFacade(FacadeManager manager) {
    super(manager);
    mService = manager.getService();
    mContext = mService.getApplicationContext();
    mBluetoothAdapter = MainThread.run(mService, new Callable<BluetoothAdapter>() {
      @Override
      public BluetoothAdapter call() throws Exception {
        return BluetoothAdapter.getDefaultAdapter();
      }
    });
    mBluetoothManager = (BluetoothManager) mContext.getSystemService(Service.BLUETOOTH_SERVICE);
    mEventFacade = manager.getReceiver(EventFacade.class);
    mCharacteristicList = new HashMap<Integer, BluetoothGattCharacteristic>();
    mDescriptorList = new HashMap<Integer, BluetoothGattDescriptor>();
    mBluetoothGattServerList = new HashMap<Integer, BluetoothGattServer>();
    mBluetoothGattServerCallbackList = new HashMap<Integer, myBluetoothGattServerCallback>();
    mGattServiceList = new HashMap<Integer, BluetoothGattService>();
    mBluetoothGattDiscoveredServicesList = new HashMap<Integer, List<BluetoothGattService>>();
    mGattServerDiscoveredDevicesList = new HashMap<Integer, List<BluetoothDevice>>();
  }

  /**
   * Open a new Gatt server.
   *
   * @param index the bluetooth gatt server callback to open on
   * @return the index of the newly opened gatt server
   * @throws Exception
   */
  @Rpc(description = "Open new gatt server")
  public int gattServerOpenGattServer(@RpcParameter(name = "index") Integer index)
      throws Exception {
    if (mBluetoothGattServerCallbackList.get(index) != null) {
      BluetoothGattServer mGattServer =
          mBluetoothManager.openGattServer(mContext, mBluetoothGattServerCallbackList.get(index));
      GattServerCount += 1;
      int in = GattServerCount;
      mBluetoothGattServerList.put(in, mGattServer);
      return in;
    } else {
      throw new Exception("Invalid index input:" + Integer.toString(index));
    }
  }

  /**
   * Add a service to a bluetooth gatt server
   *
   * @param index the bluetooth gatt server to add a service to
   * @param serviceIndex the service to add to the bluetooth gatt server
   * @throws Exception
   */
  @Rpc(description = "Add service to bluetooth gatt server")
  public void gattServerAddService(@RpcParameter(name = "index") Integer index,
      @RpcParameter(name = "serviceIndex") Integer serviceIndex) throws Exception {
    if (mBluetoothGattServerList.get(index) != null) {
      if (mGattServiceList.get(serviceIndex) != null) {
        mBluetoothGattServerList.get(index).addService(mGattServiceList.get(serviceIndex));
      } else {
        throw new Exception("Invalid serviceIndex input:" + Integer.toString(serviceIndex));
      }
    } else {
      throw new Exception("Invalid index input:" + Integer.toString(index));
    }
  }

  /**
   * Get connected devices of the gatt server
   *
   * @param gattServerIndex the gatt server index
   * @throws Exception
   */
  @Rpc(description = "Return a list of connected gatt devices.")
  public List<BluetoothDevice> gattServerGetConnectedDevices(
      @RpcParameter(name = "gattServerIndex") Integer gattServerIndex) throws Exception {
    if (mBluetoothGattServerList.get(gattServerIndex) == null) {
      throw new Exception("Invalid gattServerIndex: " + Integer.toString(gattServerIndex));
    }
    List<BluetoothDevice> connectedDevices =
        mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT_SERVER);
    mGattServerDiscoveredDevicesList.put(gattServerIndex, connectedDevices);
    return connectedDevices;
  }

  /**
   * Get connected devices of the gatt server
   *
   * @param gattServerIndex the gatt server index
   * @param bluetoothDeviceIndex the remotely connected bluetooth device
   * @param requestId the ID of the request that was received with the callback
   * @param status the status of the request to be sent to the remote devices
   * @param offset value offset for partial read/write response
   * @param value the value of the attribute that was read/written
   * @throws Exception
   */
  @Rpc(description = "Send a response after a write.")
  public void gattServerSendResponse(
      @RpcParameter(name = "gattServerIndex") Integer gattServerIndex,
      @RpcParameter(name = "bluetoothDeviceIndex") Integer bluetoothDeviceIndex,
      @RpcParameter(name = "requestId") Integer requestId,
      @RpcParameter(name = "status") Integer status, @RpcParameter(name = "offset") Integer offset,
      @RpcParameter(name = "value") String value) throws Exception {

    BluetoothGattServer gattServer = mBluetoothGattServerList.get(gattServerIndex);
    if (gattServer == null)
      throw new Exception("Invalid gattServerIndex: " + Integer.toString(gattServerIndex));
    List<BluetoothDevice> connectedDevices = mGattServerDiscoveredDevicesList.get(gattServerIndex);
    if (connectedDevices == null)
      throw new Exception(
          "Connected device list empty for gattServerIndex:" + Integer.toString(gattServerIndex));
    BluetoothDevice bluetoothDevice = connectedDevices.get(bluetoothDeviceIndex);
    if (bluetoothDevice == null)
      throw new Exception(
          "Invalid bluetoothDeviceIndex: " + Integer.toString(bluetoothDeviceIndex));
    gattServer.sendResponse(bluetoothDevice, requestId, status, offset,
        ConvertUtils.convertStringToByteArray(value));
  }

  /**
   * Create a new bluetooth gatt service
   *
   * @param uuid the UUID that characterises the service
   * @param serviceType the service type
   * @return The index of the new bluetooth gatt service
   */
  @Rpc(description = "Create new bluetooth gatt service")
  public int gattServerCreateService(@RpcParameter(name = "uuid") String uuid,
      @RpcParameter(name = "serviceType") Integer serviceType) {
    GattServiceCount += 1;
    int index = GattServiceCount;
    mGattServiceList.put(index, new BluetoothGattService(UUID.fromString(uuid), serviceType));
    return index;
  }

  // TODO: Finish this for bluetooth device, need to create a bt device list.
  /*
   * @Rpc(description = "cancel gatt server connection by device") public void
   * gattServerCancelConnection(
   *
   * @RpcParameter(name = "index") Integer index,
   *
   * @RpcParameter(name = "deviceIndex") Integer bluetoothDevice ) throws Exception { if
   * (mBluetoothGattServerList.get(index) != null) {
   * mBluetoothGattServerList.get(index).cancelConnection(bluetoothDevice); } else { throw new
   * Exception("Invalid index input:" + Integer.toString(index)); } }
   */

  /**
   * Add a characteristic to a bluetooth gatt service
   *
   * @param index the bluetooth gatt service index
   * @param serviceUuid the service Uuid to get
   * @param characteristicIndex the character index to use
   * @throws Exception
   */
  @Rpc(description = "Add a characteristic to a bluetooth gatt service")
  public void gattServiceAddCharacteristic(@RpcParameter(name = "index") Integer index,
      @RpcParameter(name = "serviceUuid") String serviceUuid,
      @RpcParameter(name = "characteristicIndex") Integer characteristicIndex) throws Exception {
    if (mBluetoothGattServerList.get(index) != null
        && mBluetoothGattServerList.get(index).getService(UUID.fromString(serviceUuid)) != null
        && mCharacteristicList.get(characteristicIndex) != null) {
      mBluetoothGattServerList.get(index).getService(UUID.fromString(serviceUuid))
          .addCharacteristic(mCharacteristicList.get(characteristicIndex));
    } else {
      if (mBluetoothGattServerList.get(index) == null) {
        throw new Exception("Invalid index input:" + index);
      } else if (mCharacteristicList.get(characteristicIndex) == null) {
        throw new Exception("Invalid characteristicIndex input:" + characteristicIndex);
      } else {
        throw new Exception("Invalid serviceUuid input:" + serviceUuid);
      }
    }
  }

  /**
   * Add a characteristic to a bluetooth gatt service
   *
   * @param index the bluetooth gatt service to add a characteristic to
   * @param characteristicIndex the characteristic to add
   * @throws Exception
   */
  @Rpc(description = "Add a characteristic to a bluetooth gatt service")
  public void gattServerAddCharacteristicToService(@RpcParameter(name = "index") Integer index,
      @RpcParameter(name = "characteristicIndex") Integer characteristicIndex

  ) throws Exception {
    if (mGattServiceList.get(index) != null) {
      if (mCharacteristicList.get(characteristicIndex) != null) {
        mGattServiceList.get(index).addCharacteristic(mCharacteristicList.get(characteristicIndex));
      } else {
        throw new Exception("Invalid index input:" + index);
      }
    } else {
      throw new Exception("Invalid index input:" + index);
    }
  }

  /**
   * Close a bluetooth gatt
   *
   * @param index the bluetooth gatt index to close
   * @throws Exception
   */
  @Rpc(description = "Close a bluetooth gatt")
  public void gattServerClose(@RpcParameter(name = "index") Integer index) throws Exception {
    if (mBluetoothGattServerList.get(index) != null) {
      mBluetoothGattServerList.get(index).close();
    } else {
      throw new Exception("Invalid index input:" + index);
    }
  }

  /**
   * Get a list of Bluetooth Devices connnected to the bluetooth gatt
   *
   * @param index the bluetooth gatt index
   * @return List of BluetoothDevice Objects
   * @throws Exception
   */
  @Rpc(description = "Get a list of Bluetooth Devices connnected to the bluetooth gatt")
  public List<BluetoothDevice> gattGetConnectedDevices(@RpcParameter(name = "index") Integer index)
      throws Exception {
    if (mBluetoothGattServerList.get(index) != null) {
      return mBluetoothGattServerList.get(index).getConnectedDevices();
    } else {
      throw new Exception("Invalid index input:" + index);
    }
  }

  /**
   * Get the service from an input UUID
   *
   * @param index the bluetooth gatt index
   * @return BluetoothGattService related to the bluetooth gatt
   * @throws Exception
   */
  @Rpc(description = "Get the service from an input UUID")
  public ArrayList<String> gattGetServiceUuidList(@RpcParameter(name = "index") Integer index)
      throws Exception {
    if (mBluetoothGattServerList.get(index) != null) {
      ArrayList<String> serviceUuidList = new ArrayList<String>();
      for (BluetoothGattService service : mBluetoothGattServerList.get(index).getServices()) {
        serviceUuidList.add(service.getUuid().toString());
      }
      return serviceUuidList;
    } else {
      throw new Exception("Invalid index input:" + index);
    }
  }

  /**
   * Get the service from an input UUID
   *
   * @param index the bluetooth gatt index
   * @param uuid the String uuid that matches the service
   * @return BluetoothGattService related to the bluetooth gatt
   * @throws Exception
   */
  @Rpc(description = "Get the service from an input UUID")
  public BluetoothGattService gattGetService(@RpcParameter(name = "index") Integer index,
      @RpcParameter(name = "uuid") String uuid) throws Exception {
    if (mBluetoothGattServerList.get(index) != null) {
      return mBluetoothGattServerList.get(index).getService(UUID.fromString(uuid));
    } else {
      throw new Exception("Invalid index input:" + index);
    }
  }

  /**
   * Add a descriptor to a bluetooth gatt characteristic
   *
   * @param index the bluetooth gatt characteristic to add a descriptor to
   * @param descriptorIndex the descritor index to add to the characteristic
   * @throws Exception
   */
  @Rpc(description = "add descriptor to blutooth gatt characteristic")
  public void gattServerCharacteristicAddDescriptor(@RpcParameter(name = "index") Integer index,
      @RpcParameter(name = "descriptorIndex") Integer descriptorIndex) throws Exception {
    if (mCharacteristicList.get(index) != null) {
      if (mDescriptorList.get(descriptorIndex) != null) {
        mCharacteristicList.get(index).addDescriptor(mDescriptorList.get(descriptorIndex));
      } else {
        throw new Exception("Invalid descriptorIndex input:" + descriptorIndex);
      }
    } else {
      throw new Exception("Invalid index input:" + index);
    }
  }

  /**
   * Create a new Characteristic object
   *
   * @param characteristicUuid uuid The UUID for this characteristic
   * @param property Properties of this characteristic
   * @param permission permissions Permissions for this characteristic
   * @return
   */
  @Rpc(description = "Create a new Characteristic object")
  public int gattServerCreateBluetoothGattCharacteristic(
      @RpcParameter(name = "characteristicUuid") String characteristicUuid,
      @RpcParameter(name = "property") Integer property,
      @RpcParameter(name = "permission") Integer permission) {
    CharacteristicCount += 1;
    int index = CharacteristicCount;
    BluetoothGattCharacteristic characteristic =
        new BluetoothGattCharacteristic(UUID.fromString(characteristicUuid), property, permission);
    mCharacteristicList.put(index, characteristic);
    return index;
  }

  /**
   * Create a new GattCallback object
   *
   * @return the index of the callback object
   */
  @Rpc(description = "Create a new GattCallback object")
  public Integer gattServerCreateGattServerCallback() {
    GattServerCallbackCount += 1;
    int index = GattServerCallbackCount;
    mBluetoothGattServerCallbackList.put(index, new myBluetoothGattServerCallback(index));
    return index;
  }

  /**
   * Create a new Descriptor object
   *
   * @param descriptorUuid the UUID for this descriptor
   * @param permissions Permissions for this descriptor
   * @return the index of the Descriptor object
   */
  @Rpc(description = "Create a new Descriptor object")
  public int gattServerCreateBluetoothGattDescriptor(
      @RpcParameter(name = "descriptorUuid") String descriptorUuid,
      @RpcParameter(name = "permissions") Integer permissions) {
    DescriptorCount += 1;
    int index = DescriptorCount;
    BluetoothGattDescriptor descriptor =
        new BluetoothGattDescriptor(UUID.fromString(descriptorUuid), permissions);
    mDescriptorList.put(index, descriptor);
    return index;
  }

  private class myBluetoothGattServerCallback extends BluetoothGattServerCallback {
    private final Bundle mResults;
    private final int index;
    private final String mEventType;

    public myBluetoothGattServerCallback(int idx) {
      mResults = new Bundle();
      mEventType = "GattServer";
      index = idx;
    }

    @Override
    public void onServiceAdded(int status, BluetoothGattService service) {
      Log.d("gatt_server change onServiceAdded " + mEventType + " " + index);
      mResults.putString("serviceUuid", service.getUuid().toString());
      mResults.putInt("instanceId", service.getInstanceId());
      mEventFacade.postEvent(mEventType + index + "onServiceAdded", mResults.clone());
      mResults.clear();
    }

    @Override
    public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset,
        BluetoothGattCharacteristic characteristic) {
      Log.d("gatt_server change onCharacteristicReadRequest " + mEventType + " " + index);
      mResults.putInt("requestId", requestId);
      mResults.putInt("offset", offset);
      mResults.putInt("instanceId", characteristic.getInstanceId());
      mResults.putInt("properties", characteristic.getProperties());
      mResults.putString("uuid", characteristic.getUuid().toString());
      mResults.putInt("permissions", characteristic.getPermissions());
      mEventFacade.postEvent(mEventType + index + "onCharacteristicReadRequest", mResults.clone());
      mResults.clear();
    }

    @Override
    public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
        BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded,
        int offset, byte[] value) {
      Log.d("gatt_server change onCharacteristicWriteRequest " + mEventType + " " + index);
      mResults.putInt("requestId", requestId);
      mResults.putInt("offset", offset);
      mResults.putParcelable("BluetoothDevice", device);
      mResults.putBoolean("preparedWrite", preparedWrite);
      mResults.putBoolean("responseNeeded", responseNeeded);
      mResults.putString("value", ConvertUtils.convertByteArrayToString(value));
      mResults.putInt("instanceId", characteristic.getInstanceId());
      mResults.putInt("properties", characteristic.getProperties());
      mResults.putString("uuid", characteristic.getUuid().toString());
      mResults.putInt("permissions", characteristic.getPermissions());
      mEventFacade.postEvent(mEventType + index + "onCharacteristicWriteRequest", mResults.clone());
      mResults.clear();

    }

    @Override
    public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset,
        BluetoothGattDescriptor descriptor) {
      Log.d("gatt_server change onDescriptorReadRequest " + mEventType + " " + index);
      mResults.putInt("requestId", requestId);
      mResults.putInt("offset", offset);
      mResults.putParcelable("BluetoothDevice", device);
      mResults.putInt("instanceId", descriptor.getInstanceId());
      mResults.putInt("permissions", descriptor.getPermissions());
      mResults.putString("uuid", descriptor.getUuid().toString());
      mEventFacade.postEvent(mEventType + index + "onDescriptorReadRequest", mResults.clone());
      mResults.clear();
    }

    @Override
    public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
        BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded,
        int offset, byte[] value) {
      Log.d("gatt_server change onDescriptorWriteRequest " + mEventType + " " + index);
      mResults.putInt("requestId", requestId);
      mResults.putInt("offset", offset);
      mResults.putParcelable("BluetoothDevice", device);
      mResults.putBoolean("preparedWrite", preparedWrite);
      mResults.putBoolean("responseNeeded", responseNeeded);
      mResults.putString("value", ConvertUtils.convertByteArrayToString(value));
      mResults.putInt("instanceId", descriptor.getInstanceId());
      mResults.putInt("permissions", descriptor.getPermissions());
      mResults.putString("uuid", descriptor.getUuid().toString());
      mEventFacade.postEvent(mEventType + index + "onDescriptorWriteRequest", mResults.clone());
      mResults.clear();
    }

    @Override
    public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
      Log.d("gatt_server change onExecuteWrite " + mEventType + " " + index);
      mResults.putParcelable("BluetoothDevice", device);
      mResults.putInt("requestId", requestId);
      mResults.putBoolean("execute", execute);
      mEventFacade.postEvent(mEventType + index + "onExecuteWrite", mResults.clone());
      mResults.clear();
    }

    @Override
    public void onNotificationSent(BluetoothDevice device, int status) {
      Log.d("gatt_server change onNotificationSent " + mEventType + " " + index);
      mResults.putParcelable("BluetoothDevice", device);
      mResults.putInt("status", status);
      mEventFacade.postEvent(mEventType + index + "onNotificationSent", mResults.clone());
      mResults.clear();
    }

    @Override
    public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
      Log.d("gatt_server change onConnectionStateChange " + mEventType + " " + index);
      if (newState == BluetoothProfile.STATE_CONNECTED) {
        Log.d("State Connected to mac address " + device.getAddress() + " status " + status);
      } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
        Log.d("State Disconnected from mac address " + device.getAddress() + " status " + status);
      }
      mResults.putParcelable("BluetoothDevice", device);
      mResults.putInt("status", status);
      mResults.putInt("newState", newState);
      mEventFacade.postEvent(mEventType + index + "onConnectionStateChange", mResults.clone());
      mResults.clear();
    }

    @Override
    public void onMtuChanged(BluetoothDevice device, int mtu) {
      Log.d("gatt_server change onMtuChanged " + mEventType + " " + index);
      mResults.putParcelable("BluetoothDevice", device);
      mResults.putInt("mtu", mtu);
      mEventFacade.postEvent(mEventType + index + "onMtuChanged", mResults.clone());
      mResults.clear();
    }
  }

  @Override
  public void shutdown() {
    if (!mBluetoothGattServerList.isEmpty()) {
      if (mBluetoothGattServerList.values() != null) {
        for (BluetoothGattServer mBluetoothGattServer : mBluetoothGattServerList.values()) {
          mBluetoothGattServer.close();
        }
      }
    }
  }
}
