package os2

import "core:io"

General_Error :: enum u32 {
	Invalid_Argument,

	Permission_Denied,
	Exist,
	Not_Exist,
	Closed,

	Timeout,
}

Platform_Error :: struct {
	err: i32,
}

Error :: union {
	General_Error,
	io.Error,
	Platform_Error,
}
#assert(size_of(Error) == size_of(u64))

Path_Error :: struct {
	op:   string,
	path: string,
	err:  Error,
}

Link_Error :: struct {
	op:  string,
	old: string,
	new: string,
	err: Error,
}

path_error_delete :: proc(perr: Maybe(Path_Error)) {
	if err, ok := perr.?; ok {
		context.allocator = error_allocator()
		delete(err.op)
		delete(err.path)
	}
}

link_error_delete :: proc(lerr: Maybe(Link_Error)) {
	if err, ok := lerr.?; ok {
		context.allocator = error_allocator()
		delete(err.op)
		delete(err.old)
		delete(err.new)
	}
}



is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) {
	v := ferr.(Platform_Error) or_else {}
	return v.err, v.err != 0
}


error_string :: proc(ferr: Error) -> string {
	switch ferr {
	case nil:                return ""
	case .Invalid_Argument:  return "invalid argument"
	case .Permission_Denied: return "permission denied"
	case .Exist:             return "file already exists"
	case .Not_Exist:         return "file does not exist"
	case .Closed:            return "file already closed"
	case .Timeout:           return "i/o timeout"
	case .EOF:               return "eof"
	case .Unexpected_EOF:    return "unexpected eof"
	case .Short_Write:       return "short write"
	case .Invalid_Write:     return "invalid write result"
	case .Short_Buffer:      return "short buffer"
	case .No_Progress:       return "multiple read calls return no data or error"
	case .Invalid_Whence:    return "invalid whence"
	case .Invalid_Offset:    return "invalid offset"
	case .Invalid_Unread:    return "invalid unread"
	case .Negative_Read:     return "negative read"
	case .Negative_Write:    return "negative write"
	case .Negative_Count:    return "negative count"
	case .Buffer_Full:       return "buffer full"
	}

	if errno, ok := is_platform_error(ferr); ok {
		return _error_string(errno)
	}

	return "unknown error"
}
