//                    (C) 2016 SiLeader.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)
#pragma once

#include <developer_settings.hpp>
#include <cstddef>

namespace STD
{
    template<class T, STD::size_t N> class array
    {
    private:
        T m_buf[N];
    public:
        using value_type=T;
        using size_type=STD::size_t;
        using difference_type=STD::ptrdiff_t;

        using reference=value_type&;
        using const_reference=const value_type&;

        using pointer=T*;
        using const_pointer=const T*;

        using iterator=STD::array_iterator<T,N>;
        using const_iterator=STD::array_const_iterator<T,N>;

        using reverse_iterator=STD::array_reverse_iterator<T,N>;
        using const_reverse_iterator=STD::array_const_reverse_iterator<T,N>;

        reference at(size_type n)
        {
            return const_cast<reference>(this->at(n));
        }

        constexpr const_reference at(size_type n)const
        {
            if(n<N){
                return this->m_buf[n];
            }else{
                return this->m_buf[N-1];
            }
        }

        reference operator[](size_type n)
        {
            return const_cast<reference>(this->at(n));
        }

        constexpr const_reference operator[](size_type n)const
        {
            return this->at(n);
        }

        reference front()
        {
            return const_cast<reference>(this->front());
        }

        constexpr const_reference front()const
        {
            return this->m_buf[0];
        }

        reference back()
        {
            return const_cast<reference>(this->back());
        }

        constexpr const_reference back()const
        {
            return this->m_buf[(N==0 ? 0 : N-1)];
        }

        T* data() noexcept
        {
            return const_cast<T*>(this->data());
        }

        const T* data() const noexcept
        {
            return this->m_buf;
        }

        iterator begin()
        {
            return iterator(*this, 0);
        }

        iterator end()
        {
            return iterator(*this, N-1);
        }

        const_iterator cbegin()
        {
            return const_iterator(*this, 0);
        }

        const_iterator cend()
        {
            return const_iterator(*this, N-1);
        }

        reverse_iterator rbegin()
        {
            return reverse_iterator(this->end());
        }

        reverse_iterator rend()
        {
            return reverse_iterator(this->begin());
        }

        const_reverse_iterator crbegin()
        {
            return reverse_const_iterator(this->cend());
        }

        const_reverse_iterator crend()
        {
            return reverse_const_iterator(this->cbegin());
        }

        constexpr size_type size()const noexcept
        {
            return N;
        }

        constexpr size_type max_size()const noexcept
        {
            return N;
        }

        constexpr bool empty()const noexcept
        {
            return true;
        }
    };
}
