// CapacityEdge.hpp
//
//     Created on: 28. 03. 2018
//         Author: Jan Uhlik
//    Modified by:
//
// Copyright (c) 2017 Czech Technical University in Prague | Faculty of Information Technology. All rights reserved.
// Git repository: https://gitlab.fit.cvut.cz/algorithms-library-toolkit/automata-library

#ifndef ALIB2_CAPACITYEDGE_HPP
#define ALIB2_CAPACITYEDGE_HPP

#include <ostream>
#include <alib/pair>
#include <object/Object.h>
#include <alib/tuple>

#include <edge/EdgeFeatures.hpp>
#include <edge/EdgeBase.hpp>

namespace edge {

template<typename TNode, typename TCapacity>
class CapacityEdge : public ext::pair<TNode, TNode>, public EdgeBase {
// ---------------------------------------------------------------------------------------------------------------------
 public:
  using node_type = TNode;
  using capacity_type = TCapacity;
  using normalized_type = WeightedEdge<>;

// ---------------------------------------------------------------------------------------------------------------------

 protected:
  TCapacity m_capacity;

// =====================================================================================================================
// Constructor, Destructor, Operators

 public:
  explicit CapacityEdge(TNode _first, TNode _second, TCapacity capacity);

// ---------------------------------------------------------------------------------------------------------------------

  TCapacity capacity() const;
  void capacity(TCapacity &&capacity);

// =====================================================================================================================
// EdgeBase interface

 public:
  int compare(const EdgeBase &other) const override;

  virtual int compare(const CapacityEdge &other) const;

  void operator>>(std::ostream &ostream) const override;

  explicit operator std::string() const override;

// =====================================================================================================================
 public:

  virtual std::string name() const;

// ---------------------------------------------------------------------------------------------------------------------
};
// =====================================================================================================================

template<typename TNode, typename TCapacity>
CapacityEdge<TNode, TCapacity>::CapacityEdge(TNode _first, TNode _second, TCapacity capacity)
    : ext::pair<TNode, TNode>(_first, _second), m_capacity(capacity) {

}

// ---------------------------------------------------------------------------------------------------------------------

template<typename TNode, typename TCapacity>
TCapacity CapacityEdge<TNode, TCapacity>::capacity() const {
  return m_capacity;
}

template<typename TNode, typename TCapacity>
void CapacityEdge<TNode, TCapacity>::capacity(TCapacity &&capacity) {
  m_capacity = std::forward<TCapacity>(capacity);
}

// ---------------------------------------------------------------------------------------------------------------------

template<typename TNode, typename TCapacity>
std::string CapacityEdge<TNode, TCapacity>::name() const {
  return "CapacityEdge";
}

// ---------------------------------------------------------------------------------------------------------------------

template<typename TNode, typename TCapacity>
int CapacityEdge<TNode, TCapacity>::compare(const EdgeBase &other) const {
  if (ext::type_index(typeid(*this)) == ext::type_index(typeid(other))) return this->compare((decltype(*this)) other);
  return ext::type_index(typeid(*this)) - ext::type_index(typeid(other));
}

template<typename TNode, typename TCapacity>
int CapacityEdge<TNode, TCapacity>::compare(const CapacityEdge &other) const {
  auto one = ext::tie(this->first, this->second, m_capacity);
  auto two = ext::tie(other.first, other.second, other.m_capacity);

  static ext::compare<decltype(one)> comp;

  return comp(one, two);
}

template<typename TNode, typename TCapacity>
void CapacityEdge<TNode, TCapacity>::operator>>(std::ostream &ostream) const {
  ostream << "(" << name() << "(first=" << this->first << ", second=" << this->second << ", weight="
          << m_capacity << "))";
}

template<typename TNode, typename TCapacity>
CapacityEdge<TNode, TCapacity>::operator std::string() const {
  std::stringstream ss;
  ss << "(" << name() << "(first=" << this->first << ", second=" << this->second << ", weight="
     << m_capacity << "))";
  return std::move(ss).str();
}

// ---------------------------------------------------------------------------------------------------------------------

} // namespace edge

// =====================================================================================================================


#endif //ALIB2_CAPACITYEDGE_HPP
