/*
 * Copyright 2018 Google, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include "systemc/core/event.hh"

#include <algorithm>
#include <cstring>
#include <utility>

#include "sim/core.hh"
#include "systemc/core/module.hh"
#include "systemc/core/scheduler.hh"
#include "systemc/ext/core/messages.hh"
#include "systemc/ext/core/sc_main.hh"
#include "systemc/ext/core/sc_module.hh"

namespace sc_gem5
{

Event::Event(sc_core::sc_event *_sc_event, bool internal) :
    Event(_sc_event, nullptr, internal)
{}

Event::Event(sc_core::sc_event *_sc_event, const char *_basename_cstr,
        bool internal) :
    _sc_event(_sc_event), _basename(_basename_cstr ? _basename_cstr : ""),
    _inHierarchy(!internal), delayedNotify([this]() { this->notify(); }),
    _triggeredStamp(~0ULL)
{
    if (_basename == "" && ::sc_core::sc_is_running())
        _basename = ::sc_core::sc_gen_unique_name("event");

    parent = internal ? nullptr : pickParentObj();

    if (internal) {
        _basename = globalNameGen.gen(_basename);
        _name = _basename;
    } else {
        std::string original_name = _basename;
        _basename = pickUniqueName(parent, _basename);

        if (parent) {
            Object *obj = Object::getFromScObject(parent);
            obj->addChildEvent(_sc_event);
        } else {
            topLevelEvents.emplace(topLevelEvents.end(), _sc_event);
        }

        std::string path = parent ? (std::string(parent->name()) + ".") : "";

        if (original_name != "" && _basename != original_name) {
            std::string message = path + original_name +
                ". Latter declaration will be renamed to " +
                path + _basename;
            SC_REPORT_WARNING(sc_core::SC_ID_INSTANCE_EXISTS_,
                    message.c_str());
        }

        _name = path + _basename;
    }

    allEvents.emplace(allEvents.end(), _sc_event);

    // Determine if we're in the hierarchy (created once initialization starts
    // means no).
}

Event::~Event()
{
    if (parent) {
        Object *obj = Object::getFromScObject(parent);
        obj->delChildEvent(_sc_event);
    } else if (inHierarchy()) {
        EventsIt it = find(topLevelEvents.begin(), topLevelEvents.end(),
                           _sc_event);
        assert(it != topLevelEvents.end());
        std::swap(*it, topLevelEvents.back());
        topLevelEvents.pop_back();
    }

    EventsIt it = findEvent(_name);
    std::swap(*it, allEvents.back());
    allEvents.pop_back();

    if (delayedNotify.scheduled())
        scheduler.deschedule(&delayedNotify);
}

const std::string &
Event::name() const
{
    return _name;
}

const std::string &
Event::basename() const
{
    return _basename;
}

bool
Event::inHierarchy() const
{
    return _inHierarchy;
}

sc_core::sc_object *
Event::getParentObject() const
{
    return parent;
}

void
Event::notify(StaticSensitivities &senses)
{
    for (auto s: senses)
        s->notify(this);
}

void
Event::notify(DynamicSensitivities &senses)
{
    int size = senses.size();
    int pos = 0;
    while (pos < size) {
        if (senses[pos]->notify(this))
            senses[pos] = senses[--size];
        else
            pos++;
    }
    senses.resize(size);
}

void
Event::notify()
{
    if (scheduler.inUpdate())
        SC_REPORT_ERROR(sc_core::SC_ID_IMMEDIATE_NOTIFICATION_, "");

    // An immediate notification overrides any pending delayed notification.
    if (delayedNotify.scheduled())
        scheduler.deschedule(&delayedNotify);

    _triggeredStamp = scheduler.changeStamp();
    notify(staticSenseMethod);
    notify(dynamicSenseMethod);
    notify(staticSenseThread);
    notify(dynamicSenseThread);
}

void
Event::notify(const sc_core::sc_time &t)
{
    if (delayedNotify.scheduled()) {
        if (scheduler.delayed(t) >= delayedNotify.when())
            return;

        scheduler.deschedule(&delayedNotify);
    }
    scheduler.schedule(&delayedNotify, t);
}

void
Event::notifyDelayed(const sc_core::sc_time &t)
{
    if (delayedNotify.scheduled())
        SC_REPORT_ERROR(sc_core::SC_ID_NOTIFY_DELAYED_, "");
    notify(t);
}

void
Event::cancel()
{
    if (delayedNotify.scheduled())
        scheduler.deschedule(&delayedNotify);
}

bool
Event::triggered() const
{
    return _triggeredStamp == scheduler.changeStamp();
}

void
Event::clearParent()
{
    if (!parent)
        return;
    Object::getFromScObject(parent)->delChildEvent(sc_event());
    parent = nullptr;
    topLevelEvents.emplace(topLevelEvents.end(), sc_event());
}

Events topLevelEvents;
Events allEvents;

EventsIt
findEvent(const std::string &name)
{
    EventsIt it;
    for (it = allEvents.begin(); it != allEvents.end(); it++)
        if (!strcmp((*it)->name(), name.c_str()))
            break;

    return it;
}

} // namespace sc_gem5
