#pragma once

#include <functional>

#include "OperatingSystem.h"

namespace Framework
{
    template<typename T> class Maybe
    {
    private:
        bool set;
        T value;

        Maybe()
        {
            set = 0;
        }

        Maybe(T value)
            : set(1),
              value(value) {};

    public:
        static Maybe<T> of(T value)
        {
            return Maybe(value);
        }

        static Maybe<T> empty()
        {
            return Maybe();
        }

        bool isEmpty() const
        {
            return !set;
        }

        bool isPresent() const
        {
            return set;
        }

        operator T() const
        {
            assert(set);
            return value;
        }

        void ifPresent(std::function<void(T)> action)
        {
            if (set) action(value);
        }

        void ifNotPresent(std::function<void(T)> action)
        {
            if (!set) action(value);
        }

        template<typename R> Maybe<R> map(std::function<R(T)> action)
        {
            if (set)
                return Maybe<R>::of(action(value));
            else
                return Maybe<R>::empty();
        }

        template<typename R> Maybe<R> flatMap(std::function<Maybe<R>(T)> action)
        {
            if (set)
                return action(value);
            else
                return Maybe<R>::empty();
        }

        T orElse(T elseValue)
        {
            if (set)
                return value;
            else
                return elseValue;
        }

        T operator->()
        {
            assert(set);
            return value;
        }
    };
} // namespace Framework