/*  Tux Commandern VFS: String utilities
 *  Copyright (C) 2007 Tomas Bzatek <tbzatek@users.sourceforge.net>
 *   Check for updates on tuxcmd.sourceforge.net
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "strutils.h"


char* include_trailing_path_sep(const char *APath)
{
  if (APath == NULL) return NULL;
  char *ANewPath;
//  log("xxx = %s\n", (APath + strlen(APath) - 1));
  if (strcmp(APath + strlen(APath) - 1, "/") != 0) {
    ANewPath = (char*)malloc(strlen(APath) + 2);
    snprintf(ANewPath, strlen(APath) + 2, "%s/", APath);
  } else ANewPath = strdup(APath);
  return ANewPath;
}

char* exclude_trailing_path_sep(const char *APath)
{
  if (APath == NULL) return NULL;
  char *ANewPath;
//  log("orig = %s, len = %d, xxx = %s\n", APath, (int)strlen(APath), (APath + strlen(APath) - 1));
  if ((strcmp(APath + strlen(APath) - 1, "/") == 0) && (strlen(APath) > 1)) {
    ANewPath = (char*)malloc(strlen(APath));
    snprintf(ANewPath, strlen(APath), "%s", APath);  //  The number of bytes copied includes the trailing \0
  } else ANewPath = strdup(APath);
  return ANewPath;
}

char* include_leading_path_sep(const char *APath)
{
  if (APath == NULL) return NULL;
  char *ANewPath;
//  log("xxx = %s, %lu, strlen(APath) = %d, index() = %ld\n", APath, (unsigned long int)APath, (int)strlen(APath), (unsigned long int)index(APath, 0x2f));
  if (index(APath, 0x2f) != APath) {
    ANewPath = (char*)malloc(strlen(APath) + 2);
    snprintf(ANewPath, strlen(APath) + 2, "/%s", APath);    //  The number of bytes copied includes the trailing \0
  } else ANewPath = strdup(APath);
  return ANewPath;
}

char* exclude_leading_path_sep(const char* APath)
{
  if (APath == NULL) return NULL;
  char *s = strdup(APath);
  char *ss;
  if (IS_DIR_SEP(*s)) ss = strdup(s + 1); else ss = strdup(s);
  free(s);
  return ss;
}


char* extract_file_name(const char *APath)
{
  if (APath == NULL) return NULL;
//  log("xxx = %s\n", (APath + strlen(APath) - 1));
  const char *file_part = rindex(APath, 0x2f);   //  returns NULL if not found or if the file is in the root ( / )
  if (file_part == NULL) return NULL;
  return strdup(file_part + 1);
}

//  Extracts file path starting with "/" and ending with "/"
char* extract_file_path(const char *APath)
{
  if (APath == NULL) return NULL;
//  log("xxx = %s\n", (APath + strlen(APath) - 1));
  const char *file_part = rindex(APath, 0x2f);   //  returns NULL if not found or if the file is in the root ( / )
  if (file_part == NULL) return NULL;
  char *ANewPath = (char*)malloc(file_part - APath + 2);
  snprintf(ANewPath, file_part - APath + 2, "%s", APath);
  return ANewPath;
}








//  canonicalize_filename() is stolen from glib-2.16
//  Copyright (C) 2006-2007 Alexander Larsson <alexl@redhat.com>
char *
canonicalize_filename (const char *filename)
{
  char *canon, *start, *p, *q;
  int i;

  canon = g_strdup (filename);

  start = (char *)g_path_skip_root (canon);
  if (start == NULL)  start = canon;

  /* POSIX allows double slashes at the start to
   * mean something special (as does windows too).
   * So, "//" != "/", but more than two slashes
   * is treated as "/".
   */
  i = 0;
  for (p = start - 1;
       (p >= canon) &&
	 G_IS_DIR_SEPARATOR (*p);
       p--)
    i++;
  if (i > 2)
    {
      i -= 1;
      start -= i;
      memmove (start, start+i, strlen (start+i)+1);
    }

  p = start;
  while (*p != 0)
    {
      if (p[0] == '.' && (p[1] == 0 || G_IS_DIR_SEPARATOR (p[1])))
	{
	  memmove (p, p+1, strlen (p+1)+1);
	}
      else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 || G_IS_DIR_SEPARATOR (p[2])))
	{
	  q = p + 2;
	  /* Skip previous separator */
	  p = p - 2;
	  if (p < start)
	    p = start;
	  while (p > start && !G_IS_DIR_SEPARATOR (*p))
	    p--;
	  if (G_IS_DIR_SEPARATOR (*p))
	    *p++ = G_DIR_SEPARATOR;
	  memmove (p, q, strlen (q)+1);
	}
      else
	{
	  /* Skip until next separator */
	  while (*p != 0 && !G_IS_DIR_SEPARATOR (*p))
	    p++;

	  if (*p != 0)
	    {
	      /* Canonicalize one separator */
	      *p++ = G_DIR_SEPARATOR;
	    }
	}

      /* Remove additional separators */
      q = p;
      while (*q && G_IS_DIR_SEPARATOR (*q))
	q++;

      if (p != q)
	memmove (p, q, strlen (q)+1);
    }

  /* Remove trailing slashes */
  if (p > start && G_IS_DIR_SEPARATOR (*(p-1)))
    *(p-1) = 0;

  return canon;
}


char* resolve_relative(const char *source, const char *point_to)
{
  if (source == NULL) return NULL;
  if (point_to == NULL) return strdup(source);
  if (g_path_is_absolute(point_to)) return strdup(point_to);

  char *rel = g_build_filename(source, point_to, NULL);
  log("resolve_relative: rel = '%s'\n", rel);
  char *canon = canonicalize_filename(rel);
  log("resolve_relative: canon = '%s'\n", canon);
  free(rel);

  return canon;
}



//  Originally stolen from wine-0.9.19, utf8.c
//  Copyright 2000 Alexandre Julliard
char*
wide_to_utf8 (const wchar_t *src)
{
#define CONV_BUFF_MAX 32768
  int len;
  char *buf, *dst, *ret;

  buf = (char *) malloc (CONV_BUFF_MAX);
  memset (&buf[0], 0, CONV_BUFF_MAX);
  dst = buf;

  if (src)
  for (len = CONV_BUFF_MAX; *src; src++)
  {
      wchar_t ch = *src;

      if (ch < 0x80)  /* 0x00-0x7f: 1 byte */
      {
          if (!len--) {
            log ("wide_to_utf8: error converting input string, overflow.\n");
            break;  /* overflow */
          }
          *dst++ = ch;
          continue;
      }

      if (ch < 0x800)  /* 0x80-0x7ff: 2 bytes */
      {
          if ((len -= 2) < 0) {
            log ("wide_to_utf8: error converting input string, overflow.\n");
            break;  /* overflow */
          }
          dst[1] = 0x80 | (ch & 0x3f);
          ch >>= 6;
          dst[0] = 0xc0 | ch;
          dst += 2;
          continue;
      }

      /* 0x800-0xffff: 3 bytes */
      if ((len -= 3) < 0) {
        log ("wide_to_utf8: error converting input string, overflow.\n");
        break;  /* overflow */
      }
      dst[2] = 0x80 | (ch & 0x3f);
      ch >>= 6;
      dst[1] = 0x80 | (ch & 0x3f);
      ch >>= 6;
      dst[0] = 0xe0 | ch;
      dst += 3;
  }

  ret = g_strdup (buf);
  free (buf);
  return ret;
}
