{.deadCodeElim: on.}

from ../vk/vulkan import VkDeviceSize
from sequtils import concat
from ../platforms/unix/x11/xcb import xcb_keycode_t

#from ../platforms/unix/xcb import xcb_keysym_t
import bitops
import macros, strutils

macro string_of*( x: typed
                ): string = x.toStrLit

proc printf*(formatstr: cstring) {.importc: "printf", varargs, header: "<stdio.h>".}

proc `<`*(x,y: VkDeviceSize): bool = return x.int < y.int
proc `>`*(x,y: VkDeviceSize): bool = return x.int > y.int
proc `==`*(x,y: VkDeviceSize): bool = return x.int == y.int

proc `&=`*(s,s2: string): string = result = s & s2

template pr*(t: varargs[string, `$`]) = 
 var str: string
 for thing in t: str &= thing & " "
 echo str 
   
proc `$>>`*[T](t: T) = echo repr t

proc flatten2*[T](a: seq[T]): seq[T] = a
proc flatten2*[T](a: seq[seq[T]]): auto = a.concat.flatten

proc toString*(str: array[0..255, char]): string =
 result = newStringOfCap str.len
 for ch in str: 
  if ch == '\x00': discard
  else: add(result, ch)

proc toString*(str: seq[char] | cstring): string =
 result = newStringOfCap str.len
 for ch in str: add(result, ch)

proc `nil?` *[T](t: T):bool = cast[pointer](t).isNil

iterator count*(f: float): float =
 var i = 0.0
 while i <= f:
  if (i == 121).bool: break  # this is a stupid hack because Keymaps is an array of 121
  yield i
  i += 1 

#define _KTX_PADN(n, nbytes) (nbytes + (n-1) & ~(ktx_uint32_t)(n-1))
# right now this is only used for `loadKTXFile` from text/textutils.nim
proc pad_bytes*[T]( n: int
                  , nBytes: T
                  ): uint8 = 
 # Equivalent to n * ceil(nbytes / n) 
 bitand( nBytes + cast[uint32](n-1)
              , bitnot( cast[uint32](n - 1) ) 
              ).uint8

template `+`*[T]( p: ptr T
                , off: xcb_keycode_t | int | int32 | uint32 | uint64 | Natural
                ): ptr T =
 cast[ptr type(p[])](cast[ByteAddress](p) +% (off * sizeof(p[])))


template `+=`*[T]( p: ptr T
                 , off: T#int | Natural
                 ) =
  p = p + off

template `-`*[T]( p: ptr T
                , off: int | xcb_keycode_t
                ): ptr T =
 cast[ptr type(p[])](cast[ByteAddress](p) -% off * sizeof(p[]))

template `-=`*[T](p: ptr T, off: int | xcb_keycode_t) =
 p = p - off

template `[]`*[T]( p: ptr T
                 , off: int | xcb_keycode_t | int32 | Natural
                 ): T =
 (p + off)[]

template `[]=`*[T]( p: ptr T
                  , off: int | int32 | Natural 
                  , val: T
                  ) =
  (p + off)[] = val



#[
  proc main = 

 var 
  p = A_WAINDO()
  t = aTriShape p.rec
  frameCounter: uint32
  frameTimer = 1.0
  paused = false
  timer = 0.0
  timerSpeed = 1.0 # speed up or slow down
  lastTS: float
  lastFPS: uint32
  ticks: float
  diff: float

 while not p.quit:
  events p 
 
  let a = cpuTime()
  
  #render
  p.rec.draw t
  frameCounter += 1
  let b = cpuTime()
  
  diff =  b - a
  frameTimer = diff * 1000
  ticks = frameTimer * 10_000
  # camera.update frameTimer
  if not paused:
   timer += timerSpeed * frameTimer 
   if timer > 1.0: timer -= 1.0
  
  #echo("diff: ",diff, " FT: ",frameTimer, " ticks: ", frame)
#  echo fpsTimer / 1000
  var fpsTimer = (b - lastTS) * 1000
  if fpsTimer > 1000:
   lastFPS = (frameCounter.float * (1000.0 / fpsTimer)).uint32
   #echo("fps:", lastFPS, " FT: ", frameTimer)
   echo frameCounter
   frameCounter = 0 
   lastTS = b
 # updateOverlay()
 # 
 p.close

main()
]#

#include <err.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#include <xcb/xcb.h>
#include <xcb/xkb.h>

# struct ctx {
#     xcb_connection_t *conn;
#     uint8_t first_xkb_event;
# };

# static void
# handle_xkb_event(struct ctx *ctx, xcb_generic_event_t *event)
# {
#     union xkb_event {
#         struct {
#             uint8_t response_type;
#             uint8_t xkbType;
#             uint16_t sequence;
#             xcb_timestamp_t time;
#             uint8_t deviceID;
#         } any;
#         xcb_xkb_map_notify_event_t map_notify;
#         xcb_xkb_state_notify_event_t state_notify;
#     } *xkb_event;

#     xkb_event = (union xkb_event *) event;
#     switch (xkb_event->any.xkbType) {
#     case XCB_XKB_NEW_KEYBOARD_NOTIFY:
#         printf("xkb new keyboard notify\n");
#         break;
#     case XCB_XKB_MAP_NOTIFY:
#         printf("xkb map notify\n");
#         break;
#     case XCB_XKB_STATE_NOTIFY:
#         printf("xkb state notify\n");
#          break;
#     default:
#         break;
#     }
# }

# static void
# loop(struct ctx *ctx)
# {
#     while (true) 
#     {
#         xcb_generic_event_t *event;

#         event = xcb_wait_for_event(ctx->conn);
#         if (!event)
#             errx(1, "couldn't get event");

#         if (event->response_type == XCB_MAPPING_NOTIFY) {
#             printf("core mapping notify\n");
#         }
#         if (event->response_type == ctx->first_xkb_event) {
#             handle_xkb_event(ctx, event);
#         }

#         free(event);
#     }
# }

# static void
# setup_xkb(struct ctx *ctx)
# {
#     {
#         const xcb_query_extension_reply_t *ext;

#         ext = xcb_get_extension_data(ctx->conn, &xcb_xkb_id);
#         if (!ext)
#             errx(1, "no XKB in X server");
#         ctx->first_xkb_event = ext->first_event;
#     }

#     {
#         xcb_xkb_use_extension_cookie_t use_ext;
#         xcb_xkb_use_extension_reply_t *use_ext_reply;

#         use_ext = xcb_xkb_use_extension(ctx->conn,
#                                         XCB_XKB_MAJOR_VERSION,
#                                         XCB_XKB_MINOR_VERSION);
#         use_ext_reply = xcb_xkb_use_extension_reply(ctx->conn, use_ext, NULL);
#         if (!use_ext_reply)
#             errx(1, "couldn't use XKB extension");

#         if (!use_ext_reply->supported)
#             errx(1, "the XKB extension is not supported in X server");

#         free(use_ext_reply);
#     }

#     {
#         xcb_void_cookie_t select;
#         xcb_generic_error_t *error;
#         static const uint16_t affectWhich = (XCB_XKB_EVENT_TYPE_MAP_NOTIFY |
#                                              XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |
#                                              XCB_XKB_EVENT_TYPE_STATE_NOTIFY);

#         static const uint16_t affectMap = (XCB_XKB_MAP_PART_KEY_TYPES |
#                                            XCB_XKB_MAP_PART_KEY_SYMS |
#                                            XCB_XKB_MAP_PART_MODIFIER_MAP |
#                                            XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
#                                            XCB_XKB_MAP_PART_KEY_ACTIONS |
#                                            XCB_XKB_MAP_PART_KEY_BEHAVIORS |
#                                            XCB_XKB_MAP_PART_VIRTUAL_MODS |
#                                            XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP);

#         select = xcb_xkb_select_events_checked(ctx->conn,
#                                                XCB_XKB_ID_USE_CORE_KBD,
#                                                affectWhich,
#                                                0,
#                                                affectWhich,
#                                                affectMap,
#                                                affectMap,
#                                                NULL);
#         error = xcb_request_check(ctx->conn, select);
#         if (error)
#             errx(1, "couldn't select XKB events");
#     }
# }

# int
# main(void)
# {
#     struct ctx ctx;

#     ctx.conn = xcb_connect(NULL, NULL);
#     if (!ctx.conn)
#         errx(1, "couldn't connect to display");

#     setup_xkb(&ctx);
#     loop(&ctx);

#     xcb_disconnect(ctx.conn);

#     return 0;
# }