#ifndef __JEVENT__
#define __JEVENT__

#include <vector>
#include <algorithm>

#include "JDAQ/JDAQChronometer.hh"
#include "JDAQ/JDAQTriggerMask.hh"
#include "JTrigger/JTriggeredHit.hh"
#include "JTrigger/JTriggerException.hh"


namespace JTRIGGER {

  namespace {
    using KM3NETDAQ::JDAQChronometer;
    using KM3NETDAQ::JDAQTriggerMask;
    using KM3NETDAQ::NUMBER_OF_TRIGGER_BITS;
    using KM3NETDAQ::getTriggerMask;
  }


  /**
   * Triggered event.
   */
  class JEvent :
    public JDAQChronometer,
    public JDAQTriggerMask,
    public std::vector<JTriggeredHit>
  {
  public:
    /**
     * Default constructor.
     */
    JEvent() :
      JDAQChronometer(),
      JDAQTriggerMask(),
      std::vector<JTriggeredHit>(),
      overlays(0)
    {}


    /**
     * Constructor.
     *
     * \param  chronometer    DAQ chronometer
     * \param  __begin        begin of hit list
     * \param  __end          end   of hit list
     * \param  bit            trigger bit
     */
    template<class T>
    JEvent(const JDAQChronometer& chronometer,
	   T                      __begin,
	   T                      __end,
	   const unsigned int     bit) :
      JDAQChronometer(chronometer),
      JDAQTriggerMask(KM3NETDAQ::getTriggerMask(bit)),
      std::vector<JTriggeredHit>(),
      overlays(0)
    {
      for (T i = __begin; i != __end; ++i)
	push_back(JTriggeredHit(i->getPMTIdentifier(),
				i->getHit(),
				this->getTriggerMask()));

      std::sort(this->begin(), this->end());
    }


    /**
     * Merge event.
     *
     * \param  event          event
     */
    void merge(const JEvent& event)
    {
      using namespace std;

      addTriggerMask(event.getTriggerMask());
      
      const_iterator __hit1 = this ->begin();
      const_iterator __end1 = this ->end();

      const_iterator __hit2 = event.begin();
      const_iterator __end2 = event.end();

      buffer.resize(this->size() + event.size());

      iterator out = buffer.begin();

      while (__hit1 != __end1 && __hit2 != __end2) {

	if        (*__hit1 < *__hit2) {

	  *out = *__hit1;
	  ++__hit1;

	} else if (*__hit2 < *__hit1) {

	  *out = *__hit2;
	  ++__hit2;
          
	} else {

	  *out  = *__hit1;
	  *out |= *__hit2;

	  ++__hit1;
	  ++__hit2;
	}

	++out;
      }

      out = copy(__hit1, __end1, out);
      out = copy(__hit2, __end2, out);

      buffer.resize(distance(buffer.begin(), out));

      this->swap(buffer);

      ++overlays;
    }


    /**
     * Get number of overlays.
     *
     * \return                number of overlays
     */
    unsigned int getOverlays() const 
    {
      return overlays;
    }


  protected:
    unsigned int    overlays;

  private:
    mutable std::vector<JTriggeredHit> buffer;
  };


  /**
   * Less than operator for events.
   *
   * \param  first          first  event
   * \param  second         second event
   * \return                true if first event earliear than second; else false
   */
  inline bool operator<(const JEvent& first, const JEvent& second)
  {
    if (first.empty() || second.empty())
      throw JTriggerException("Comparison with empty event(s).");

    return first.begin()->getT() < second.begin()->getT();
  }
}

#endif