/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
 * -*- coding: utf-8 -*-
 *
 * Copyright (C) 2022 KylinSoft Co., Ltd.
 *
 * This program 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
 * any later version.
 *
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors: sundagao <sundagao@kylinos.cn>
 */
#include "input-device-manager.h"
#include "input-device-helper.h"
#include "input-device-function.h"
#define TEST_PRINT
using namespace InputDeviceHelper;

extern const DeviceFunctionMap deviceFuncMap;

InputDeviceManager::InputDeviceManager(QObject *parent) : QObject(parent)
{
    m_timer = new QTimer(this);
}

InputDeviceManager::~InputDeviceManager()
{
    disconnectAll();
    clearUpDeviceList();
}

void InputDeviceManager::start()
{
    connect(m_timer, &QTimer::timeout, this, &InputDeviceManager::managerStart);
    m_timer->start();
}

void InputDeviceManager::stop()
{
    disconnectAll();
    clearUpDeviceList();
}

bool InputDeviceManager::initDeviceFactor()
{
    //初始化设备factor,获取设备列表
    m_deviceFactor = InputDeviceFactorManager::createDeviceFactor(this);
    if (!m_deviceFactor) {
        return false;
    }
    m_deviceFactor->initInputDevices();
    return true;
}

void InputDeviceManager::eliminateSpecialDevice()
{
    for (InputDevice *touchpad : m_touchpadList) {
        QVariant touchProduct = touchpad->getProductId();
        USD_LOG(LOG_DEBUG,"touchProduct : %d", touchProduct.toInt());
        for (InputDevice* mouse : m_mouseList) {
            QVariant mouseProduct = mouse->getProductId();
            USD_LOG(LOG_DEBUG,"mouseProduct : %d", mouseProduct.toInt());
            if (touchProduct == mouseProduct) {
                m_mouseList.removeAll(mouse);
            }
        }
    }
}

//清空设备列表
void InputDeviceManager::clearUpDeviceList()
{
    qDeleteAll(m_mouseList);
    m_mouseList.clear();
    qDeleteAll(m_touchpadList);
    m_touchpadList.clear();
}

void InputDeviceManager::connctGsettings()
{
    //gsettings 改变
    connect(m_inputGsettings,&InputGsettings::mouseChanged,this,&InputDeviceManager::onMouseChanged);
    connect(m_inputGsettings,&InputGsettings::touchpadChanged,this,&InputDeviceManager::onTouchpadChanged);

}

void InputDeviceManager::disconnectAll()
{
    //断开监听
    disconnect(m_inputGsettings,&InputGsettings::mouseChanged,this,&InputDeviceManager::onMouseChanged);
    disconnect(m_inputGsettings,&InputGsettings::touchpadChanged,this,&InputDeviceManager::onTouchpadChanged);
}

void InputDeviceManager::classifyDevice(InputDevice *device)
{
    DeviceType type = device->getDeviceType();
    switch (type) {
    case DeviceType::IN_MOUSE:
        m_mouseList.append(device);
        break;
    case DeviceType::IN_TOUCHPAD:
        m_touchpadList.append(device);
        break;
    case DeviceType::IN_TOUCHSCREEN:
        /*
         *
         *
         */
        break;
    default:
        break;
    }
}

bool InputDeviceManager::deleteDevice(QVariant deviceId)
{
    for (InputDevice* device : m_mouseList) {
        if (deviceId == device->getDeviceId()) {
            m_mouseList.removeOne(device);
            return true;
        }
    }
    for (InputDevice* device : m_touchpadList) {
        if (deviceId == device->getDeviceId()) {
            m_touchpadList.removeOne(device);
            return true;
        }
    }
    return false;
}

bool InputDeviceManager::existMouse()
{
    return m_mouseList.count();
}

void InputDeviceManager::testPrintDeviceList()
{
    for (InputDevice* device : m_mouseList) {
        USD_LOG(LOG_DEBUG,"mouse device name : %s - device id %s",device->getDeviceName().toLatin1().data(),device->getDeviceId().toString().toLatin1().data());
    }
    for (InputDevice* device : m_touchpadList) {
        USD_LOG(LOG_DEBUG,"touchpad device name : %s - device id %s",device->getDeviceName().toLatin1().data(),device->getDeviceId().toString().toLatin1().data());
    }
}

#define device_function(list, key, value) \
    auto func = deviceFuncMap.value(key); \
    if (func) { \
        for (InputDevice* device : list) { \
            func(value, device); \
        } \
    }

#define disable_touchpad_on_external_mouse(prama) \
    for (InputDevice* device : m_touchpadList) {\
        device->setDisableTpMoPresent(prama); \
    }

void InputDeviceManager::disbleTouchpadMousePresent()
{
    disable_touchpad_on_external_mouse(QVariant(existMouse()));
}

void InputDeviceManager::onMouseChanged(const QString& key, QVariant value)
{
    USD_LOG(LOG_DEBUG,"mouse property %s is changed",key.toLatin1().data());
    if (key == QStringLiteral(KEY_MOUSE_LOCATE_POINTER)) {
        InputDeviceFunction::setLocatePointer(value);
    } else {
        device_function(m_mouseList, key, value);
    }
}

void InputDeviceManager::onTouchpadChanged(const QString &key, QVariant value)
{
    USD_LOG(LOG_DEBUG,"touchpad property %s is changed",key.toLatin1().data());
    if (key == QStringLiteral(KEY_TOUCHPAD_DISBLE_O_E_MOUSE)) { // 插入鼠标禁用触摸板
        disable_touchpad_on_external_mouse(QVariant(existMouse()));
    } else {
        device_function(m_touchpadList, key, value);
    }
}

//slots
void InputDeviceManager::deviceAdd(InputDevice* device)
{
    classifyDevice(device);
    eliminateSpecialDevice();
    disbleTouchpadMousePresent();
#ifdef TEST_PRINT
    testPrintDeviceList();
#endif
}

void InputDeviceManager::deviceRemove(QVariant deviceId)
{
    deleteDevice(deviceId);
    disbleTouchpadMousePresent();
#ifdef TEST_PRINT
    testPrintDeviceList();
#endif
}

void InputDeviceManager::managerStart()
{
    m_timer->stop();
    m_inputGsettings = InputGsettings::instance();
    m_inputGsettings->initGsettings();
    //gsettings init failed
    if (!m_inputGsettings->resultInitGsettings()) {
        USD_LOG(LOG_WARNING,"input gsettings init failed .");
        return;
    }
    //初始化设备工场
    if (!initDeviceFactor()) {
        USD_LOG(LOG_WARNING,"init device factor failed .");
        return;
    }
    //剔除与触摸板Product ID 一致的mouse设备
    eliminateSpecialDevice();
    //gsettings 改变
    connctGsettings();

    disbleTouchpadMousePresent();

#ifdef TEST_PRINT
    testPrintDeviceList();
#endif
}
