#ifndef STR_H
#define STR_H

#include <stdlib.h>
#include <stddef.h>
#include <stdbool.h>

#include "da.h"

struct str {
	const char *data;
	size_t size;
};

DA_DEF_STRUCT(struct str, str_da);

struct str str_from_cstr(const char *cstr, size_t size);
struct str str_from_cstr_ns(const char *cstr);

struct str str_strip_left(struct str str);
struct str str_strip_right(struct str str);
struct str str_strip(struct str str);
struct str_da str_split(struct str str, char c);

bool str_eq(struct str str_a, struct str str_b);
bool str_eq_cstr(struct str str, const char *cstr, size_t size);
bool str_eq_cstr_ns(struct str str, const char *cstr);

bool str_contain_char(struct str str, char c);

#if defined(STR_IMP) || defined(IMP)


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

struct str
str_from_cstr(const char *cstr, size_t size)
{
	return (struct str) { .data=cstr, .size=size };
}

struct str
str_from_cstr_ns(const char *cstr)
{
	return str_from_cstr(cstr, strlen(cstr));
}

struct str
str_strip_left(struct str str)
{
	while ( isspace(*str.data) && str.size > 0 ) {
		++str.data;
		--str.size;
	}
	return str;
}

struct str
str_strip_right(struct str str)
{
	while ( isspace(str.data[str.size-1]) && str.size > 0 ) {
		--str.size;
	}
	return str;
}

struct str
str_strip(struct str str)
{
	return str_strip_right(str_strip_left(str));
}

struct str_da
str_split(struct str str, char c)
{
	struct str_da da = {0};
	DA_CREATE(da);

	struct str part = {
		.data = str.data,
	};
	for ( size_t i = 0; i < str.size; ++i ) {
		if ( str.data[i] == c ) {
			part.size = i - (size_t)(part.data - str.data);
			DA_APPEND(da, part);
			part.data += part.size+1;
		}
	}
	part.size = str.size - (size_t)(part.data - str.data);
	DA_APPEND(da, part);

	return da;
}

bool
str_eq(struct str str_a, struct str str_b)
{
	if ( str_a.size != str_b.size ) {
		return false;
	}
	for ( size_t i = 0; i < str_a.size; ++i ) {
		if ( str_a.data[i] != str_b.data[i] ) {
			return false;
		}
	}
	return true;
}

bool
str_eq_cstr(struct str str, const char *cstr, size_t size)
{
	return str_eq(str, str_from_cstr(cstr, size));
}

bool
str_eq_cstr_ns(struct str str, const char *cstr)
{
	return str_eq(str, str_from_cstr_ns(cstr));
}

bool
str_contain_char(struct str str, char c)
{
	for ( size_t i = 0; i < str.size; ++i ) {
		if ( str.data[i] == c ) {
			return true;
		}
	}
	return false;
}


#endif /* defined(STR_IMP) || defined(IMP) */

#endif
