#ifndef OPSTREAM_H
#define OPSTREAM_H

#include <QList>
#include <functional>

namespace Operate {

    template<class ValueType, class TargetType>
    class Result
    {
    public:
        Result(QList<ValueType> source, std::function<bool(const ValueType&)> list_filter, std::function<TargetType(const ValueType&)> list_peaks)
            : source_store(source), peak_store(list_peaks), filter_store(list_filter){}
        virtual ~Result() = default;

        virtual QList<TargetType> toList()
        {
            QList<TargetType> rets_list;

            for(auto &it : source_store)
                if(filter_store(it))
                    rets_list << peak_store(it);

            return rets_list;
        }

        template<class Key>
        QHash<Key, TargetType> toMap(std::function<Key(ValueType)> key_selector)
        {
            QHash<Key, TargetType> map;

            for(auto &it : source_store)
                if(filter_store(it))
                    map[key_selector(it)] = peak_store(it);

            return map;
        }

        virtual void forEach(std::function<void(TargetType)> ex_proc)
        {
            auto items = toList();
            for(auto &it : items)
                ex_proc(it);
        }

        Result<ValueType, TargetType> filter(std::function<bool(const ValueType&)> filter){
            auto filter_combine = [filter, this](const ValueType& it){ return filter(it) && filter_store(it); };
            return Result<ValueType, TargetType>(source_store, filter_combine, peak_store);
        }

        template<class TargetTypeOut>
        Result<TargetType, TargetTypeOut> select(std::function<TargetTypeOut(const TargetType&)> peak){
            auto peak_combine = [peak, this](const TargetType &it){
                auto temp = this->peak_store(it);
                return peak(temp);
            };
            return Result<TargetType, TargetTypeOut>(source_store, filter_store, peak_combine);
        }


    private:
        QList<ValueType> source_store;
        std::function<TargetType(const ValueType&)> peak_store;
        std::function<bool(const ValueType&)> filter_store;
    };


    template<class ValueType>
    class OpStream
    {
    public:
        OpStream(std::function<ValueType(int &cnt, int idx)> peak_proc)
        {
            int count = 0;
            peak_proc(count, -1);

            for(int index = 0; index < count; ++index)
                source_store << peak_proc(count, index);
        }
        OpStream(QList<ValueType> source)
            : source_store(source){}

        template<class TargetType>
        Result<ValueType, TargetType> select(std::function<TargetType(const ValueType&)> value_selector)
        {
            return Result<ValueType, TargetType>(source_store, [](const ValueType& it){return true;}, value_selector);
        }
        Result<ValueType, ValueType> select()
        {
            return Result<ValueType, ValueType>(source_store, [](const ValueType& it){return true;}, [](const ValueType& it){return it;});
        }

        Result<ValueType, ValueType> filter(std::function<bool(const ValueType&)> filter)
        {
            return Result<ValueType, ValueType>(source_store, filter, [](const ValueType& it){ return it; });
        }

    private:
        QList<ValueType> source_store;
    };

}

#endif // OPSTREAM_H
