text: #include "controller.h"
  
  #include <SDL2/SDL_assert.h>
  #include "config.h"
  #include "lock_util.h"
  #include "log.h"
  
  SDL_bool controller_init(struct controller *controller, socket_t video_socket) {
      if (!control_event_queue_init(&controller->queue)) {
          return SDL_FALSE;
      }
  
      if (!(controller->mutex = SDL_CreateMutex())) {
          return SDL_FALSE;
      }
  
      if (!(controller->event_cond = SDL_CreateCond())) {
          SDL_DestroyMutex(controller->mutex);
          return SDL_FALSE;
      }
  
      controller->video_socket = video_socket;
      controller->stopped = SDL_FALSE;
  
      return SDL_TRUE;
  }
  
  void controller_destroy(struct controller *controller) {
      SDL_DestroyCond(controller->event_cond);
      SDL_DestroyMutex(controller->mutex);
      control_event_queue_destroy(&controller->queue);
  }
  
  SDL_bool controller_push_event(struct controller *controller, const struct control_event *event) {
      LOGD("controller: %d", controller);
      if (event->type == CONTROL_EVENT_TYPE_MOUSE) {
          LOGD("push mouse event...");
      } else if (event->type == CONTROL_EVENT_TYPE_SCROLL) {
          LOGD("push scroll event...");
  
      } else if (event->type == CONTROL_EVENT_TYPE_KEYCODE) {
          LOGD("push key event...");
  
      } else if (event->type == CONTROL_EVENT_TYPE_TEXT) {
          LOGD("push text event...");
          LOGD("%s", event->text_event.text);
  
      } else if (event->type == CONTROL_EVENT_TYPE_COMMAND) {
          LOGD("push command event...");
      }
      SDL_bool res;
      mutex_lock(controller->mutex);
      SDL_bool was_empty = control_event_queue_is_empty(&controller->queue);
      res = control_event_queue_push(&controller->queue, event);
      if (was_empty) {
          cond_signal(controller->event_cond);
      }
      mutex_unlock(controller->mutex);
      return res;
  }
  
  static SDL_bool process_event(struct controller *controller, const struct control_event *event) {
      unsigned char serialized_event[SERIALIZED_EVENT_MAX_SIZE];
      int length = control_event_serialize(event, serialized_event);
      if (!length) {
          return SDL_FALSE;
      }
      int w = net_send_all(controller->video_socket, serialized_event, length);
      return w == length;
  }
  
  static int run_controller(void *data) {
      struct controller *controller = data;
  
      for (;;) {
          mutex_lock(controller->mutex);
          while (!controller->stopped && control_event_queue_is_empty(&controller->queue)) {
              cond_wait(controller->event_cond, controller->mutex);
          }
          if (controller->stopped) {
              // stop immediately, do not process further events
              mutex_unlock(controller->mutex);
              break;
          }
          struct control_event event;
          SDL_bool non_empty = control_event_queue_take(&controller->queue, &event);
          SDL_assert(non_empty);
          mutex_unlock(controller->mutex);
  
          SDL_bool ok = process_event(controller, &event);
          control_event_destroy(&event);
          if (!ok) {
              LOGD("Cannot write event to socket");
              break;
          }
      }
      return 0;
  }
  
  SDL_bool controller_start(struct controller *controller) {
      LOGD("Starting controller thread");
  
      controller->thread = SDL_CreateThread(run_controller, "controller", controller);
      if (!controller->thread) {
          LOGC("Could not start controller thread");
          return SDL_FALSE;
      }
  
      return SDL_TRUE;
  }
  
  void controller_stop(struct controller *controller) {
      mutex_lock(controller->mutex);
      controller->stopped = SDL_TRUE;
      cond_signal(controller->event_cond);
      mutex_unlock(controller->mutex);
  }
  
  void controller_join(struct controller *controller) {
      SDL_WaitThread(controller->thread, NULL);
  }
  