#include "ListString.hpp"
#include <cassert>

using std::string;

struct ListString::Cell {
    Cell * m_prev;
    Cell * m_next;
    string     m_value;
    Cell(const string &Value = "UNINITIALIZED",
         Cell *prev = nullptr, Cell *next = nullptr);
    bool phantom() const { return (! m_next) || (! m_prev ); }
};

ListString::Cell::Cell(const string & value, Cell *prev, Cell *next )
    : m_prev{prev},
    m_next{next},
    m_value(value)
{
}

unsigned int ListString::size() const
{
    return m_size;
}

ListString::ListString()
    : m_size{0}
    , m_first{new Cell}
    , m_last{new Cell}
{
    m_first->m_next = m_last;
    m_last->m_prev  = m_first;
}

ListString::~ListString()
{
    for ( ListString::Position iter = begin() ;
         iter.valid();
         iter.inc() )
        delete iter.m_cell; //  fuite et use past free
}

void ListString::push_back(const std::string &value) {   
    m_last->m_prev = new Cell{value, m_last->m_prev, m_last};
    m_last->m_prev->m_prev->m_next = m_last->m_prev;
    ++m_size;
}

void ListString::insert(const Position & p, const std::string &value)
{
    Cell *before   = p.m_cell;
    Cell *neo      = new Cell(value, before, before->m_next);
    before->m_next->m_prev = neo;
    before->m_next = neo;
    ++m_size;
}


ListString::Position ListString::begin() const
{
    return Position{m_first->m_next};
}



std::ostream &operator<<(std::ostream &os, const ListString &list) {
    os << "[ ";
    for ( ListString::Cell * cell = list.m_first->m_next ;
          cell != list.m_last;
          cell = cell->m_next         )
        os << cell->m_value << ", " ;
    return os << "] ";
}

ListString::Position::Position(Cell *cell)
    : m_cell{cell}
{
}

void ListString::Position::inc()
{
    assert(m_cell->m_next);

    m_cell = m_cell->m_next;
}

bool ListString::Position::valid() const
{
    return ! m_cell->phantom();
}

const string &ListString::Position::value() const
{
    assert( valid() );

    return m_cell->m_value;
}

ListString::Position ListString::find(const std::string & value) const
{
    ListString::Position iter{begin()};
    for ( ;
          iter.valid() && iter.value() != value ;
          iter.inc() ) {
    }

    return iter;
}

void affiche(ListString liste) {
    for ( ListString::Position iter{liste.begin()};
         iter.valid() ;
         iter.inc() ) {
        std::cout << iter.value() << std::endl;
    }
}
