// singly_linked_list.cpp

#include <cassert>
#include <iostream>
using namespace std;

class Node
{
    friend void print_list( Node const& head );
    Node* pnext;
public:
    int data;

    // Constructor taking initial value:
    Node( int value = 0 )
    : pnext( NULL ), data( value )
    {
    }

    // Copy constructor:
    Node( Node const& other )
        : pnext( NULL ), data( other.data )
    {
    }

    // Insert new node in front:
    void insert( Node* newNode )
    {
        newNode->pnext = pnext;
        pnext = newNode;
    }

    // Remove node in front:
    void remove_next()
    {
        if ( pnext == NULL ) return;
        Node* obsolete = pnext;
        this->pnext = obsolete->pnext;
        // Make node "single":
        obsolete->pnext = NULL;
    }

    // Remove other node in front:
    bool remove( Node* other )
    {
        Node* previous = this;
        Node* iter = pnext;
        while ( iter != other ) {
            if ( iter == NULL )
                return false;
            previous = iter;
            iter = iter->pnext;
        }
        previous->pnext = iter->pnext;
        // Make node "single" after successful removal:
        other->pnext = NULL;
        return true;
    }

    // Measure distance to other node:
    int distance( Node const* other ) const
    {
        int hops = 1;
        Node const* iter = pnext;
        while ( iter != other ) {
            if ( iter == NULL ) {
                // Don't count this last hop:
                return hops - 1;
            }
            iter = iter->pnext;
            ++hops;
        }
        return hops;
    }
    // Calculate number of nodes in the list:
    size_t size() const
    {
        return distance( NULL );
    }
};

// Print contents of the list:
void print_list( Node const& head )
{
    cout << '[' << head.size() << "] ";
    Node const* iter = &head;
    do {
        cout << iter->data << ' ';
        iter = iter->pnext;

    } while ( iter != NULL );
    cout << '\n';
}

// Main driver to test list functionality:
int main( )
{
    Node n12( 12 );
    Node n99( 99 );
    Node n37( 37 );

    assert( n12.distance( &n12 ) == 0 );

    n12.insert( &n99 );
    assert( n12.distance( &n99 ) == 1 );

    print_list( n12 ); // 12 99
    print_list( n99 ); // 99

    n99.insert( &n37 );
    assert( n12.distance( &n37 ) == 2 );

    print_list( n12 ); // 12 99 37
    print_list( n99 ); // 99 37
    print_list( n37 ); // 37

    Node single;
    bool result = n12.remove( &single );
    assert( result == false );

    n12.remove_next();
    print_list( n12 ); // 12 37

    n12.insert( &n99 );
    print_list( n12 ); // 12 99 37

    n12.remove( &n12 );
    print_list( n99 ); // 99 37

    n99.remove_next();
    print_list( n99 ); // 99

    n99.remove( &n99 );
    print_list( n99 ); // 99

    n37.insert( &n99 );
    n99.insert( &n12 );

    print_list( n37 ); // 37 99 12

    n37.remove_next();
    print_list( n99 ); // 99
    print_list( n37 ); // 37 12

    return 0;
}

