// This file is generated by apc_parsers.py do not edit!

#pragma once

#include "base64.h"

static inline void parse_dnd_code(PS *self, uint8_t *parser_buf,
                                  const size_t parser_buf_pos) {
  unsigned int pos = 0;
  size_t payload_start = 0;
  enum PARSER_STATES { KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE, PAYLOAD };
  enum PARSER_STATES state = KEY, value_state = FLAG;
  DnDCommand g = {0};
  unsigned int i, code;
  uint64_t lcode;
  int64_t accumulator;
  bool is_negative;
  (void)is_negative;
  size_t sz;

  enum KEYS {
    type = 't',
    more = 'm',
    client_id = 'i',
    operation = 'o',
    cell_x = 'x',
    cell_y = 'y',
    pixel_x = 'X',
    pixel_y = 'Y'
  };

  enum KEYS key = 'a';
  if (parser_buf[pos] == ';')
    state = AFTER_VALUE;

  while (pos < parser_buf_pos) {
    switch (state) {
    case KEY:
      key = parser_buf[pos++];
      state = EQUAL;
      switch (key) {
      case type:
        value_state = FLAG;
        break;
      case more:
        value_state = UINT;
        break;
      case client_id:
        value_state = UINT;
        break;
      case operation:
        value_state = UINT;
        break;
      case cell_x:
        value_state = INT;
        break;
      case cell_y:
        value_state = INT;
        break;
      case pixel_x:
        value_state = INT;
        break;
      case pixel_y:
        value_state = INT;
        break;
      default:
        REPORT_ERROR(
            "Malformed DnDCommand control block, invalid key character: 0x%x",
            key);
        return;
      }
      break;

    case EQUAL:
      if (parser_buf[pos++] != '=') {
        REPORT_ERROR("Malformed DnDCommand control block, no = after key, "
                     "found: 0x%x instead",
                     parser_buf[pos - 1]);
        return;
      }
      state = value_state;
      break;

    case FLAG:
      switch (key) {

      case type: {
        g.type = parser_buf[pos++];
        if (g.type != 'A' && g.type != 'E' && g.type != 'M' && g.type != 'P' &&
            g.type != 'R' && g.type != 'a' && g.type != 'e' && g.type != 'k' &&
            g.type != 'm' && g.type != 'o' && g.type != 'p' && g.type != 'q' &&
            g.type != 'r') {
          REPORT_ERROR("Malformed DnDCommand control block, unknown flag value "
                       "for type: 0x%x",
                       g.type);
          return;
        };
      } break;

      default:
        break;
      }
      state = AFTER_VALUE;
      break;

    case INT:
#define READ_UINT                                                              \
  for (i = pos, accumulator = 0; i < MIN(parser_buf_pos, pos + 10); i++) {     \
    int64_t n = parser_buf[i] - '0';                                           \
    if (n < 0 || n > 9)                                                        \
      break;                                                                   \
    accumulator += n * digit_multipliers[i - pos];                             \
  }                                                                            \
  if (i == pos) {                                                              \
    REPORT_ERROR("Malformed DnDCommand control block, expecting an integer "   \
                 "value for key: %c",                                          \
                 key & 0xFF);                                                  \
    return;                                                                    \
  }                                                                            \
  lcode = accumulator / digit_multipliers[i - pos - 1];                        \
  pos = i;                                                                     \
  if (lcode > UINT32_MAX) {                                                    \
    REPORT_ERROR("Malformed DnDCommand control block, number is too large");   \
    return;                                                                    \
  }                                                                            \
  code = lcode;

      is_negative = false;
      if (parser_buf[pos] == '-') {
        is_negative = true;
        pos++;
      }
#define I(x)                                                                   \
  case x:                                                                      \
    g.x = is_negative ? 0 - (int32_t)code : (int32_t)code;                     \
    break
      READ_UINT;
      switch (key) {
        I(cell_x);
        I(cell_y);
        I(pixel_x);
        I(pixel_y);
      default:
        break;
      }
      state = AFTER_VALUE;
      break;
#undef I
    case UINT:
      READ_UINT;
#define U(x)                                                                   \
  case x:                                                                      \
    g.x = code;                                                                \
    break
      switch (key) {
        U(more);
        U(client_id);
        U(operation);
      default:
        break;
      }
      state = AFTER_VALUE;
      break;
#undef U
#undef READ_UINT

    case AFTER_VALUE:
      switch (parser_buf[pos++]) {
      default:
        REPORT_ERROR("Malformed DnDCommand control block, expecting a : or "
                     "semi-colon after a value, found: 0x%x",
                     parser_buf[pos - 1]);
        return;
      case ':':
        state = KEY;
        break;
      case ';':
        state = PAYLOAD;
        break;
      }
      break;

    case PAYLOAD: {
      sz = parser_buf_pos - pos;
      payload_start = pos;
      g.payload_sz = sz;
      pos = parser_buf_pos;
    } break;

    } // end switch
  } // end while

  switch (state) {
  case EQUAL:
    REPORT_ERROR("Malformed DnDCommand control block, no = after key");
    return;
  case INT:
  case UINT:
    REPORT_ERROR(
        "Malformed DnDCommand control block, expecting an integer value");
    return;
  case FLAG:
    REPORT_ERROR("Malformed DnDCommand control block, expecting a flag value");
    return;
  default:
    break;
  }

  REPORT_VA_COMMAND(
      "K s {sc sI sI sI si si si si ss#}", self->window_id, "dnd_command",

      "type", g.type,

      "more", (unsigned int)g.more, "client_id", (unsigned int)g.client_id,
      "operation", (unsigned int)g.operation,

      "cell_x", (int)g.cell_x, "cell_y", (int)g.cell_y, "pixel_x",
      (int)g.pixel_x, "pixel_y", (int)g.pixel_y,

      "", (char *)parser_buf + payload_start, g.payload_sz);

  screen_handle_dnd_command(self->screen, &g, parser_buf + payload_start);
}
