// bytran -|- spectral calculations for portable devices using the HITRAN database
//
// Developed by Dzianis Pliutau (Denis Plutov) and Kostya Roslyakov
// www.bytran.org | bytran@bytran.org
// Copyright (c) 2016 Dzianis Pliutau
// Distributed under the MIT license
//
// The MIT License (MIT)
// Copyright (c) 2016 Dzianis Pliutau
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.



// This class is used to display the list of available bluetooth devices
#include "bluetoothlistviewmodel.h"
#include <QMessageBox>
#include <QDebug>
#include <QApplication>

BluetoothListView::BluetoothListView(const QString &deviceName, const QString &color)
     : m_deviceName(deviceName), m_color(color)
{
}

QString BluetoothListView::deviceName() const
{
    return m_deviceName;
}
void BluetoothListView::setDeviceName(const QString &deviceName)
{
    if (deviceName != m_deviceName)
    {
        m_deviceName = deviceName;
    }
}

QString BluetoothListView::color() const
{ return m_color; }
void BluetoothListView::setColor(const QString &color)
{
    if (color != m_color)
    {
        m_color = color;
    }
}

BluetoothListViewModel::BluetoothListViewModel(QObject *parent, BluetoothDiscoverDevices *inBluetoothDiscoverDevices) : QAbstractListModel(parent)
{
    // Passing in the core module
    this->bluetoothDiscoverDevices = inBluetoothDiscoverDevices;
    this->informationStr = "Press \"Discover devices\" first.";
    this->m_activeIndex = 0;

    // Setting up connections
    connect(this->bluetoothDiscoverDevices, SIGNAL(deviceDiscoveryStarted()), this, SLOT(setDeviceDiscoveryStarted()));
    connect(this->bluetoothDiscoverDevices, SIGNAL(deviceDiscoveryFinished()), this, SLOT(setDeviceDiscoveryFinished()));
    connect(this->bluetoothDiscoverDevices, SIGNAL(connected()), this, SLOT(setDeviceConnected()));
    connect(this->bluetoothDiscoverDevices, SIGNAL(disconnected()), this, SLOT(setDeviceDisconnected()));

    // Updating displayed data
    populateList();
}

// Method to update the list of displayed molecules
void BluetoothListViewModel::populateList()
{
    int i;  // Loop variable
    QString deviceName;
    QString color;


    // Need to change the core module and then modify this population method
    removeAllElements();
    for (i = 0; i < this->bluetoothDiscoverDevices->getBluetoothDeviceDiscoveryAgent()->discoveredDevices().count(); i++)
    {
        deviceName = this->bluetoothDiscoverDevices->getBluetoothDeviceDiscoveryAgent()->discoveredDevices().at(i).name();
        if (deviceName == "") { deviceName = this->bluetoothDiscoverDevices->getBluetoothDeviceDiscoveryAgent()->discoveredDevices().at(i).address().toString(); }

        // Need to iterate through the list of connected devices to determine if this device is connected
        if (this->bluetoothDiscoverDevices->getConnectedDeviceIndex() == i)
        {
            deviceName = deviceName + " - Connected";
        }
        this->addElement(BluetoothListView(deviceName, color));
    }
    if (this->bluetoothDiscoverDevices->getBluetoothDeviceDiscoveryAgent()->discoveredDevices().count() == 0)
    {
        this->addElement(BluetoothListView(this->informationStr, color));
    }    
}

// Method to only update one item in the list
void BluetoothListViewModel::updateDisplayed()
{
    int i;  // Loop variable
    QString deviceName;


    // Need to change the core module and then modify this population method
    if (this->bluetoothDiscoverDevices->getBluetoothDeviceDiscoveryAgent()->discoveredDevices().count() > 0)
    {
        for (i = 0; i < m_devicesListView.count(); i++)
        {
            deviceName = this->bluetoothDiscoverDevices->getBluetoothDeviceDiscoveryAgent()->discoveredDevices().at(i).name();
            if (deviceName == "") { deviceName = this->bluetoothDiscoverDevices->getBluetoothDeviceDiscoveryAgent()->discoveredDevices().at(i).address().toString(); }

            // Need to iterate through the list of connected devices to determine if this device is connected
            // May not be the very best approach beause though unlikely the number of items on the list may be different that the number of discovered devices
            if (this->bluetoothDiscoverDevices->getConnectedDeviceIndex() == i)
            {
                deviceName = deviceName + " - Connected";
            }
            m_devicesListView[i].setDeviceName(deviceName);
        }
    }

    if (m_devicesListView.count() > 0)
    {
        // Emit data changed from here to update the list when this control is modified
        emit dataChanged(BluetoothListViewModel::index(0, 0, QModelIndex()), BluetoothListViewModel::index(m_devicesListView.count() - 1, 0, QModelIndex()));
    }
}

// Slot is called when the device discovery is started
void BluetoothListViewModel::setDeviceDiscoveryStarted()
{
    this->informationStr = "Scanning in progress...";
    populateList();    
}

// Slot is called when the device discovery has finished
void BluetoothListViewModel::setDeviceDiscoveryFinished()
{
    this->informationStr = "No bluetooth devices in range";
    populateList();
}

void BluetoothListViewModel::addElement(const BluetoothListView &bluetoothListView)
{
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    m_devicesListView << bluetoothListView;
    endInsertRows();
}

void BluetoothListViewModel::removeAllElements()
{
    beginRemoveRows(QModelIndex(), 0, rowCount());
    m_devicesListView.clear();
    endRemoveRows();
}

int BluetoothListViewModel::rowCount(const QModelIndex & parent) const {
    Q_UNUSED(parent);
    return m_devicesListView.count();
}

QVariant BluetoothListViewModel::data(const QModelIndex & index, int role) const {
    if ((index.row() < 0) || (index.row() >= m_devicesListView.count()))
        return QVariant();

    const BluetoothListView &devicesListView = m_devicesListView[index.row()];
    if (role == deviceNameRole)
    {
        return devicesListView.deviceName();
    }
    else if (role == colorRole)
        return devicesListView.color();
    return QVariant();
}

// Method to set the data when the values in the model are modified
bool BluetoothListViewModel::setData(const QModelIndex & index, const QVariant & value, int role)
{
    switch (role)
    {
        case colorRole:
            m_devicesListView[index.row()].setColor(value.toString());
            break;
    }
    emit dataChanged(index, index);
    return true;
}

//![0]
QHash<int, QByteArray> BluetoothListViewModel::roleNames() const {
    QHash<int, QByteArray> roles;
    roles[deviceNameRole] = "deviceName";
    roles[colorRole] = "color";
    return roles;
}
//![0]

// Slot to update the list of connected devices
void BluetoothListViewModel::setDeviceConnected() { updateDisplayed(); }
void BluetoothListViewModel::setDeviceDisconnected() { updateDisplayed(); }

// Need to update the model and synch data etc.
