/*============================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

============================================================================*/

#include <usServiceEvent.h>

#include <usServiceProperties.h>

#include <stdexcept>

namespace us {

class ServiceEventData : public SharedData
{
public:

  ServiceEventData(const ServiceEvent::Type& type, const ServiceReferenceBase& reference)
    : type(type), reference(reference)
  {

  }

  ServiceEventData(const ServiceEventData& other)
    : SharedData(other), type(other.type), reference(other.reference)
  {

  }

  const ServiceEvent::Type type;
  const ServiceReferenceBase reference;

private:

  // purposely not implemented
  ServiceEventData& operator=(const ServiceEventData&);
};

ServiceEvent::ServiceEvent()
  : d(nullptr)
{

}

ServiceEvent::~ServiceEvent()
{

}

bool ServiceEvent::IsNull() const
{
  return !d;
}

ServiceEvent::ServiceEvent(Type type, const ServiceReferenceBase& reference)
  : d(new ServiceEventData(type, reference))
{

}

ServiceEvent::ServiceEvent(const ServiceEvent& other)
  : d(other.d)
{

}

ServiceEvent& ServiceEvent::operator=(const ServiceEvent& other)
{
  d = other.d;
  return *this;
}

ServiceReferenceU ServiceEvent::GetServiceReference() const
{
  if (!d) return ServiceReferenceU();
  return d->reference;
}

ServiceEvent::Type ServiceEvent::GetType() const
{
  if (!d) throw std::logic_error("ServiceEvent is null");
  return d->type;
}

std::ostream& operator<<(std::ostream& os, const ServiceEvent::Type& type)
{
  switch(type)
  {
  case ServiceEvent::MODIFIED:          return os << "MODIFIED";
  case ServiceEvent::MODIFIED_ENDMATCH: return os << "MODIFIED_ENDMATCH";
  case ServiceEvent::REGISTERED:        return os << "REGISTERED";
  case ServiceEvent::UNREGISTERING:     return os << "UNREGISTERING";

  default: return os << "unknown service event type (" << static_cast<int>(type) << ")";
  }
}

std::ostream& operator<<(std::ostream& os, const ServiceEvent& event)
{
  if (event.IsNull()) return os << "NONE";

  os << event.GetType();

  ServiceReferenceU sr = event.GetServiceReference();
  if (sr)
  {
    // Some events will not have a service reference
    long int sid = any_cast<long int>(sr.GetProperty(ServiceConstants::SERVICE_ID()));
    os << " " << sid;

    Any classes = sr.GetProperty(ServiceConstants::OBJECTCLASS());
    os << " objectClass=" << classes.ToString() << ")";
  }

  return os;
}

}
