/* MIT License
 *
 * Copyright (c) 2025 Tyge Løvset
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
// Deque - double ended queue. Implemented as a ring buffer, extension of queue.

#include "priv/linkage.h"
#include "types.h"

#ifndef STC_DEQUE_H_INCLUDED
#define STC_DEQUE_H_INCLUDED
#include "common.h"
#include <stdlib.h>
#endif // STC_DEQUE_H_INCLUDED

#ifndef _i_prefix
  #define _i_prefix deque_
#endif
#define _pop _pop_front
#define _pull _pull_front
#include "priv/template.h"
#include "priv/queue_prv.h"
#undef _pop
#undef _pull

STC_API _m_value*   _c_MEMB(_push_front)(Self* self, _m_value value);
STC_API _m_iter     _c_MEMB(_insert_n)(Self* self, isize idx, const _m_value* arr, isize n);
STC_API _m_iter     _c_MEMB(_insert_uninit)(Self* self, isize idx, isize n);
STC_API void        _c_MEMB(_erase_n)(Self* self, isize idx, isize n);

STC_INLINE const _m_value*
_c_MEMB(_at)(const Self* self, isize idx) {
    c_assert(c_uless(idx, _c_MEMB(_size)(self)));
    return self->cbuf + _cbuf_topos(self, idx);
}

STC_INLINE _m_value*
_c_MEMB(_at_mut)(Self* self, isize idx)
    { return (_m_value*)_c_MEMB(_at)(self, idx); }

STC_INLINE _m_value*
_c_MEMB(_push_back)(Self* self, _m_value val)
    { return  _c_MEMB(_push)(self, val); }

STC_INLINE void
_c_MEMB(_pop_back)(Self* self) {
    c_assert(!_c_MEMB(_is_empty)(self));
    self->end = (self->end - 1) & self->capmask;
    i_keydrop((self->cbuf + self->end));
}

STC_INLINE _m_value _c_MEMB(_pull_back)(Self* self) { // move back out of deque
    c_assert(!_c_MEMB(_is_empty)(self));
    self->end = (self->end - 1) & self->capmask;
    return self->cbuf[self->end];
}

STC_INLINE _m_iter
_c_MEMB(_insert_at)(Self* self, _m_iter it, const _m_value val) {
    isize idx = _cbuf_toidx(self, it.pos);
    return _c_MEMB(_insert_n)(self, idx, &val, 1);
}

STC_INLINE _m_iter
_c_MEMB(_erase_at)(Self* self, _m_iter it) {
    _c_MEMB(_erase_n)(self, _cbuf_toidx(self, it.pos), 1);
    if (it.pos == self->end) it.ref = NULL;
    return it;
}

STC_INLINE _m_iter
_c_MEMB(_erase_range)(Self* self, _m_iter it1, _m_iter it2) {
    isize idx1 = _cbuf_toidx(self, it1.pos);
    isize idx2 = _cbuf_toidx(self, it2.pos);
    _c_MEMB(_erase_n)(self, idx1, idx2 - idx1);
    if (it1.pos == self->end) it1.ref = NULL;
    return it1;
}

#if !defined i_no_emplace
STC_API _m_iter
_c_MEMB(_emplace_n)(Self* self, isize idx, const _m_raw* raw, isize n);

STC_INLINE _m_value*
_c_MEMB(_emplace_front)(Self* self, const _m_raw raw)
    { return _c_MEMB(_push_front)(self, i_keyfrom(raw)); }

STC_INLINE _m_value*
_c_MEMB(_emplace_back)(Self* self, const _m_raw raw)
    { return _c_MEMB(_push)(self, i_keyfrom(raw)); }

STC_INLINE _m_iter
_c_MEMB(_emplace_at)(Self* self, _m_iter it, const _m_raw raw)
    { return _c_MEMB(_insert_at)(self, it, i_keyfrom(raw)); }
#endif

#if defined _i_has_eq
STC_API _m_iter _c_MEMB(_find_in)(const Self* self, _m_iter p1, _m_iter p2, _m_raw raw);

STC_INLINE _m_iter
_c_MEMB(_find)(const Self* self, _m_raw raw) {
    return _c_MEMB(_find_in)(self, _c_MEMB(_begin)(self), _c_MEMB(_end)(self), raw);
}
#endif // _i_has_eq

#if defined _i_has_cmp
#include "priv/sort_prv.h"
#endif // _i_has_cmp

/* -------------------------- IMPLEMENTATION ------------------------- */
#if defined i_implement

STC_DEF _m_value*
_c_MEMB(_push_front)(Self* self, _m_value value) {
    isize start = (self->start - 1) & self->capmask;
    if (start == self->end) { // full
        if (!_c_MEMB(_reserve)(self, self->capmask + 3)) // => 2x expand
            return NULL;
        start = (self->start - 1) & self->capmask;
    }
    _m_value *v = self->cbuf + start;
    self->start = start;
    *v = value;
    return v;
}

STC_DEF void
_c_MEMB(_erase_n)(Self* self, const isize idx, const isize n) {
    const isize len = _c_MEMB(_size)(self);
    c_assert(idx + n <= len);
    for (isize i = idx + n - 1; i >= idx; --i)
        i_keydrop(_c_MEMB(_at_mut)(self, i));
    for (isize i = idx, j = i + n; j < len; ++i, ++j)
        *_c_MEMB(_at_mut)(self, i) = *_c_MEMB(_at)(self, j);
    self->end = (self->end - n) & self->capmask;
}

STC_DEF _m_iter
_c_MEMB(_insert_uninit)(Self* self, const isize idx, const isize n) {
    const isize len = _c_MEMB(_size)(self);
    _m_iter it = {._s=self};
    if (len + n >= self->capmask)
        if (!_c_MEMB(_reserve)(self, len + n)) // minimum 2x expand
            return it;
    it.pos = _cbuf_topos(self, idx);
    it.ref = self->cbuf + it.pos;
    self->end = (self->end + n) & self->capmask;

    if (it.pos < self->end) // common case because of reserve policy
        c_memmove(it.ref + n, it.ref, (len - idx)*c_sizeof *it.ref);
    else for (isize i = len - 1, j = i + n; i >= idx; --i, --j)
        *_c_MEMB(_at_mut)(self, j) = *_c_MEMB(_at)(self, i);
    return it;
}

STC_DEF _m_iter
_c_MEMB(_insert_n)(Self* self, const isize idx, const _m_value* arr, const isize n) {
    _m_iter it = _c_MEMB(_insert_uninit)(self, idx, n);
    for (isize i = idx, j = 0; j < n; ++i, ++j)
        *_c_MEMB(_at_mut)(self, i) = arr[j];
    return it;
}

#if !defined i_no_emplace
STC_DEF _m_iter
_c_MEMB(_emplace_n)(Self* self, const isize idx, const _m_raw* raw, const isize n) {
    _m_iter it = _c_MEMB(_insert_uninit)(self, idx, n);
    for (isize i = idx, j = 0; j < n; ++i, ++j)
        *_c_MEMB(_at_mut)(self, i) = i_keyfrom(raw[j]);
    return it;
}
#endif

#if defined _i_has_eq
STC_DEF _m_iter
_c_MEMB(_find_in)(const Self* self, _m_iter i1, _m_iter i2, _m_raw raw) {
    (void)self;
    for (; i1.ref != i2.ref; _c_MEMB(_next)(&i1)) {
        const _m_raw r = i_keytoraw(i1.ref);
        if (i_eq((&raw), (&r)))
            break;
    }
    return i1;
}
#endif
#endif // IMPLEMENTATION
#include "priv/linkage2.h"
#include "priv/template2.h"
