// stdlib.slg

#[builtin(Exit)]
pub fn exit(status_code: int) {}

#[builtin(Print)]
pub fn print(msg: string) {}
pub fn println(msg: string) { print(msg + "\n") }

#[builtin(IntToString)]
pub fn int_to_string(number: int) -> string {}

#[builtin(StringPushChar)]
pub fn string_push_char(str: string, value: int) -> string {}
#[builtin(StringCharAt)]
pub fn string_char_at(str: string, index: int) -> int {}
#[builtin(StringLength)]
pub fn string_length(str: string) -> int {}
#[builtin(StringToInt)]
pub fn string_to_int(str: string) -> int {}

#[builtin(ArrayNew)]
pub fn array_new<T>() -> [T] {}
#[builtin(ArrayPush)]
pub fn array_push<T>(array: [T], value: T) {}
#[builtin(ArrayLength)]
pub fn array_length<T>(array: [T]) -> int {}
#[builtin(ArrayAt)]
pub fn array_at<T>(array: [T], index: int) -> T {}

#[builtin(StructNew)]
pub fn struct_new<S>() -> S {}
#[builtin(StructSet)]
pub fn struct_set<S, T>(subject: S, value: T) {}

#[builtin(FileOpen)]
pub fn file_open(filename: string, mode: string) -> int {}
#[builtin(FileClose)]
pub fn file_close(file: int) {}
#[builtin(FileWriteString)]
pub fn file_write_string(file: int, content: string) -> int {}
#[builtin(FileReadChar)]
pub fn file_read_char(file: int) -> int {}
#[builtin(FileReadToString)]
pub fn file_read_to_string(file: int) -> string {}
#[builtin(FileFlush)]
pub fn file_flush(file: int) {}
#[builtin(FileEof)]
pub fn file_eof(file: int) -> bool {}

#[builtin(IntToString)]
pub fn itos(number: int) -> string {}
#[builtin(StringToInt)]
pub fn stoi(str: string) -> int {}

pub fn ctos(ch: int) -> string { string_push_char("", ch) }

pub fn stdin() -> int { 0 }
pub fn stdout() -> int { 1 }
pub fn stderr() -> int { 2 }

pub fn file_read_line(file: int) -> string {
    let line = "";
    loop {
        if file_eof(file) {
            break;
        }
        let ch = file_read_char(file);
        if ch == "\n"[0] {
            break;
        }
        line = string_push_char(line, ch);
    }
    line
}

pub fn read_text_file(filename: string) -> string {
    let file = file_open(filename, "r");
    let text = file_read_to_string(file);
    file_close(file);
    text
}

pub fn input(prompt: string) -> string {
    print(prompt);
    file_flush(stdout());
    file_read_line(stdin())
}

pub fn string_abs(number: int) -> int {
    let result = number;
    if number < 0 {
        result = number - (number * 2);
    }
    result
}

pub fn string_split(str: string, seperator: int) -> [string] {
    let result = array_new::<string>();

    let i = 0;
    let current_str = "";
    loop {
        if i >= string_length(str) {
            break;
        }
        let char = str[i];
        if char == seperator {
            array_push(result, current_str);
            current_str = "";
        } else {
            current_str = string_push_char(current_str, char);
        }
        i = i + 1;
    }
    array_push(result, current_str);
    result
}

pub fn string_slice(str: string, from: int, to: int) -> string {
    let result = "";
    let i = from;
    loop {
        if i >= string_length(str) {
            break;
        }
        if i >= to {
            break;
        }
        result = string_push_char(result, str[i]);
        i = i + 1;
    }
    result
}

pub fn string_contains(str: string, ch: int) -> bool {
    let len = string_length(str);
    for (let i = 0; i < len; i += 1) {
        if str[i] == ch {
            return true;
        }
    }
    false
}

pub fn array_clone<T>(array: [T]) -> [T] {
    let len = array_length(array);
    let result = array_new::<T>();
    let i = 0;
    loop {
        if i >= len { break; }
        array_push(result, array[i]);
        i = 1 + 1;
    }
    result
}

pub fn array_sort_mut(array: [int]) {
    let len = array_length(array);
    for (let i = 0; i < len; i += 1) {
        for (let j = i + 1; j < len; j += 1) {
            if array[j] < array[i] {
                let tmp = array[j];
                array[j] = array[i];
                array[i] = tmp;
            }
        }
    }
}

pub fn array_to_sorted(array: [int]) -> [int] {
    let cloned = array_clone(array);
    array_sort_mut(array);
    cloned
}

pub fn assert(value: bool, msg: string) {
    if not value {
        println("assertion failed: " + msg);
        exit(1);
    }
}