/*
 * Copyright (C) 2018-2020 Western Digital Corporation or its affiliates
 * Copyright (C) 2017-2018 Wearable, Inc.
 * Copyright (C) 2000-2012 leJOS Contributors
 * Copyright (C) 2000 Jose H. Solorzano and TinyVM Contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 * 
 * This Source Code Form is “Incompatible With Secondary Licenses”,
 * as defined by the Mozilla Public License, v. 2.0.
 */

#include "constants.h"
#include "poll.h"
#include "threads.h"
#include "platform_hooks.h"


/**
 * Initialize the event system. At startup we are not monitoring for any events.
 */
void init_events(nvm_state_t* pState)
{
    int i;
    for(i = 0; i < MAX_EVENTS; i++) {
        pState->events[i] = NULL;
    }
    pState->shutdown_started = 0;
}

/**
 * register a new event object. After this the system will check for these
 * events, and notify the Java code if any fire.
 */
boolean register_event(nvm_state_t* pState, Object *event, JINT type)
{
    if (type >= MAX_EVENTS || pState->events[type] != NULL) {
        return false;
    }
    pState->events[type] = event;
    return true;
}

/**
 * remove an event object from being monitored. Following this the event will
 * no longer be checked by the system.
 */
boolean unregister_event(nvm_state_t* pState, JINT type)
{
    if (type >= MAX_EVENTS || pState->events[type] == NULL) {
        return false;
    }

    pState->events[type] = NULL;
    return true;
}

JINT poll_event(nvm_state_t* pState, JINT type)
{
    if (type == NVM_EVT_SHUTDOWN) {
        return pState->shutdown_started;
    } else {
        return platform_check_event(type);
    }
    return 0;
}

/**
 * Check all active event objects. If an event is detected, notify the
 * associated waiting Java thread.
 */
void check_events(nvm_state_t* pState)
{
    int i;
    
    for(i = 0; i < MAX_EVENTS; i++) {
        Object *event = pState->events[i];
        // Is this event being waited on, and has the event check period expired?
        if (event && get_monitor_count(&(event->sync)) == 0) {
            // Check to see if we have anything of interest
            JINT polled = poll_event(pState, i);
            if (polled) {
                if (monitor_notify_unchecked(pState, event, 1)) {
                    schedule_request(pState, REQUEST_SWITCH_THREAD);
                }
            }
        }
    }
}

// Called to shutdown the current program. If the program has
// shutdown hooks then these will be initiated; if not the
// program will be terminated.

void shutdown_program(nvm_state_t* pState)
{
    Object *event = pState->events[NVM_EVT_SHUTDOWN];
    if (event) {
        pState->shutdown_started = 1;
        return;
    }
    // no event registered so just shut things down...
    schedule_request(pState, REQUEST_EXIT);
}


