/****************************************************************************
 * This file is part of the project AqHome.
 * AqHome (c) by 2024 Martin Preuss, all rights reserved.
 *
 * The license for this file can be found in the file COPYING which you
 * should have received along with this file.
 ****************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "./path.h"

#include <gwenhywfar/stringlist.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/debug.h>

#include <string.h>
#include <ctype.h>
#include <stdlib.h>



/* ------------------------------------------------------------------------------------------------
 * forward declarations
 * ------------------------------------------------------------------------------------------------
 */

static void *_handleElement(const char *element, void *data, uint32_t flags, AQH_PATH_HANDLERFN fn);
static void _getPathBetween(const char *path1, const char *path2, GWEN_BUFFER *diffBuf);



/* ------------------------------------------------------------------------------------------------
 * implementations
 * ------------------------------------------------------------------------------------------------
 */

void *AQH_Path_Handle(const char *path, void *data, uint32_t flags, const char *delimiters, AQH_PATH_HANDLERFN fn)
{
  if (path && *path) {
    GWEN_STRINGLIST *elementList;

    /* clear internal flags */
    flags&=~AQH_PATH_FLAGS_LAST;

    elementList=GWEN_StringList_fromString2(path, delimiters, 0, GWEN_TEXT_FLAGS_CHECK_BACKSLASH | GWEN_TEXT_FLAGS_DEL_QUOTES);
    if (elementList) {
      GWEN_STRINGLISTENTRY *se;

      se=GWEN_StringList_FirstEntry(elementList);
      while(se) {
	const char *s;
	GWEN_STRINGLISTENTRY *seNext;

	seNext=GWEN_StringListEntry_Next(se);
	if (seNext)
	  flags&=~AQH_PATH_FLAGS_LAST;
	else
	  flags|=AQH_PATH_FLAGS_LAST;
	s=GWEN_StringListEntry_Data(se);
	if (s && *s) {
	  void *result;

	  result=_handleElement(s, data, flags, fn);
	  if (result==NULL) {
	    DBG_INFO(NULL, "Error handling element \"%s\" (%08x)", s, flags);
	    GWEN_StringList_free(elementList);
	    return NULL;
	  }
	  data=result;
	}
	se=GWEN_StringListEntry_Next(se);
      }
      GWEN_StringList_free(elementList);
      return data;
    }
    else {
      DBG_INFO(NULL, "Error reading path \"%s\" into stringlist", path);
    }
  }
  else {
    DBG_ERROR(NULL, "Empty path given");
  }
  return NULL;
}



void *_handleElement(const char *element, void *data, uint32_t flags, AQH_PATH_HANDLERFN fn)
{
  if (flags & AQH_PATH_FLAGS_PARSEIDX) {
    const char *ptrOpenBracket;

    ptrOpenBracket=strchr(element, '[');
    if (ptrOpenBracket) {
      if (ptrOpenBracket!=element) {
	const char *s;
	int idx=0;

	s=ptrOpenBracket+1;
	while(*s && isdigit(*s)) {
	  idx*=10;
	  idx+=*s-'0';
	  s++;
	}
	if (*s!=']') {
	  DBG_ERROR(NULL, "Closed bracket expected (got \"%c\")", *s);
	  return NULL;
	}
	else {
	  char *rawElement;
	  void *result;

	  s++;
	  rawElement=GWEN_Text_strndup(element, ptrOpenBracket-element);
	  result=fn?fn(rawElement, data, idx, flags):data;
	  free(rawElement);
	  return result;
	}
      }
      else {
	DBG_ERROR(NULL, "Empty element with index");
	return NULL;
      }
    }
  }
  return fn(element, data, 0, flags);
}



int AQH_Path_GetPathBetween(const char *path1, const char *path2, GWEN_BUFFER *diffBuf)
{
  if (!(path1 && *path1)) {
    if (path2 && *path2) {
      GWEN_Buffer_AppendString(diffBuf, path2);
      return 0;
    }
    else {
      DBG_INFO(AQH_LOGDOMAIN, "Both paths are NULL.");
      return 0;
    }
  }

  if (!(path2 && *path2)) {
    GWEN_STRINGLIST *sl1;

    sl1=GWEN_StringList_fromString2(path1, "/", 0, GWEN_TEXT_FLAGS_DEL_QUOTES | GWEN_TEXT_FLAGS_CHECK_BACKSLASH);
    if (sl1) {
      int cnt;
      int i;

      cnt=GWEN_StringList_Count(sl1);
      for (i=0; i<cnt; i++) {
	if (i>0)
	  GWEN_Buffer_AppendString(diffBuf, "/");
	GWEN_Buffer_AppendString(diffBuf, "..");
      }
      GWEN_StringList_free(sl1);
      return 0;
    }
  }

  _getPathBetween(path1, path2, diffBuf);
  return 0;
}



void _getPathBetween(const char *path1, const char *path2, GWEN_BUFFER *diffBuf)
{
  GWEN_STRINGLIST *sl1;
  GWEN_STRINGLIST *sl2;
  GWEN_STRINGLISTENTRY *se;
  int count;
  int i;

  sl2=GWEN_StringList_fromString2(path2, "/", 0, GWEN_TEXT_FLAGS_DEL_QUOTES | GWEN_TEXT_FLAGS_CHECK_BACKSLASH);
  sl1=GWEN_StringList_fromString2(path1, "/", 0, GWEN_TEXT_FLAGS_DEL_QUOTES | GWEN_TEXT_FLAGS_CHECK_BACKSLASH);

  GWEN_StringList_RemoveCommonFirstEntries(sl1, sl2);

  count=GWEN_StringList_Count(sl1);
  for (i=0; i<count; i++) {
    if (GWEN_Buffer_GetUsedBytes(diffBuf))
      GWEN_Buffer_AppendString(diffBuf, "/");
    GWEN_Buffer_AppendString(diffBuf, "..");
  }
  GWEN_StringList_free(sl1);

  se=GWEN_StringList_FirstEntry(sl2);
  while(se) {
    const char *s;

    s=GWEN_StringListEntry_Data(se);
    if (s && *s) {
      if (GWEN_Buffer_GetUsedBytes(diffBuf))
        GWEN_Buffer_AppendString(diffBuf, "/");
      GWEN_Buffer_AppendString(diffBuf, s);
    }

    se=GWEN_StringListEntry_Next(se);
  }
  GWEN_StringList_free(sl2);
}



#include "./path-t.c"




