#if OSW_IMPL_WIN32
# include "mr4th_osw.win32.c"
#elif OSW_IMPL_WAYLAND
# include "mr4th_osw.wayland.c"
#else
# error no OSW implementation for this OS
#endif

////////////////////////////////
// Functions: OSW Backend Functions

MR4TH_SYMBOL U32          osw__activation_counter = 0;
MR4TH_SYMBOL OSW_Backend* osw__active_backend = 0;
MR4TH_SYMBOL OSW_Window*  osw__active_window = 0;

MR4TH_SYMBOL void
osw_backend_close(OSW_Backend *backend){
  if (osw__active_backend != 0){
    er_emit_lit("osw: closing render backend with an active render");
  }
  else{
    backend->close();
  }
}

MR4TH_SYMBOL void
osw_backend_render_begin(OSW_Backend *backend, OSW_Window *window){
  Assert(window == 0 || osw_window_is_valid(window));
  if (osw__activation_counter == 0){
    backend->begin(window);
    osw__activation_counter = 1;
    osw__active_backend = backend;
    osw__active_window = window;
  }
  else{
    if (backend != osw__active_backend){
      er_emit_lit("osw: beginning active render with conflicting backend");
    }
    else if (window != 0 && window != osw__active_window){
      er_emit_lit("osw: beginning active render with conflicting window");
    }
    else{
      osw__activation_counter += 1;
    }
  }
}

MR4TH_SYMBOL void
osw_backend_render_end(void){
  if (osw__activation_counter == 0){
    er_emit_lit("osw: ending render backend with no active render");
  }
  else{
    osw__activation_counter -= 1;
    if (osw__activation_counter == 0){
      osw__active_backend->end(osw__active_window);
      osw__active_backend = 0;
      osw__active_window = 0;
    }
  }
}

////////////////////////////////
// Functions: OSW Input Generator Functions

MR4TH_SYMBOL_STATIC OSW_Input *osw__input = 0;
MR4TH_SYMBOL_STATIC Arena     *osw__input_arena = 0;

MR4TH_SYMBOL void
osw_event__write_begin(Arena *arena){
  osw__input_arena = arena;
  osw__input = push_array(arena, OSW_Input, 1);
}

MR4TH_SYMBOL OSW_Event*
osw_event__write_push(void){
  static OSW_Event dummy_event = {0};
  OSW_Event *event = &dummy_event;
  if (osw__input_arena != 0 && osw__input != 0){
    event = push_array(osw__input_arena, OSW_Event, 1);
    DLLPushBack(osw__input->first_event, osw__input->last_event, event);
    osw__input->event_count += 1;
  }
  return(event);
}

////////////////////////////////
// Functions: OSW Input Accessor Functions

MR4TH_SYMBOL void
osw_event_erase(OSW_Event *event){
  if (event->kind != 0 && osw__input != 0){
    event->kind = 0;
    DLLRemove(osw__input->first_event, osw__input->last_event, event);
    osw__input->event_count -= 1;
  }
}

MR4TH_SYMBOL OSW_Event*
osw_event__first(void){
  OSW_Event *first = osw__input->first_event;
  return(first);
}

////////////////////////////////
// Functions: OSW Window Allocator Functions

MR4TH_SYMBOL OSW_Window  osw__windows[MR4TH_OSW_MAX_WINDOW_COUNT] = {0};
MR4TH_SYMBOL OSW_Window* osw__window_cursor = osw__windows;
MR4TH_SYMBOL OSW_Window* osw__window_free = 0;
MR4TH_SYMBOL OSW_Window* osw__window_first = 0;
MR4TH_SYMBOL OSW_Window* osw__window_last = 0;

MR4TH_SYMBOL OSW_Window*
osw_window__alloc(void){
  // TODO(allen): take mutex
  
  OSW_Window *ptr = osw__window_free;
  if (ptr != 0){
    SLLStackPop_NZ(osw__window_free, base.next, 0);
  }
  if (ptr == 0 && osw__window_cursor < ArrayOpl(osw__windows)){
    ptr = osw__window_cursor;
    osw__window_cursor += 1;
  }
  
  if (ptr != 0){
    ptr->base.allocated = 1;
    DLLPushBack_NPZ(osw__window_first, osw__window_last, ptr,
                    base.next, base.prev, 0);
  }
  
  // TODO(allen): release mutex
  return(ptr);
}

MR4TH_SYMBOL void
osw_window__release(OSW_Window *window){
  window->base.allocated = 0;
  DLLRemove_NPZ(osw__window_first, osw__window_last, window,
                base.next, base.prev, 0);
  SLLStackPush_N(osw__window_free, window, base.next);
}

MR4TH_SYMBOL OSW_Window*
osw_window__first(void){
  OSW_Window *result = osw__window_first;
  return(result);
}

MR4TH_SYMBOL U32
osw_window__idx_from_ptr(OSW_Window *window){
  U32 result = (U32)(window - osw__windows);
  return(result);
}

////////////////////////////////
// Functions: OSW Error Functions

MR4TH_SYMBOL void
osw__error_unsupported(OSW_Cap cap){
}
