/* bzflag
 * Copyright (c) 1993-2017 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* common headers */
#include "common.h"

#ifdef HAVE_SDL

/* interface headers */
#include "SDLJoystick.h"

/* system headers */
#include <vector>
#include <string>
#include <string.h>
#include <ctype.h>

/* implementation headers */
#include "ErrorHandler.h"
#include "TextUtils.h"
#include "bzfSDL.h"

SDLJoystick::SDLJoystick() : joystickID(NULL), joystickButtons(0), numHats(0),
  xAxis(0), yAxis(1)
{
  if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) {
    std::vector<std::string> args;
    args.push_back(SDL_GetError());
    printError("Could not initialize SDL Joystick subsystem: %s.\n", &args);
  };
}

SDLJoystick::~SDLJoystick()
{
  SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
}

void			SDLJoystick::initJoystick(const char* joystickName)
{
  if (!strcasecmp(joystickName, "off") || !strcmp(joystickName, "")) {
    if (joystickID != NULL) {
      SDL_JoystickClose(joystickID);
      joystickID = NULL;
    }
    return;
  }
  char num = joystickName[0];
  int  i   = (int)num - '0';
  if (!isdigit(num) || i >= SDL_NumJoysticks()) {
    printError("No supported SDL joysticks were found.");
    joystickID = NULL;
    return;
  }
  joystickID = SDL_JoystickOpen(i);
  if (joystickID == NULL)
    return;
  if (SDL_JoystickNumAxes(joystickID) < 2) {
    SDL_JoystickClose(joystickID);
    printError("Joystick has less then 2 axes:\n");
    joystickID = NULL;
    return;
  }
  joystickButtons = SDL_JoystickNumButtons(joystickID);
  numHats = SDL_JoystickNumHats(joystickID);
}

bool			SDLJoystick::joystick() const
{
  return joystickID != NULL;
}

void			SDLJoystick::getJoy(int& x, int& y)
{
  x = y = 0;

  if (!joystickID)
    return;

  SDL_JoystickUpdate();
  x = SDL_JoystickGetAxis(joystickID, xAxis);
  y = SDL_JoystickGetAxis(joystickID, yAxis);

  x = x * 1000 / 32768;
  y = y * 1000 / 32768;

  // ballistic
  x = (x * abs(x)) / 1000;
  y = (y * abs(y)) / 1000;

}

unsigned long		SDLJoystick::getJoyButtons()
{
  unsigned long buttons = 0;

  if (!joystickID)
    return 0;

  SDL_JoystickUpdate();
  for (int i = 0; i < joystickButtons; i++)
    buttons |= SDL_JoystickGetButton(joystickID, i) << i;

  return buttons;
}

int		 SDLJoystick::getNumHats()
{
  if (!joystickID)
    return 0;

  return numHats;
}

void		SDLJoystick::getJoyHat(int hat, float &hatX, float &hatY)
{
  hatX = hatY = 0;

  if (!joystickID)
    return;

  if (hat >= numHats) // a precaution
    return;

  SDL_JoystickUpdate();
  int value = SDL_JoystickGetHat(joystickID, hat);
  //  9 1 3 ->   -1
  //  8 0 2 -> -1 0 1
  // 12 6 4 ->    1
  if (value - 8 >= 0) { value -= 8;
    hatX = -1;
  }
  if (value - 4 >= 0) { value -= 4;
    hatY = 1;
  }
  if (value - 2 >= 0) { value -= 2;
    hatX = 1;
  }
  if (value - 1 >= 0) {
    hatY = -1;
  }
}

void		    SDLJoystick::getJoyDevices(std::vector<std::string>
						 &list) const
{
  int numJoystick = SDL_NumJoysticks();
  if (numJoystick > 9) //user would have to be insane to have this many anyway
    numJoystick = 9;
  int i;
  for (i = 0; i < numJoystick; i++) {
    char joystickName[50]; //only room for so much on the menu
#ifdef HAVE_SDL2
    snprintf(joystickName, 50, "%d - %s", i, SDL_JoystickNameForIndex(i));
#else
    snprintf(joystickName, 50, "%d - %s", i, SDL_JoystickName(i));
#endif
    list.push_back(joystickName);
  }
}

void		    SDLJoystick::getJoyDeviceAxes(std::vector<std::string> &list) const
{
  if (!joystickID) return;
  list.clear();
  // number all the axes and send them off
  for (int i = 0; i < SDL_JoystickNumAxes(joystickID); ++i) {
    list.push_back(TextUtils::format("%d", i));
  }
}

void		    SDLJoystick::setXAxis(const std::string &axis)
{
  // unset
  if (axis == "") return;
  xAxis = atoi(axis.c_str());
}

void		    SDLJoystick::setYAxis(const std::string &axis)
{
  // unset
  if (axis == "") return;
  yAxis = atoi(axis.c_str());
}

#endif

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
