/*
 * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
 *
 * This file is part of ZLToolKit(https://github.com/xia-chu/ZLToolKit).
 *
 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
 */

#ifndef ZLTOOLKIT_LIST_H
#define ZLTOOLKIT_LIST_H

#include <list>
#include <type_traits>
using namespace std;

namespace toolkit {

#if 0
template<typename T>
class List;

template<typename T>
class ListNode
{
public:
    friend class List<T>;
    ~ListNode(){}

    template <class... Args>
    ListNode(Args&&... args):_data(std::forward<Args>(args)...){}

private:
    T _data;
    ListNode *next = nullptr;
};


template<typename T>
class List {
public:
    typedef ListNode<T> NodeType;
    List(){}
    List(List &&that){
        swap(that);
    }
    ~List(){
        clear();
    }
    void clear(){
        auto ptr = _front;
        auto last = ptr;
        while(ptr){
            last = ptr;
            ptr = ptr->next;
            delete last;
        }
        _size = 0;
        _front = nullptr;
        _back = nullptr;
    }

    template<typename FUN>
    void for_each(FUN &&fun) const {
        auto ptr = _front;
        while (ptr) {
            fun(ptr->_data);
            ptr = ptr->next;
        }
    }

    size_t size() const{
        return _size;
    }

    bool empty() const{
        return _size == 0;
    }
    template <class... Args>
    void emplace_front(Args&&... args){
        NodeType *node = new NodeType(std::forward<Args>(args)...);
        if(!_front){
            _front = node;
            _back = node;
            _size = 1;
        }else{
            node->next = _front;
            _front = node;
            ++_size;
        }
    }

    template <class...Args>
    void emplace_back(Args&&... args){
        NodeType *node = new NodeType(std::forward<Args>(args)...);
        if(!_back){
            _back = node;
            _front = node;
            _size = 1;
        }else{
            _back->next = node;
            _back = node;
            ++_size;
        }
    }

    T &front() const{
        return _front->_data;
    }

    T &back() const{
        return _back->_data;
    }

    T &operator[](size_t pos){
        NodeType *front = _front ;
        while(pos--){
            front = front->next;
        }
        return front->_data;
    }

    void pop_front(){
        if(!_front){
            return;
        }
        auto ptr = _front;
        _front = _front->next;
        delete ptr;
        if(!_front){
            _back = nullptr;
        }
        --_size;
    }

    void swap(List &other){
        NodeType *tmp_node;

        tmp_node = _front;
        _front = other._front;
        other._front = tmp_node;

        tmp_node = _back;
        _back = other._back;
        other._back = tmp_node;

        size_t tmp_size = _size;
        _size = other._size;
        other._size = tmp_size;
    }

    void append(List<T> &other){
        if(other.empty()){
            return;
        }
        if(_back){
            _back->next = other._front;
            _back = other._back;
        }else{
            _front = other._front;
            _back = other._back;
        }
        _size += other._size;

        other._front = other._back = nullptr;
        other._size = 0;
    }

    List &operator=(const List &that) {
        that.for_each([&](const T &t) {
            emplace_back(t);
        });
        return *this;
    }

private:
    NodeType *_front = nullptr;
    NodeType *_back = nullptr;
    size_t _size = 0;
};

#else

template<typename T>
class List : public list<T> {
public:
    template<typename ... ARGS>
    List(ARGS &&...args) : list<T>(std::forward<ARGS>(args)...) {};

    ~List() = default;

    void append(List<T> &other) {
        if (other.empty()) {
            return;
        }
        this->insert(this->end(), other.begin(), other.end());
        other.clear();
    }

    template<typename FUNC>
    void for_each(FUNC &&func) {
        for (auto &t : *this) {
            func(t);
        }
    }

    template<typename FUNC>
    void for_each(FUNC &&func) const {
        for (auto &t : *this) {
            func(t);
        }
    }
};

#endif

} /* namespace toolkit */
#endif //ZLTOOLKIT_LIST_H