/*
 * str_replace.c
 *
 * TODO: Add the ability to replace from the end
 *
 * Author: Intel A80486DX2-66
 * License: Creative Commons Zero 1.0 Universal or Unlicense
 * SPDX-License-Identifier: CC0-1.0 OR Unlicense
 */

#include "str_replace.h"

char* str_replace(
  const char* str,
  const char* substr,
  const char* replacement,
  size_t max_count,
  bool direction
) {
	/*
	 * input arguments:
	 * 	max_count: N <= 0 for all replacements, N > 0 for N replacement
	 *
	 * the output string should be freed!
	 */
	size_t substr_len = strlen(substr),
	       replacement_len = strlen(replacement),
	       count = 0;

	if (direction == STR_REPLACE_DIR_BACKWARD) {
		// TODO: implement replacing from the end
		fprintf(stderr, "str_replace, STR_REPLACE_DIR_BACKWARD: Work in "
		                "progress\n");
		return str_replace(str, substr, replacement, max_count,
		                   STR_REPLACE_DIR_FORWARD);
	}

	const char* p = str;

	// count the number of occurrences of the substring
	for (; (p = strstr(p, substr)) != NULL; count++) {
		if (max_count > 0 && count >= (size_t) max_count)
			break;
		p += substr_len;
	}

	// allocate a buffer to hold the modified string
	size_t new_len = strlen(str) + count * (replacement_len - substr_len);

	char* result = malloc((new_len + 1) * sizeof(char));
	if (result == NULL)
		return NULL;

	const char* q = str;
	char* r = result;
	for (; (p = strstr(q, substr)) != NULL && count > 0; count--) {
		size_t len = p - q;
		memcpy(r, q, len);
		r += len;
		memcpy(r, replacement, replacement_len);
		r += replacement_len;
		q = p + substr_len;
	}
	strcpy(r, q);

	return result;
}

#ifdef TEST
# include <stdint.h>
# include <stdio.h>

uintmax_t tests_failed = 0;

static void func_expect(
  const char* str,
  const char* substr,
  const char* replacement,
  size_t max_count,
  bool direction,
  const char* expected_output
);

static void func_expect(
  const char* str,
  const char* substr,
  const char* replacement,
  size_t max_count,
  bool direction,
  const char* expected_output
) {
	char* result = str_replace(str, substr, replacement, max_count, direction);
	if (result == NULL) {
		perror("str_replace");
		exit(EXIT_FAILURE);
	}

	if (strcmp(result, expected_output)) {
		puts("Failed!\n");
		tests_failed++;
		return;
	}

	puts("Passed\n");
}

int main(void) {
	func_expect("Hello; peace! This is a peaceful test.",
	            "; peace",
	            ", universe",
	            STR_REPLACE_ALL,
	            STR_REPLACE_DIR_FORWARD,
	            "Hello, universe! This is a peaceful test.");
	const char* str = "Hello; peace! This is a peaceful test.",
	          * substr = "peace",
	          * replacement1 = "universe",
	          * replacement2 = "_____";

	char* result1 = str_replace(str, substr, replacement1, STR_REPLACE_ALL,
	                            STR_REPLACE_DIR_FORWARD),
	    * result2 = str_replace(str, substr, replacement2, 1,
	                            STR_REPLACE_DIR_FORWARD);

	puts(result1); free(result1);
	puts(result2); free(result2);

	return 0;
}
#endif