/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * 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.android.bluetoothmidiservice;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.media.midi.MidiDeviceInfo;
import android.media.midi.MidiDeviceServer;
import android.media.midi.MidiDeviceStatus;
import android.media.midi.MidiManager;
import android.media.midi.MidiReceiver;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;

import com.android.internal.midi.MidiEventScheduler;
import com.android.internal.midi.MidiEventScheduler.MidiEvent;

import libcore.io.IoUtils;

import java.io.IOException;
import java.util.List;
import java.util.UUID;

/**
 * Class used to implement a Bluetooth MIDI device.
 */
public final class BluetoothMidiDevice {

    private static final String TAG = "BluetoothMidiDevice";
    private static final boolean DEBUG = false;

    private static final int MAX_PACKET_SIZE = 20;

    //  Bluetooth MIDI Gatt service UUID
    private static final UUID MIDI_SERVICE = UUID.fromString(
            "03B80E5A-EDE8-4B33-A751-6CE34EC4C700");
    // Bluetooth MIDI Gatt characteristic UUID
    private static final UUID MIDI_CHARACTERISTIC = UUID.fromString(
            "7772E5DB-3868-4112-A1A9-F2669D106BF3");
    // Descriptor UUID for enabling characteristic changed notifications
    private static final UUID CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString(
            "00002902-0000-1000-8000-00805f9b34fb");

    private final BluetoothDevice mBluetoothDevice;
    private final BluetoothMidiService mService;
    private final MidiManager mMidiManager;
    private MidiReceiver mOutputReceiver;
    private final MidiEventScheduler mEventScheduler = new MidiEventScheduler();

    private MidiDeviceServer mDeviceServer;
    private BluetoothGatt mBluetoothGatt;

    private BluetoothGattCharacteristic mCharacteristic;

    // PacketReceiver for receiving formatted packets from our BluetoothPacketEncoder
    private final PacketReceiver mPacketReceiver = new PacketReceiver();

    private final BluetoothPacketEncoder mPacketEncoder
            = new BluetoothPacketEncoder(mPacketReceiver, MAX_PACKET_SIZE);

    private final BluetoothPacketDecoder mPacketDecoder
            = new BluetoothPacketDecoder(MAX_PACKET_SIZE);

    private final MidiDeviceServer.Callback mDeviceServerCallback
            = new MidiDeviceServer.Callback() {
        @Override
        public void onDeviceStatusChanged(MidiDeviceServer server, MidiDeviceStatus status) {
        }

        @Override
        public void onClose() {
            close();
        }
    };

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status,
                int newState) {
            String intentAction;
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                Log.d(TAG, "Connected to GATT server.");
                Log.d(TAG, "Attempting to start service discovery:" +
                        mBluetoothGatt.discoverServices());
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                Log.i(TAG, "Disconnected from GATT server.");
                close();
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                BluetoothGattService service = gatt.getService(MIDI_SERVICE);
                if (service != null) {
                    Log.d(TAG, "found MIDI_SERVICE");
                    BluetoothGattCharacteristic characteristic
                            = service.getCharacteristic(MIDI_CHARACTERISTIC);
                    if (characteristic != null) {
                        Log.d(TAG, "found MIDI_CHARACTERISTIC");
                        mCharacteristic = characteristic;

                        // Request a lower Connection Interval for better latency.
                        boolean result = gatt.requestConnectionPriority(
                                BluetoothGatt.CONNECTION_PRIORITY_HIGH);
                        Log.d(TAG, "requestConnectionPriority(CONNECTION_PRIORITY_HIGH):"
                            + result);

                        // Specification says to read the characteristic first and then
                        // switch to receiving notifications
                        mBluetoothGatt.readCharacteristic(characteristic);
                    }
                }
            } else {
                Log.e(TAG, "onServicesDiscovered received: " + status);
                close();
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic,
                int status) {
            Log.d(TAG, "onCharacteristicRead " + status);

            // switch to receiving notifications after initial characteristic read
            mBluetoothGatt.setCharacteristicNotification(characteristic, true);

            // Use writeType that requests acknowledgement.
            // This improves compatibility with various BLE-MIDI devices.
            int originalWriteType = characteristic.getWriteType();
            characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);

            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
                    CLIENT_CHARACTERISTIC_CONFIG);
            if (descriptor != null) {
                descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                boolean result = mBluetoothGatt.writeDescriptor(descriptor);
                Log.d(TAG, "writeDescriptor returned " + result);
            } else {
                Log.e(TAG, "No CLIENT_CHARACTERISTIC_CONFIG for device " + mBluetoothDevice);
            }

            characteristic.setWriteType(originalWriteType);
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic,
                int status) {
            Log.d(TAG, "onCharacteristicWrite " + status);
            mPacketEncoder.writeComplete();
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic characteristic) {
            if (DEBUG) {
                logByteArray("Received ", characteristic.getValue(), 0,
                        characteristic.getValue().length);
            }
            mPacketDecoder.decodePacket(characteristic.getValue(), mOutputReceiver);
        }
    };

    // This receives MIDI data that has already been passed through our MidiEventScheduler
    // and has been normalized by our MidiFramer.

    private class PacketReceiver implements PacketEncoder.PacketReceiver {
        // buffers of every possible packet size
        private final byte[][] mWriteBuffers;

        public PacketReceiver() {
            // Create buffers of every possible packet size
            mWriteBuffers = new byte[MAX_PACKET_SIZE + 1][];
            for (int i = 0; i <= MAX_PACKET_SIZE; i++) {
                mWriteBuffers[i] = new byte[i];
            }
        }

        @Override
        public void writePacket(byte[] buffer, int count) {
            if (mCharacteristic == null) {
                Log.w(TAG, "not ready to send packet yet");
                return;
            }
            byte[] writeBuffer = mWriteBuffers[count];
            System.arraycopy(buffer, 0, writeBuffer, 0, count);
            mCharacteristic.setValue(writeBuffer);
            if (DEBUG) {
                logByteArray("Sent ", mCharacteristic.getValue(), 0,
                       mCharacteristic.getValue().length);
            }
            mBluetoothGatt.writeCharacteristic(mCharacteristic);
        }
    }

    public BluetoothMidiDevice(Context context, BluetoothDevice device,
            BluetoothMidiService service) {
        mBluetoothDevice = device;
        mService = service;

        mBluetoothGatt = mBluetoothDevice.connectGatt(context, false, mGattCallback);

        mMidiManager = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);

        Bundle properties = new Bundle();
        properties.putString(MidiDeviceInfo.PROPERTY_NAME, mBluetoothGatt.getDevice().getName());
        properties.putParcelable(MidiDeviceInfo.PROPERTY_BLUETOOTH_DEVICE,
                mBluetoothGatt.getDevice());

        MidiReceiver[] inputPortReceivers = new MidiReceiver[1];
        inputPortReceivers[0] = mEventScheduler.getReceiver();

        mDeviceServer = mMidiManager.createDeviceServer(inputPortReceivers, 1,
                null, null, properties, MidiDeviceInfo.TYPE_BLUETOOTH, mDeviceServerCallback);

        mOutputReceiver = mDeviceServer.getOutputPortReceivers()[0];

        // This thread waits for outgoing messages from our MidiEventScheduler
        // And forwards them to our MidiFramer to be prepared to send via Bluetooth.
        new Thread("BluetoothMidiDevice " + mBluetoothDevice) {
            @Override
            public void run() {
                while (true) {
                    MidiEvent event;
                    try {
                        event = (MidiEvent)mEventScheduler.waitNextEvent();
                    } catch (InterruptedException e) {
                        // try again
                        continue;
                    }
                    if (event == null) {
                        break;
                    }
                    try {
                        mPacketEncoder.send(event.data, 0, event.count,
                                event.getTimestamp());
                    } catch (IOException e) {
                        Log.e(TAG, "mPacketAccumulator.send failed", e);
                    }
                    mEventScheduler.addEventToPool(event);
                }
                Log.d(TAG, "BluetoothMidiDevice thread exit");
            }
        }.start();
    }

    private void close() {
        synchronized (mBluetoothDevice) {
            mEventScheduler.close();
            mService.deviceClosed(mBluetoothDevice);

            if (mDeviceServer != null) {
                IoUtils.closeQuietly(mDeviceServer);
                mDeviceServer = null;
            }
            if (mBluetoothGatt != null) {
                mBluetoothGatt.close();
                mBluetoothGatt = null;
            }
        }
    }

    public IBinder getBinder() {
        return mDeviceServer.asBinder();
    }

    private static void logByteArray(String prefix, byte[] value, int offset, int count) {
        StringBuilder builder = new StringBuilder(prefix);
        for (int i = offset; i < count; i++) {
            builder.append(String.format("0x%02X", value[i]));
            if (i != value.length - 1) {
                builder.append(", ");
            }
        }
        Log.d(TAG, builder.toString());
    }
}
