/* Copyright (c) 2005-2007 DN-Systems GmbH http://rfdump.org

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */

/* $Header: /cvs/rfdump/src/tagtypes.c,v 1.11 2007/10/31 21:59:27 dirk Exp $ */

#include <errno.h>
#include <expat.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <glib.h>

#include "tagtypes.h"
#include "tools.h"

static char buff[32000];
static int depth;
static struct RFIDTagType **tmpTagTypes;
static char element[255];
static int idx;
static int idxMax;

static void XMLCALL start(void *data, const char *el, const char **attr)
{
  int i;

  //for (i = 0; i < depth; i++)
  //printf("  ");

  //printf("el:%s (%d)", el, depth);

  strcpy(element, el);

  for (i = 0; attr[i]; i += 2)
    {
      //printf(" %s='%s'", attr[i], attr[i+1]);

      if (!strcmp(attr[i], "id"))
	{
	  struct RFIDTagType *tmpTagType = (struct RFIDTagType*)calloc(1, sizeof(struct RFIDTagType));
	  strcpy(tmpTagType->tagTypeID, attr[i+1]);
	  strcpy(tmpTagType->tagTypeName, "");
	  strcpy(tmpTagType->tagManufacturerName, "");
	  if(idx+1<idxMax)
	    tmpTagTypes[++idx] = tmpTagType;
	}
    }

  //printf("\n");
  depth++;
}

static void XMLCALL content(void *data, const char *s, int len)
{
  if (len > 0)
    {
      char *textinfo = g_malloc(len+1);
      strncpy(textinfo, s, len);
      textinfo[len] = '\0';

      // strip white spaces
      int strip = 1;
      while (strip)
	{
	  const char c = textinfo[strlen(textinfo)-1];
	  if (c == ' ' || c == '\t' || c == '\n')
	    textinfo[strlen(textinfo)-1] = '\0';
	  else
	    strip = 0;
	}

      if (strlen(textinfo)>0)
	{
	  //printf("text:'%s' (%d)\n", textinfo, depth);

	  if (depth==3 && idx<idxMax)
	    {
	      struct RFIDTagType *tmpTagType=tmpTagTypes[idx];
	      if (!strcmp(element, "rfd:tagTypeName"))
		strcpy(tmpTagType->tagTypeName, textinfo);
	      else if (!strcmp(element, "rfd:tagManufacturerName"))
		strcpy(tmpTagType->tagManufacturerName, textinfo);
	      else if (!strcmp(element, "rfd:tagPageSize"))
		tmpTagType->pageSize=strtoul(textinfo, 0, 0);
	      else if (!strcmp(element, "rfd:tagMemSize"))
		tmpTagType->memSize=strtoul(textinfo, 0, 0);
	    }
	}

      g_free(textinfo);
    }
}

static void XMLCALL end(void *data, const char *el)
{
  depth--;
}

static char* rfd_types_fn()
{
  char *fn[] = {
    "rfd_types.xml",
    "/usr/share/rfdump/rfd_types.xml",
    "/usr/local/share/rfdump/rfd_types.xml",
  };
  int i;
  for(i=0; i<sizeof_array(fn); ++i)
    if(access(fn[i], R_OK) == 0)
      return fn[i];
  return 0;
}

int readTagTypes(struct RFIDTagType **tagTypes, const int max_)
{
  /* get filename */
  char *fn=rfd_types_fn();
  if(!fn)
    {
      fprintf(stderr, "did not find rfd_types.xml\n");
      return -1;
    }
  /* read whole file into buff */
  FILE *fp=fopen(fn,"r");
  if (!fp)
    {
      fprintf(stderr, "Error opening file %s: %s\n", fn, strerror(errno));
      return -1;
    }

  const int len = fread(buff, 1, sizeof(buff), fp);

  if (ferror(fp))
    {
      fprintf(stderr, "Read error: %s\n", strerror(errno));
      fclose(fp);
      return -1;
    }

  fclose(fp);

  idx = -1;
  idxMax=max_;

  int i;
  for (i=0; i<idxMax; i++)
    tagTypes[i] = NULL;

  tmpTagTypes = tagTypes;

  XML_Parser p = XML_ParserCreate(NULL);
  if (!p)
    {
      fprintf(stderr, "Couldn't allocate memory for parser\n");
      return -1;
    }

  XML_SetElementHandler(p, start, end);
  XML_SetCharacterDataHandler(p, content);

  int done=0;
  if (XML_Parse(p, buff, len, done) == XML_STATUS_ERROR)
    {
      fprintf(stderr, "Parse error at line %d:\n%s\n", (int)XML_GetCurrentLineNumber(p), XML_ErrorString(XML_GetErrorCode(p)));
      return -1;
    }

  return idx;
}

int getTagType(char *id, struct RFIDTagType **tagTypes)
{
  int idx = 0;

  while (tagTypes[idx] != NULL)
    {
      int match = 1;
      const int len=strlen(tagTypes[idx]->tagTypeID);

      int i;
      for (i=0; id[i] && i<len; ++i)
	{
	  const char c=tagTypes[idx]->tagTypeID[i];
	  if (c != '?' && c != id[i])
	    {
	      match = 0;
	      break;
	    }
	}

      if (match)
	return idx;

      idx++;
    }

  return -1;
}
