#include <vector>
#include <string>
#include <list>
#include <type_traits>
#include <iostream>
#include <iterator>

using T = std::string;
using VectT = std::vector<T>;
using ListT = std::list<VectT>;

using value_type = T;

class const_iterator :
    public std::iterator<std::bidirectional_iterator_tag , value_type const> {
public:
    using ListIt = typename ListT::const_iterator;
    using VectIt = typename VectT::const_iterator;

    explicit const_iterator(ListIt itHigh, VectIt itLow) :
        itHigh_{itHigh}, itLow_{itLow} {
    }
    
    const_iterator(const const_iterator &it) :
        itHigh_{it.itHigh_}, itLow_{it.itLow_} {
    }
    
    const_iterator & operator ++ () {
        std::cout << "increment" << std::endl;
        itLow_++;
        if (itLow_ == itHigh_->end()) {
            itHigh_++;
            itLow_ = itHigh_->begin();
        }
        
        return *this;
    }

    const_iterator operator ++ (int) {
        const_iterator retval = *this;

        ++(*this);

        return retval;
    }

    const_iterator & operator -- () {
        std::cout << "decrement" << std::endl;
        itLow_--;
        if (itLow_ == --itHigh_->begin()) {
            itHigh_--;
            itLow_ = --(itHigh_->end());
        }
        
        return *this;
    }

    const_iterator operator -- (int) {
        const_iterator retval = *this;

        --(*this);

        return retval;
    }

    bool operator == (const_iterator other) const {
        return other.itHigh_ == itHigh_&& other.itLow_ == itLow_;
    }

    bool operator != (const_iterator other) const {
        return !(other == *this);
    }

    const value_type & operator * () const {
        return *itLow_;
    }
        
    const value_type * operator -> () const {
        return &(operator *());
    }

private:
    ListIt itHigh_;
    VectIt itLow_;
};

int main() {
    std::cout 
        << std::is_same<typename std::iterator_traits<const_iterator>::value_type, std::string const>::value
        << std::endl;

    ListT items = {{"First", "Second"}, {"Third", "Fourth"}, {"Fifth", "Sixth", "Seventh"}};

    const_iterator it{items.begin(), items.begin()->begin()};
    
    const_iterator end{items.end(), items.end()->begin()};

    for (; it != end; it++) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
    
    const_reverse_iterator rit{const_iterator{(--items.end()), --items.rbegin()->rbegin().base()}};
    
    const_reverse_iterator rend{const_iterator{items.begin(), --items.rend()->end()}};
    
    /*for (; rit != rend; rit++) {
        std::cout << *rit << " ";
    }*/
    rit--;
    --rit;
    rit++;
    ++rit;
    std::cout << *rit << std::endl;
    *rit;
    *rit;
        
    std::cout << std::endl;
}
