typedef struct BuildContext {
	String ODIN_OS;      // target operating system
	String ODIN_ARCH;    // target architecture
	String ODIN_VENDOR;  // compiler vendor
	String ODIN_VERSION; // compiler version
	String ODIN_ROOT;    // Odin ROOT

	i64    word_size;
	i64    max_align;
	String llc_flags;
	String link_flags;
} BuildContext;

// TODO(bill): OS dependent versions for the BuildContext
// join_path
// is_dir
// is_file
// is_abs_path
// has_subdir

String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
String const NIX_SEPARATOR_STRING   = {cast(u8 *)"/",  1};

String odin_root_dir(void) {
	String path = global_module_path;
	Array(wchar_t) path_buf;
	isize len, i;
	gbTempArenaMemory tmp;
	wchar_t *text;

	if (global_module_path_set) {
		return global_module_path;
	}

	array_init_count(&path_buf, heap_allocator(), 300);

	len = 0;
	for (;;) {
		len = GetModuleFileNameW(NULL, &path_buf.e[0], path_buf.count);
		if (len == 0) {
			return make_string(NULL, 0);
		}
		if (len < path_buf.count) {
			break;
		}
		array_resize(&path_buf, 2*path_buf.count + 300);
	}

	tmp = gb_temp_arena_memory_begin(&string_buffer_arena);

	text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);

	GetModuleFileNameW(NULL, text, len);
	path = string16_to_string(heap_allocator(), make_string16(text, len));
	for (i = path.len-1; i >= 0; i--) {
		u8 c = path.text[i];
		if (c == '/' || c == '\\') {
			break;
		}
		path.len--;
	}

	global_module_path = path;
	global_module_path_set = true;

	gb_temp_arena_memory_end(tmp);

	array_free(&path_buf);

	return path;
}

String path_to_fullpath(gbAllocator a, String s) {
	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
	String16 string16 = string_to_string16(string_buffer_allocator, s);
	String result = {0};

	DWORD len = GetFullPathNameW(string16.text, 0, NULL, NULL);
	if (len != 0) {
		wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
		GetFullPathNameW(string16.text, len, text, NULL);
		text[len] = 0;
		result = string16_to_string(a, make_string16(text, len));
	}
	gb_temp_arena_memory_end(tmp);
	return result;
}


String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
	String res = {0};
	isize str_len = base_dir.len+path.len;

	u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);

	isize i = 0;
	gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len;
	gb_memmove(str+i, path.text, path.len);
	str[str_len] = '\0';
	res = path_to_fullpath(a, make_string(str, str_len));
	gb_free(heap_allocator(), str);
	return res;
}

String get_fullpath_core(gbAllocator a, String path) {
	String module_dir = odin_root_dir();
	String res = {0};

	char core[] = "core/";
	isize core_len = gb_size_of(core)-1;

	isize str_len = module_dir.len + core_len + path.len;
	u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);

	gb_memmove(str, module_dir.text, module_dir.len);
	gb_memmove(str+module_dir.len, core, core_len);
	gb_memmove(str+module_dir.len+core_len, path.text, path.len);
	str[str_len] = '\0';

	res = path_to_fullpath(a, make_string(str, str_len));
	gb_free(heap_allocator(), str);
	return res;
}


String get_filepath_extension(String path) {
	isize dot = 0;
	bool seen_slash = false;
	for (isize i = path.len-1; i >= 0; i--) {
		u8 c = path.text[i];
		if (c == '/' || c == '\\') {
			seen_slash = true;
		}

		if (c == '.') {
			if (seen_slash) {
				return str_lit("");
			}

			dot = i;
			break;
		}
	}
	return make_string(path.text, dot);
}



void init_build_context(BuildContext *bc) {
	bc->ODIN_VENDOR  = str_lit("odin");
	bc->ODIN_VERSION = str_lit("0.0.3d");
	bc->ODIN_ROOT    = odin_root_dir();

#if defined(GB_SYSTEM_WINDOWS)
	bc->ODIN_OS      = str_lit("windows");
	bc->ODIN_ARCH    = str_lit("amd64");
#else
#error Implement system
#endif

	if (str_eq(bc->ODIN_ARCH, str_lit("amd64"))) {
		bc->word_size = 8;
		bc->max_align = 16;
		bc->llc_flags = str_lit("-march=x86-64 ");
		bc->link_flags = str_lit("/machine:x64 ");
	} else if (str_eq(bc->ODIN_ARCH, str_lit("x86"))) {
		bc->word_size = 4;
		bc->max_align = 8;
		bc->llc_flags = str_lit("-march=x86 ");
		bc->link_flags = str_lit("/machine:x86 ");
	}
}
