#include "rpi_artnet.h"

#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>

#include "rpi_artnet_utils.h"

int udpSocket = -1;
char buffer[1024];

void sendPollReply(struct sockaddr_in srcAddr);

void artnet_init() {
  struct sockaddr_in serverAddr;

  /*Create UDP socket*/
  udpSocket = socket(PF_INET, SOCK_DGRAM, 0);
  if (udpSocket < 0) {
    perror("Opening socket failed");
  }

  /* Configure settings in address struct */
  serverAddr.sin_family = AF_INET;
  serverAddr.sin_port = htons(ARTNET_PORT);
  serverAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
  memset(serverAddr.sin_zero, '\0', sizeof(serverAddr.sin_zero));

  /* Bind socket with address struct */
  bind(udpSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
}

int artnet_read(artDmx_t **artDmx) {
  struct sockaddr_in srcAddr;
  socklen_t srcLen = sizeof(srcAddr);
  ssize_t bufferLen =
      recvfrom(udpSocket, buffer, ARTNET_MAX_BUFFER, 0, (struct sockaddr *)&srcAddr, &srcLen);

  if (bufferLen <= ARTNET_MAX_BUFFER && bufferLen > sizeof(artnetHeader_t)) {
    artnetHeader_t *artnetHeader = (artnetHeader_t *)buffer;
    if (memcmp(artnetHeader->id, ARTNET_ID, sizeof(ARTNET_ID)) == 0) {
      switch (artnetHeader->opCode) {
      case OpDmx:
        if (bufferLen >= 20) {
          *artDmx = (artDmx_t *)buffer;
        }
        break;
      case OpPoll:
        sendPollReply(srcAddr);
        break;
      default:
        break;
      }
    }

    return artnetHeader->opCode;
  }
  return -1;
}

void sendPollReply(struct sockaddr_in srcAddr) {
  /* Configure settings in address struct */
  srcAddr.sin_family = AF_INET;
  srcAddr.sin_port = htons(ARTNET_PORT);
  memset(srcAddr.sin_zero, '\0', sizeof(srcAddr.sin_zero));

  sendto(udpSocket, (uint8_t *)&artPollReply, sizeof(artPollReply_t), 0,
         (struct sockaddr *)&srcAddr, sizeof(srcAddr));
}