/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * This source file is part of the Cangjie project, licensed under Apache-2.0
 * with Runtime Library Exception.
 *
 * See https://cangjie-lang.cn/pages/LICENSE for license information.
 */

// The Cangjie API is in Beta. For details on its capabilities and limitations, please refer to the README file.

package std.sync

/**
 * Class that encapsulates single reentrant mutex and single condition instance (a.k.a. wait queue) associated with this mutex.
 */
@Deprecated[message: "Use `public interface Condition` instead."]
public class Monitor <: ReentrantMutex {
    public init() {
        var isNull = unsafe { monitorInit(this) }
        if (isNull) {
            throw IllegalSynchronizationStateException("Initialization failed.")
        }
    }

    init(mutex: Mutex) {
        super(mutex)
        let isNull = unsafe { monitorInit(this) }
        if (isNull) {
            throw IllegalSynchronizationStateException("Initialization failed.")
        }
    }

    /**
     * @brief Block until paired `notify` is invoked or `timeout` nanoseconds passed.
     * @return `true` if event was signalled by other thread;
     * @return `false` on timeout, otherwise.
     * @throws IllegalSynchronizationStateException if current thread does not hold this mutex
     * @throws IllegalArgumentException if `timeout <= Duration.Zero`
     */
    public func wait(timeout!: Duration = Duration.Max): Bool {
        checkMutexStatus()
        if (timeout <= Duration.Zero) {
            throw IllegalArgumentException("Timeout cannot be less than or equal to `Duration.Zero`.")
        }
        let timeoutNanos = if (timeout > MAX_TIMEOUT_DURATION) {
            MAX_TIMEOUT_NS
        } else {
            timeout.toNanoseconds()
        }
        return unsafe { monitorWait(this, timeoutNanos) }
    }

    /**
     * @brief Wake up a single thread waiting on this mutex (no particular admission policy implied).
     * @throws IllegalSynchronizationStateException if current thread does not hold this mutex
     */
    public func notify(): Unit {
        checkMutexStatus()
        unsafe { monitorNotify(this) }
    }

    /**
     * @brief Wake up all threads waiting on this mutex (no particular admission policy implied).
     * @throws IllegalSynchronizationStateException if current thread does not hold this mutex
     */
    public func notifyAll(): Unit {
        checkMutexStatus()
        unsafe { monitorNotifyAll(this) }
    }
}

/**
 * @brief Record represents unique identifier of an existing wait queue associated with given mutex.
 * Passing invalid ConditionID to the MultiConditionMonitor results into ISSE.
 */
@Deprecated[message: "Use `public interface Condition` instead."]
public struct ConditionID {
    init(m: MultiConditionMonitor, wqPtr: WaitQueue) {
        monitor = m
        waitQueue = wqPtr
    }

    let monitor: MultiConditionMonitor
    let waitQueue: WaitQueue
}

class WaitQueue {
    init() {
        var isNull = unsafe { waitQueueInit(this) }
        if (isNull) {
            throw IllegalSynchronizationStateException("Initialization failed.")
        }
    }
}
/**
 * @brief Class that encapsulates single reentrant mutex and a set of dynamically created condition instances associated with this mutex.
 */
@Deprecated[message: "Use `public class Mutex` instead."]
public class MultiConditionMonitor <: ReentrantMutex {
    public init() {}

    /**
     * @return A new ConditionID associated with this mutex. May be used to implement "single mutex -- multiple wait queues" concurrent primitives.
     * @throws IllegalSynchronizationStateException if current thread does not hold this mutex.
     */
    public func newCondition(): ConditionID {
        checkMutexStatus()
        let waitQueue = WaitQueue()
        return ConditionID(this, waitQueue)
    }

    /**
     * @brief Block until paired `notify` is invoked or `timeout` nanoseconds passed
     * @return `true` if specified condition was signalled by other thread;
     * @return `false` if timeouted.
     * @throws IllegalSynchronizationStateException if current thread does not hold this mutex
     * @throws IllegalSynchronizationStateException if `id` isn't provided by `newCondition` of this MultiConditionMonitor instance
     * @throws IllegalArgumentException if `timeout <= Duration.Zero`
     */
    public func wait(condID: ConditionID, timeout!: Duration = Duration.Max): Bool {
        if (!refEq(this, condID.monitor)) {
            throw IllegalSynchronizationStateException("Invalid condition.")
        }
        checkMutexStatus()
        if (timeout <= Duration.Zero) {
            throw IllegalArgumentException("Timeout cannot be less than or equal to `Duration.Zero`.")
        }
        let timeoutNanos = if (timeout > MAX_TIMEOUT_DURATION) {
            MAX_TIMEOUT_NS
        } else {
            timeout.toNanoseconds()
        }
        return unsafe { multiConditionMonitorWait(this, condID.waitQueue, timeoutNanos) }
    }

    /**
     * @brief Wake up a single thread waiting on this mutex (no particular admission policy implied)
     * @throws IllegalSynchronizationStateException if current thread does not hold this mutex
     * @throws IllegalSynchronizationStateException if `id` was not provided by `newCondition` of this MultiConditionMonitor instance
     */
    public func notify(condID: ConditionID): Unit {
        if (!refEq(this, condID.monitor)) {
            throw IllegalSynchronizationStateException("Invalid condition.")
        }
        checkMutexStatus()
        unsafe {
            multiConditionMonitorNotify(this, condID.waitQueue)
        }
    }

    /**
     * @brief Wake up all threads waiting on this mutex (no particular admission policy implied)
     * @throws IllegalSynchronizationStateException if current thread does not hold this mutex
     * @throws IllegalSynchronizationStateException if `id` was not provided by `newCondition` of this MultiConditionMonitor instance
     */
    public func notifyAll(condID: ConditionID): Unit {
        if (!refEq(this, condID.monitor)) {
            throw IllegalSynchronizationStateException("Invalid condition.")
        }
        checkMutexStatus()
        unsafe {
            multiConditionMonitorNotifyAll(this, condID.waitQueue)
        }
    }
}