#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "utils.h"

// http://c-faq.com/lib/randrange.html
int randint(int N) { return rand() / (RAND_MAX / N + 1); }

// http://c-faq.com/lib/randrange.html
// numbers in the range [M, N] could be generated with something like

int randrange(int M, int N) {
  return M + rand() / (RAND_MAX / (N - M + 1) + 1);
}

/**
 * Display a repr of the given string.
 *
 * This converts most \n\r\v\f\t codes,
 * defaults to \xHH (hex value).
 */
char *repr(const char *data) {
  static char buffer[40960];
  char *cp;

  strcpy(buffer, data);
  cp = buffer;
  while (*cp != 0) {
    char c = *cp;

    if (c == ' ') {
      cp++;
      continue;
    };
    /* Ok, it's form-feed ('\f'), newline ('\n'), carriage return ('\r'),
     * horizontal tab ('\t'), and vertical tab ('\v') */
    if (strchr("\f\n\r\t\v\?", c) != NULL) {
      memmove(cp + 1, cp, strlen(cp) + 1);
      *cp = '\\';
      cp++;
      switch (c) {
      case '\f':
        *cp = 'f';
        cp++;
        break;
      case '\n':
        *cp = 'n';
        cp++;
        break;
      case '\r':
        *cp = 'r';
        cp++;
        break;
      case '\t':
        *cp = 't';
        cp++;
        break;
      case '\v':
        *cp = 'v';
        cp++;
        break;
      default:
        *cp = '?';
        cp++;
        break;
      }
      continue;
    }

    if (c == '\\') {
      memmove(cp + 1, cp, strlen(cp) + 1);
      *cp = '\\';
      cp += 2;
      continue;
    }
    if (c == '"') {
      memmove(cp + 1, cp, strlen(cp) + 1);
      *cp = '\\';
      cp += 2;
      continue;
    }
    if (strchr("[()]{}:;,.<>?!@#$%^&*", c) != NULL) {
      cp++;
      continue;
    }
    if (strchr("0123456789", c) != NULL) {
      cp++;
      continue;
    }
    if (strchr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", c) !=
        NULL) {
      cp++;
      continue;
    }

    // Ok, default to \xHH output.
    memmove(cp + 3, cp, strlen(cp) + 1);
    char buffer[10];
    int slen;
    slen = snprintf(buffer, sizeof(buffer), "\\x%02x", (int)c & 0xff);
    /*
    if (slen >= sizeof(buffer)) {
      ZF_LOGE("snprintf %d > size %d", slen, (int)sizeof(buffer));
    }
    */
    strncpy(cp, buffer, 4);
    cp += 4;
    continue;
  }

  return buffer;
}

/*
 * strnstr()
 *
 * buffer safe version that looks for a string.
 */
const char *strnstr(const char *source, int len, const char *needle) {
  int pos;

  for (pos = 0; pos < len; pos++) {
    if (source[pos] == needle[0]) {
      if (strncmp(source + pos, needle, strlen(needle)) == 0) {
        return source + pos;
      }
    }
  }
  return NULL;
}

/*
 * rstrnstr() Reverse string find in a string
 *
 * This obeys the len, and handles nulls in buffer.
 * find is a c-string (null terminated)
 */
int rstrnstr(const char *buffer, int len, const char *find) {
  int flen = strlen(find);

  if (len < flen) {
    // I can't find a string in a buffer smaller then it is!
    return -1;
  }
  int pos = len - flen;
  while (pos > 0) {
    if (buffer[pos] == find[0]) {
      // First chars match, check them all.
      if (strncmp(buffer + pos, find, flen) == 0) {
        return pos;
      }
    }
    pos--;
  }
  return -1;
}

/*
 * string_insert()
 * Inserts a string into a given position.
 * This safely checks to make sure the buffer isn't overrun.
 *
 * buffer is a c null terminated string.
 */
int string_insert(char *buffer, int max_length, int pos, const char *insert) {
  /*
  assert(max_length > pos);
  assert(buffer != NULL);
  assert(insert != NULL);
  */
  if (pos >= max_length)
    return 0;
  if (buffer == NULL)
    return 0;
  if (insert == NULL)
    return 0;
  if (strlen(insert) == 0)
    return 0;
  if (pos > strlen(buffer))
    return 0;

  if (strlen(buffer) + strlen(insert) >= max_length) {
    /*
    ZF_LOGD("string_insert() failed inserting [%s]", repr(insert));
    */
    return 0;
  }
  memmove(buffer + pos + strlen(insert), buffer + pos,
          strlen(buffer + pos) + 1);
  // cp + strlen(display), cp, strlen(cp) + 1);
  strncpy(buffer + pos, insert, strlen(insert));
  // (cp, display, strlen(display));
  return 1; // success
}

/*
Pascal String Copy.  Copy from pascal string, to C String.

First char is pascal string length.  (Max 255).
 */
void pcopy(char *pstring, char *str) {
  int len = (int)*pstring;
  strncpy(str, pstring + 1, len);
  str[len] = 0;
}