/******************************************************************************
    Copyright (c) 1998-2000 CoWare, Inc.    ALL RIGHTS RESERVED

The following code is derived, directly or indirectly, from the SystemC
source code released by Synopsys, Inc Copyright (c) 1996-2001, Synopsys,
Inc., CoWare, Inc., Frontier Design, Inc. and others. All Rights reserved.
The contents of this file are subject to the restrictions and limitations
set forth in the SystemC Open Source License Version 2.0 (the "License");
You may not use this file except in compliance with such restrictions and
limitations. You may obtain instructions on how to receive a copy of the
License at http://www.systemc.org/.  Software distributed by Contributors
under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
ANY KIND, either express or implied. See the License for the specific
language governing rights and limitations under the License."

******************************************************************************/

/****************************************************************

    Authors : Harish Sarin, CoWare Inc. (harish@coware.com)
	    : Cesar Quiroz, CoWare Inc. (cesar@coware.com)
            : Vijay Kumar,  CoWare Inc. (vijay@coware.com)
            : Dirk Vermeersch,  CoWare Inc. (dirk@coware.com)

    MODIFICATION LOG 
    Modifier Name & Affiliation:
    Description of Modification:

****************************************************************/
#ifndef SC_EVENT_H
#define SC_EVENT_H



#include "sc_logic.h"
#include "sc_object.h"
#include "sc_simcontext.h"
#include "sc_vector.h"
#include "sc_trace.h"
#include "sc_module_prm.h"
#include "numeric_bit/sc_nbdefs.h"
#include "sc_time.h"


class sc_time;
class sc_event;
class sc_eventlist;
struct sc_event_schedule_info;

class sc_event {
  friend class sc_eventlist;
  friend struct sc_event_schedule_info;
  friend class sc_simcontext;

  friend void wait(sc_eventlist &el,sc_simcontext* simc);
  friend void wait(const sc_time &t,sc_simcontext* simc);
  friend void wait(const sc_time &t,sc_eventlist &el,sc_simcontext* simc);
  friend void wait(sc_event &e,sc_simcontext* simc);
  friend void wait(const sc_time &t,sc_event &e,sc_simcontext* simc);

  friend class sc_aproc_process;
 // no public copy constructor
  sc_event(const sc_event &);
  sc_event & operator=(const sc_event &);
  sc_pvector<sc_async_process_handle> sensitive_asyncs; // can only be statis
  sc_pvector<sc_aproc_process_handle> sensitive_aprocs_dynamic;
  sc_pvector<sc_aproc_process_handle> sensitive_aprocs_static;
  void schedule();
  bool notified;
  sc_event_schedule_info * scheduleInfo;
  void receive() const;

  //uint64 getScheduledTime() const;
  sc_time getScheduledTime() const;
  void sensitive( sc_async_process_handle h)  {
    sensitive_asyncs.push_back(h);
  }
  void sensitive_dynamic( sc_aproc_process_handle h) {
    sensitive_aprocs_dynamic.push_back(h);
  }
  void remove_dynamic( sc_aproc_process_handle h) {
    // slow !!
    int s,j;
    s = sensitive_aprocs_dynamic.size();
    sc_aproc_process_handle* const l_sensitive_aprocs = sensitive_aprocs_dynamic.raw_data();
    for (j=0;j<s;j++) {
      sc_aproc_process_handle aproc = l_sensitive_aprocs[j];
      if (aproc == h) {
	l_sensitive_aprocs[j] = NULL;
	break;
      } 
    } while (--j >= 0);

  }
  void sensitive( sc_aproc_process_handle h)  {
    sensitive_aprocs_static.push_back(h);
  }


public:
  sc_event() {
     notified = false;
     scheduleInfo = NULL;
  };

  ~sc_event();

  void notify(const sc_time & d) {
    if (! notified) {
      sc_get_curr_simcontext()->submit_update(this,d);
      notified=true;
    }
  }
  void notify(double  d) {
    notify(sc_time(d));
  }
};


class sc_eventlist {
  friend class sc_module;
protected:
  bool auto_delete;
  bool or_list;
 public:
  sc_plist<sc_event*> the_events;
  sc_eventlist( const sc_event & e,bool o, bool delete_on_remove = false) {
    the_events.push_back((sc_event *)&e); // casting const away
    auto_delete = delete_on_remove;
    or_list = o;
  }
  void sensitive_dynamic( sc_aproc_process_handle h) {
    sc_plist_iter<sc_event*> iter(the_events);
    while (!iter.empty()) {
      (*iter)->sensitive_dynamic(h);
      iter++;
    }
  }
  void remove_dynamic( sc_aproc_process_handle h) {
    sc_plist_iter<sc_event*> iter(the_events);
    while (!iter.empty()) {
      (*iter)->remove_dynamic(h);
      iter++;
    }
    if (auto_delete)
      delete this;
  }
  bool isOr() {
    return or_list;
  }
  unsigned size() {
    return the_events.size();
  }
};

class sc_and_eventlist: public sc_eventlist {
public:
  sc_and_eventlist(const sc_event & e,bool delete_on_remove = false) : sc_eventlist(e,false,delete_on_remove) {}
};
class sc_or_eventlist: public sc_eventlist {
public:
  sc_or_eventlist(const sc_event & e,bool delete_on_remove = false) : sc_eventlist(e,true,delete_on_remove) {}
};

inline
sc_or_eventlist& operator | (sc_or_eventlist& el,const sc_event &e) {
  el.the_events.push_back((sc_event *)&e);  
  return el;
};

inline
sc_or_eventlist& operator | (const sc_event& e1,const sc_event &e2) {
  sc_or_eventlist *el = new sc_or_eventlist(e1,true);
  el->the_events.push_back((sc_event *)&e2);  
  return *el;
};

inline
sc_and_eventlist& operator & (sc_and_eventlist& el,const sc_event &e) {
  el.the_events.push_back((sc_event *)&e);  
  return el;
};

inline
sc_and_eventlist& operator & (const sc_event& e1,const sc_event &e2) {
  sc_and_eventlist *el = new sc_and_eventlist(e1,true);
  el->the_events.push_back((sc_event *)&e2);  
  return *el;
};

struct sc_event_schedule_info {
//  uint64 scheduledTime;
    sc_time scheduledTime;
    sc_event *event; // backpointer
//  sc_event_schedule_info(sc_event *e,uint64 t) {
    sc_event_schedule_info(sc_event *e,sc_time t) {
    event = e;
    e->scheduleInfo = this;
    scheduledTime = t;

  }
}; 

inline 
//uint64 sc_event::getScheduledTime() const {
//  return scheduleInfo ? scheduleInfo->scheduledTime:(uint64)sc_time_stamp();
sc_time sc_event::getScheduledTime() const {
  return scheduleInfo ? scheduleInfo->scheduledTime:(sc_time)sc_time_stamp();
}

#endif
