// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#pragma once

#include <threads.h>

#include <ddk/debug.h>
#include <ddktl/protocol/hidbus.h>
#include <fbl/auto_lock.h>
#include <fbl/mutex.h>
#include <lib/fit/function.h>
#include <lib/zx/port.h>
#include <zircon/syscalls/port.h>
#include <zircon/syscalls/types.h>
#include <zircon/thread_annotations.h>
#include <zircon/threads.h>

namespace simplehid {

// Helper class for a "simple" HID that only supports polling. This class implements HidbusStart and
// HidbusStop, and manages the hidbus IO queue for the user. Users pass in a callback to get input
// reports and forward calls to HidbusStart and HidbusStop to an instance of this class.
// GetReportInterval and SetReportInterval can be called by the user to get or set the polling
// interval.

template <typename InputReportType>
class SimpleHid {
public:
    SimpleHid() : interval_ms_(0) {}

    SimpleHid(zx::port port, fit::function<zx_status_t(InputReportType*)> get_input_report)
        : port_(std::move(port)), interval_ms_(0), get_input_report_(std::move(get_input_report)) {}

    SimpleHid& operator=(SimpleHid&& other) {
        port_ = std::move(other.port_);
        get_input_report_ = std::move(other.get_input_report_);

        fbl::AutoLock lock1(&interval_lock_);
        fbl::AutoLock lock2(&other.interval_lock_);
        interval_ms_ = other.interval_ms_;
        return *this;
    }

    zx_status_t HidbusStart(const hidbus_ifc_protocol_t* ifc) {
        {
            fbl::AutoLock lock(&client_lock_);

            if (client_.is_valid()) {
                return ZX_ERR_ALREADY_BOUND;
            }

            client_ = ddk::HidbusIfcProtocolClient(ifc);
        }

        return thrd_status_to_zx_status(thrd_create_with_name(
            &thread_,
            [](void* arg) -> int {
                return reinterpret_cast<SimpleHid*>(arg)->Thread();
            },
            this,
            "simplehid-thread"));
    }

    void HidbusStop() {
        zx_port_packet_t packet = {kPacketKeyStop, ZX_PKT_TYPE_USER, ZX_OK, {}};
        if (port_.queue(&packet) != ZX_OK) {
            zxlogf(ERROR, "%s: Failed to queue packet\n", __FILE__);
        }

        thrd_join(thread_, nullptr);

        fbl::AutoLock lock(&client_lock_);
        client_.clear();
    }

    zx_status_t SetReportInterval(uint32_t interval_ms) {
        {
            fbl::AutoLock lock(&interval_lock_);
            interval_ms_ = interval_ms;
        }

        zx_port_packet packet = {kPacketKeyConfigure, ZX_PKT_TYPE_USER, ZX_OK, {}};
        zx_status_t status = port_.queue(&packet);
        if (status != ZX_OK) {
            zxlogf(ERROR, "%s: Failed to queue packet\n", __FILE__);
        }

        return status;
    }

    uint32_t GetReportInterval() {
        fbl::AutoLock lock(&interval_lock_);
        return interval_ms_;
    }

private:
    enum PacketKeys {
        kPacketKeyPoll,
        kPacketKeyStop,
        kPacketKeyConfigure,
    };

    int Thread() {
        zx::time deadline = zx::time::infinite();

        while (1) {
            zx_port_packet_t packet;
            zx_status_t status = port_.wait(deadline, &packet);
            if (status != ZX_OK && status != ZX_ERR_TIMED_OUT) {
                return thrd_error;
            }

            if (status == ZX_ERR_TIMED_OUT) {
                packet.key = kPacketKeyPoll;
            }

            switch (packet.key) {
            case kPacketKeyStop:
                return thrd_success;

            case kPacketKeyPoll: {
                InputReportType report;
                if (get_input_report_(&report) == ZX_OK) {
                    fbl::AutoLock lock(&client_lock_);
                    if (client_.is_valid()) {
                        client_.IoQueue(&report, sizeof(report));
                    }
                }

                __FALLTHROUGH;
            }

            case kPacketKeyConfigure:
                fbl::AutoLock lock(&interval_lock_);
                if (interval_ms_ == 0) {
                    deadline = zx::time::infinite();
                } else {
                    deadline = zx::deadline_after(zx::msec(interval_ms_));
                }
            }
        }

        return thrd_success;
    }

    fbl::Mutex client_lock_;
    fbl::Mutex interval_lock_;

    zx::port port_;
    ddk::HidbusIfcProtocolClient client_ TA_GUARDED(client_lock_);
    thrd_t thread_;
    uint32_t interval_ms_ TA_GUARDED(interval_lock_);

    fit::function<zx_status_t(InputReportType*)> get_input_report_;
};

}  // namespace simplehid
