/**----------------------------------------------------------*
 * ZAD3                                                      *
 *                                                           *
 * problem: cykliczna lista jednokierunkowa                  *
 * (uzyto samych slabych wskaznikow - wiec gubil elementy)   *
 *                                                           *
 * rozwiazanie: wykorzystanie silnych sprytnych wskaznikow   *
 *              oraz ręczne rozerwanie zależności            *
 *-----------------------------------------------------------*/

#include <memory>
#include <vector>
#include <iostream>

using namespace std;

class List {
    struct Node;
    using PNode = std::shared_ptr<Node>;
    using PWNode = std::weak_ptr<Node>;
    struct Node {
        Node(int v) : value_(v) { cout << "C-tor " << value_ << endl; }
        ~Node() { cout << "D-tor " << value_ << endl; }
        int value_;

        PWNode me_; //wskaznik na ten sam wezel
        PWNode next_; //element nastepny
    };

public:
    List() {}
    ~List() {}

    void push_front(int value) {
        PNode node( new Node(value) );
        node->me_ = node;
        if( head_ ) { //not empty list
            node->next_ = head_;
            tail_->next_ = node;
        } else { //if empty list
            node->next_ = node;
            tail_ = node;
        }
        head_ = node;
    }
    void debug() {
        PNode x = head_;
        do {
            if(x) {
                cout << x->value_ << ", ";
                x = x->next_.lock();
            }
        } while (x && x != head_);
        cout << endl;
    }
private:
    PNode head_, tail_;
};


class ListBetter {
    struct Node;
    using PNode = std::shared_ptr<Node>;
    using PWNode = std::weak_ptr<Node>;

    struct Node {
        Node(int v) : value_(v) { cout << "C-tor " << value_ << endl; }
        ~Node() { cout << "D-tor " << value_ << endl; }
        int value_;

        PWNode me_;
        PNode next_; //zmiana na silny sprytny wskaznik
    };
public:
    ListBetter() {}
    ~ListBetter() {
        //wymagane usuniecie zaleznosci cyklicznej
        if( tail_ ) tail_->next_.reset();
    }

    void push_front(int value) {
        PNode node( new Node(value) );
        node->me_ = node;
        if( head_ ) { //not empty list
            node->next_ = head_;
            tail_->next_ = node;
        } else { //if empty list
            node->next_ = node;
            tail_ = node;
        }
        head_ = node;
    }
    void debug() {
        PNode x = head_;
        do {
            if(x) {
                cout << x->value_ << ", ";
                x = x->next_;
            }
        } while (x && x != head_);
        cout << endl;
    }
private:
    PNode head_, tail_;
};


int main() {
    {
        List l1;
        l1.debug();
        l1.push_front(1);
        l1.push_front(2);
        l1.push_front(3);
        l1.debug();
    }
    {
        ListBetter l2;
        l2.debug();
        l2.push_front(11);
        l2.push_front(22);
        l2.push_front(33);
        l2.debug();
    }
    return 0;
}
