/**
 * @file edge_imp.hpp
 *
 * CopyRight F. J. Madrid-Cuevas <fjmadrid@uco.es>
 *
 * Sólo se permite el uso de este código en la docencia de las asignaturas sobre
 * Estructuras de Datos de la Universidad de Córdoba.
 *
 * Está prohibido su uso para cualquier otro objetivo.
 */
#pragma once
#include <cassert>
#include <edge.hpp>
#include <vertex.hpp>
#include <graph.hpp>

template <class T>
bool Edge<T>::is_valid() const
{
    bool ret_v = (graph_ != nullptr && u_ < graph_->order() && v_ < graph_->order());
    assert(!ret_v || (graph_ != nullptr && u_ < graph_->order() && v_ < graph_->order()));
    return ret_v;
}

template <class T>
float Edge<T>::item() const
{
    assert(is_valid());
    return graph_->weight(u_, v_);
}

template <class T>
bool Edge<T>::has(size_t n_label) const
{
    assert(is_valid());
    return n_label == u_ || n_label == v_;
}

template <class T>
bool Edge<T>::has(const Vertex<T> &n) const
{
    assert(is_valid());
    return graph_->has(n) && (n.label() == u_ || n.label() == v_);
}

template <class T>
size_t Edge<T>::other(size_t n_label) const
{
    assert(is_valid());
    assert(has(n_label));
    return (n_label == u_) ? v_ : u_;
}

template <class T>
const_VertexIterator<T> Edge<T>::other(const const_VertexIterator<T> &n) const
{
    assert(is_valid());
    assert(has(n->label()));
    size_t other_label = (n->label() == u_) ? v_ : u_;
    return graph_->vertex(other_label);
}

template <class T>
VertexIterator<T> Edge<T>::other(const VertexIterator<T> &n)
{
    assert(is_valid());
    assert(has(n->label()));
    size_t other_label = (n->label() == u_) ? v_ : u_;
    return graph_->vertex(other_label);
}

template <class T>
const_VertexIterator<T> Edge<T>::first() const
{
    assert(is_valid());
    return graph_->vertex(u_);
}

template <class T>
VertexIterator<T> Edge<T>::first()
{
    assert(is_valid());
    return graph_->vertex(u_);
}

template <class T>
const_VertexIterator<T> Edge<T>::second() const
{
    assert(is_valid());
    return graph_->vertex(v_);
}

template <class T>
VertexIterator<T> Edge<T>::second()
{
    assert(is_valid());
    return graph_->vertex(v_);
}

template <class T>
void Edge<T>::set_item(float w)
{
    assert(is_valid());
    graph_->set_weight(u_, v_, w);
    assert(item() == w);
}

template <class T>
bool Edge<T>::operator==(const Edge<T> &other) const
{
    if (graph_ != other.graph_)
        return false;
    if (graph_->is_directed())
        return u_ == other.u_ && v_ == other.v_;
    else
        return (u_ == other.u_ && v_ == other.v_) ||
               (u_ == other.v_ && v_ == other.u_);
}

template <class T>
Edge<T>::Edge(size_t u, size_t v, WGraph<T> *graph)
{
    u_ = u;
    v_ = v;
    graph_ = graph;
    assert(!is_valid() || has(*graph->vertex(u)));
    assert(!is_valid() || has(*graph->vertex(v)));
    assert(!is_valid() || other(graph->vertex(u)) == graph->vertex(v));
    assert(!is_valid() || other(graph->vertex(v)) == graph->vertex(u));
    assert(!is_valid() || first() == graph->vertex(u));
    assert(!is_valid() || second() == graph->vertex(v));
    assert(!is_valid() || item() == graph->weight(u, v));
    assert(!is_valid() || (graph->is_directed() || item() == graph->weight(v, u)));
}
