/*

ARIA header files for use with ARNL 1.7.1

Copyright(C) 2004, 2005 ActivMedia Robotics, LLC. 
Copyright(C) 2006, 2007, 2008, 2009 MobileRobots Inc.
All rights reserved.

This copy of Aria was relicensed for use with Arnl and the Arnl
license by MobileRobots Inc.  If you wish to download a seperate
distribution of Aria licensed under the GPL or a commercial license go to
http://www.mobilerobots.com/SOFTWARE/aria.html or contact MobileRobots
Inc, at robots@mobilerobots.com or MobileRobots Inc,
10 Columbia Drive, Amherst, NH 03031; 800-639-9481

MobileRobots Inc hereby grants to other individuals or
organizations permission to use this software with Arnl and in
compliance with the Arnl license.  This software may not be
distributed to others except by MobileRobots Inc.

MobileRobots Inc does not make any representations about the
suitability of this software for any purpose.  It is provided "as is"
without express or implied warranty.

*/
#ifndef ARJOYHANDLER_H
#define ARJOYHANDLER_H

#include "ariaTypedefs.h"
#include "ariaUtil.h"

#ifdef WIN32
#include <mmsystem.h> // for JOYINFO
#else // if not win32
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#endif
#ifdef linux
#include <linux/joystick.h>  // for JS_DATA_TYPE
#endif



/// Interfaces to a joystick
/** 
    The joystick handler keeps track of the minimum and maximums for both
    axes, updating them to constantly be better calibrated.  The speeds set 
    influence what is returned by getAdjusted...
    
    The joystick is not opened until init is called.  What should basically 
    be done to use this class is to 'init' a joystick, do a 'setSpeed' so you 
    can use 'getAdusted', then at some point do a 'getButton' to see if a
    button is pressed, and then do a 'getAdjusted' to get the values to act
    on.
    
    Also note that x is usually rotational velocity (since it right/left),
    whereas Y is translational (since it is up/down).
    
    You can also use this to do multiple uses with the joystick, for example to
    have button 1 drive the robot while to have button 2 move the camera, 
    you can get the different values you want (don't want to move the camera
    as quickly or as far as the robot) by using setSpeed before doing 
    getAdjusted since setSpeed is fast and won't take any time.
*/
class ArJoyHandler
{
 public:
  /// Constructor
  AREXPORT ArJoyHandler(bool useOSCal = true, bool useOldJoystick = false);
  /// Destructor
  AREXPORT ~ArJoyHandler();
  /// Intializes the joystick, returns true if successful
  AREXPORT bool init(void);
  /// Returns if the joystick was successfully initialized or not
  AREXPORT bool haveJoystick(void) { return myInitialized; }
  /// Gets the adjusted reading, as floats, between -1.0 and 1.0
  AREXPORT void getDoubles(double *x, double *y, double *z = NULL);
  /// Gets the button 
  AREXPORT bool getButton(unsigned int button);
  /// Returns true if we definitely have a Z axis (we don't know in windows unless it moves)
  AREXPORT bool haveZAxis(void) { return myHaveZ; }

  /// Sets the max that X or Y will return
  AREXPORT void setSpeeds(int x, int y, int z = 0) 
    { myTopX = x; myTopY = y; myTopZ = z; }
  /// Gets the adjusted reading, as integers, based on the setSpeed
  AREXPORT void getAdjusted(int *x, int *y, int *z = NULL);

  /// Gets the number of axes the joystick has
  AREXPORT unsigned int getNumAxes(void);
  /// Gets the floating (-1 to 1) location of the given joystick axis
  AREXPORT double getAxis(unsigned int axis);
  /// Gets the number of buttons the joystick has
  AREXPORT unsigned int getNumButtons(void);

  /// Sets whether to just use OS calibration or not
  AREXPORT void setUseOSCal(bool useOSCal);
  /// Gets whether to just use OS calibration or not
  AREXPORT bool getUseOSCal(void);
  /// Starts the calibration process
  AREXPORT void startCal(void);
  /// Ends the calibration process
  AREXPORT void endCal(void);
  /// Gets the unfilitered reading, mostly for internal use, maybe
  /// useful for Calibration
  AREXPORT void getUnfiltered(int *x, int *y, int *z = NULL);
  /// Gets the stats for the joystick, useful after calibrating to save values
  AREXPORT void getStats(int *maxX, int *minX, int *maxY, int *minY, 
		 int *cenX, int *cenY);
  /// Sets the stats for the joystick, useful for restoring calibrated settings
  AREXPORT void setStats(int maxX, int minX, int maxY, int minY, 
		int cenX, int cenY);
  /// Gets the speeds that X and Y are set to
  AREXPORT void getSpeeds(int *x, int *y, int *z);
 protected:
  // function to get the data for OS dependent part
  void getData(void);
  int myMaxX, myMinX, myMaxY, myMinY, myCenX, myCenY, myTopX, myTopY, myTopZ;
  bool myHaveZ;

  std::map<unsigned int, int> myAxes;
  std::map<unsigned int, bool> myButtons;

  int myPhysMax;
  bool myInitialized;
  bool myUseOSCal;
  bool myUseOld;
  bool myFirstData;
  ArTime myLastDataGathered;
#ifdef WIN32
  unsigned int myJoyID;
  int myLastZ;
  JOYINFO myJoyInfo;
  JOYCAPS myJoyCaps;
#else // if not win32
  int myJoyNumber;
  char myJoyNameTemp[512];
  ArTime myLastOpenTry;
  void getOldData(void);
  void getNewData(void);
  #ifdef linux 
  struct JS_DATA_TYPE myJoyData; // structure for the buttons and x,y coords
  #else
  int myJoyData;
  #endif
  FILE * myOldJoyDesc;
  int myJoyDesc;
#endif // linux
};


#endif // ARJOYHANDLER_H

