/**
 * Copyright (c) 2021 Dominic Msters
 * 
 * This software is released under the MIT License.
 * https://opensource.org/licenses/MIT
 */

#include "input.h"

void inputInit(input_t *input) {
  int32_t i;

  // Setup the bind lists
  for(i = 0; i < INPUT_BIND_COUNT; i++) {
    input->bindMap[i] = listCreate();
  }

  input->current = input->inputsA;
  input->previous = input->inputsB;

  // Create the buffer, zero all the values out.
  memset(&input->buffer, 0, sizeof(inputval_t)*INPUT_SOURCE_COUNT);
}

void inputUpdate(input_t *input) {
  int32_t i;
  listentry_t *item;
  inputval_t value;

  // Flip the states to save memory.
  inputval_t *currentCurrent = input->current;
  input->current = input->previous;
  input->previous = currentCurrent;

  // Now look at each bind...
  for(i = 0; i < INPUT_BIND_COUNT; i++) {
    // Now get the list of input sources bound to this input
    item = input->bindMap[i]->start;
    value = 0;

    // For each input source, add the value from the buffer
    while(item != NULL) {
      value += input->buffer[(inputsource_t)item->data];
      item = item->next;
    }

    // Set to the current state.
    input->current[i] = value;
  }
}

void inputDispose(input_t *input) {
  int32_t i;

  // Free up the bind lists
  for(i = 0; i < INPUT_BIND_COUNT; i++) {
    listDispose(input->bindMap[i], false);
  }
}

void inputBind(input_t *input, inputbind_t bind, inputsource_t source) {
  listAdd(input->bindMap[bind], (void *)source);
}

void inputUnbind(input_t *input, inputbind_t bind, inputsource_t source) {
  listRemove(input->bindMap[bind], (void *)source);
}

bool inputIsDown(input_t *input, inputbind_t binding) {
  return input->current[binding] != 0;
}

bool inputIsUp(input_t *input, inputbind_t binding) {
  return input->current[binding] == 0;
}

bool inputIsPressed(input_t *input, inputbind_t binding) {
  return (
    input->previous[binding] == 0 &&
    input->current[binding] != 0
  );
}

bool inputIsReleased(input_t *input, inputbind_t binding) {
  return input->current[binding]==0 && input->previous[binding] != 0;
}

inputval_t inputGetAxis(input_t *input, inputbind_t binding) {
  return input->current[binding];
}

float inputGetFullAxis(input_t *input, inputbind_t positive,
  inputbind_t negative
) {
  return -input->current[negative] + input->current[positive];
}

float inputGetAccuated(input_t *input, inputbind_t binding) {
  return input->times[binding];
}