#define HID_INTERNAL

#include <hid.h>
#include <hid_helpers.h>

#include <string.h>

#include <debug.h>
#include <assert.h>

static void hid_prepare_parse_path(HIDInterface* const hidif,
    int const path[], unsigned int const depth)
{
  ASSERT(hid_is_opened(hidif));
  ASSERT(hidif->hid_data);

  unsigned int i = 0;

  TRACE("preparing search path of depth %d for parse tree of USB device %s...",
      depth, hidif->id);
  for (; i < depth; ++i) {
    hidif->hid_data->Path.Node[i].UPage = path[i] >> 16;
    hidif->hid_data->Path.Node[i].Usage = path[i] & 0x0000ffff;
  }

  hidif->hid_data->Path.Size = depth;

  TRACE("search path prepared for parse tree of USB device %s.", hidif->id);
}

hid_return hid_init_parser(HIDInterface* const hidif)
{
  if (!hid_is_opened(hidif)) {
    ERROR("cannot initialise parser of unopened HIDinterface.");
    return HID_RET_DEVICE_NOT_OPENED;
  }
  
  ASSERT(!hidif->hid_parser);
  ASSERT(!hidif->hid_data);

  TRACE("initialising the HID parser for USB Device %s...", hidif->id);

  TRACE("allocating space for HIDData structure...");
  hidif->hid_data = (HIDData*)malloc(sizeof(HIDData));
  if (!hidif->hid_data) {
    ERROR("failed to allocate memory for HIDData structure of USB device %s.",
        hidif->id);
    return HID_RET_FAIL_ALLOC;
  }
  TRACE("successfully allocated memory for HIDData strcture.");

  TRACE("allocating space for HIDParser structure...");
  hidif->hid_parser = (HIDParser*)malloc(sizeof(HIDParser));
  if (!hidif->hid_parser) {
    ERROR("failed to allocate memory for HIDParser structure of USB device %s.",
        hidif->id);
    return HID_RET_FAIL_ALLOC;
  }
  TRACE("successfully allocated memory for HIDParser strcture.");

  NOTICE("successfully initialised the HID parser for USB Device %s.",
      hidif->id);
  
  return HID_RET_SUCCESS;
}

hid_return hid_prepare_parser(HIDInterface* const hidif)
{
  if (!hid_is_opened(hidif)) {
    ERROR("cannot prepare parser of unopened HIDinterface.");
    return HID_RET_DEVICE_NOT_OPENED;
  }
  ASSERT(hidif->hid_parser);
  
  TRACE("setting up the HID parser for USB device %s...", hidif->id);

  hid_reset_parser(hidif);

  TRACE("dumping the raw report descriptor");
  {
	  char buffer[160], tmp[10];
	  int i;

	  sprintf(buffer, "0x%03x: ", 0);
	  for(i=0; i<hidif->hid_parser->ReportDescSize; i++) {
		  if(!(i % 8)) {
			  if(i != 0) TRACE("%s", buffer);
			  sprintf(buffer, "0x%03x: ", i);
		  }
		  sprintf(tmp, "0x%02x ", (int)(hidif->hid_parser->ReportDesc[i]));
		  strcat(buffer, tmp);
	  }
	  TRACE("%s", buffer);
  }
  
  /* TODO: the return value here should be used, no? */
  TRACE("parsing the HID tree of USB device %s...", hidif->id);
  HIDParse(hidif->hid_parser, hidif->hid_data);

  NOTICE("successfully set up the HID parser for USB device %s.", hidif->id);

  return HID_RET_SUCCESS;
}

void hid_reset_parser(HIDInterface* const hidif)
{
  if (!hid_is_opened(hidif)) {
    ERROR("cannot prepare parser of unopened HIDinterface.");
    return;
  }
  ASSERT(hidif->hid_parser);
  
  TRACE("resetting the HID parser for USB device %s...", hidif->id);
  ResetParser(hidif->hid_parser);
}

hid_return hid_find_object(HIDInterface* const hidif,
    int const path[], unsigned int const depth)
{
  if (!hid_is_opened(hidif)) {
    ERROR("cannot prepare parser of unopened HIDinterface.");
    return HID_RET_DEVICE_NOT_OPENED;
  }
  ASSERT(hidif->hid_parser);
  ASSERT(hidif->hid_data);
  
  hid_prepare_parse_path(hidif, path, depth);

  if (FindObject(hidif->hid_parser, hidif->hid_data) == 1) {
    NOTICE("found requested item.");
    return HID_RET_SUCCESS;
  }

  byte const ITEMSIZE = sizeof("0xdeadbeef");
  char* buffer = (char*)malloc(depth * ITEMSIZE);
  hid_format_path(buffer, depth * ITEMSIZE, path, depth); 
  WARNING("can't find requested item %s of USB device %s.\n", buffer, hidif->id);
  free(buffer);
  
  return HID_RET_NOT_FOUND;
}

hid_return hid_extract_value(HIDInterface* const hidif,
    unsigned char *const buffer, double *const value)
{
  if (!hid_is_opened(hidif)) {
    ERROR("cannot extract value from unopened HIDinterface.");
    return HID_RET_DEVICE_NOT_OPENED;
  }
  ASSERT(hidif->hid_parser);
  ASSERT(hidif->hid_data);

  if (!buffer) {
    ERROR("cannot extract value from USB device %s into NULL raw buffer.",
        hidif->id);
    return HID_RET_INVALID_PARAMETER;
  }

  if (!value) {
    ERROR("cannot extract value from USB device %s into NULL value buffer.",
        hidif->id);
    return HID_RET_INVALID_PARAMETER;
  }
  
  TRACE("extracting data value...");

  /* Extract the data value */
  GetValue(buffer, hidif->hid_data);

  /* FIXME: unit conversion and exponent?! */
  *value = hidif->hid_data->Value;
	
  return HID_RET_SUCCESS;
}

hid_return hid_get_report_size(HIDInterface* const hidif,
    unsigned int const reportID, unsigned int const reportType,
    unsigned int *size)
{
  if (!hid_is_opened(hidif)) {
    ERROR("cannot get report size of unopened HIDinterface.");
    return HID_RET_DEVICE_NOT_OPENED;
  }
  ASSERT(hidif->hid_parser);
  ASSERT(hidif->hid_data);
  
  if (!size) {
    ERROR("cannot read report size from USB device %s into NULL size buffer.",
        hidif->id);
    return HID_RET_INVALID_PARAMETER;
  }
  
  /* FIXME: GetReportOffset has to be rewritten! */
  *size = *GetReportOffset(hidif->hid_parser, reportID, reportType);
	
  return HID_RET_SUCCESS;
}

hid_return hid_format_path(char* const buffer, unsigned int length,
    int const path[], unsigned int const depth)
{
  if (!buffer) {
    ERROR("cannot format path into NULL buffer.");
    return HID_RET_INVALID_PARAMETER;
  }

  byte const ITEMSIZE = sizeof("0xdeadbeef");
  unsigned int i = 0;

  TRACE("formatting device path...");
  for (; i < depth; ++i) {
    if (length < ITEMSIZE) {
      WARNING("not enough space in buffer to finish formatting of path.")
      return HID_RET_OUT_OF_SPACE;
    }
    snprintf(buffer + i * ITEMSIZE, ITEMSIZE + 1, "0x%08x.", path[i]);
    length -= ITEMSIZE;
  }
  buffer[i * ITEMSIZE - 1] = '\0';

  return HID_RET_SUCCESS;
}

/* COPYRIGHT --
 *
 * This file is part of libhid, a user-space HID access library.
 * libhid is (c) 2003-2005
 *   Martin F. Krafft <libhid@pobox.madduck.net>
 *   Charles Lepple <clepple@ghz.cc>
 *   Arnaud Quette <arnaud.quette@free.fr> && <arnaud.quette@mgeups.com>
 * and distributed under the terms of the GNU General Public License.
 * See the file ./COPYING in the source distribution for more information.
 *
 * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
 * OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */


syntax highlighted by Code2HTML, v. 0.9.1