use std::fs;

use parser::ASTPart;

mod lexer;
mod parser;

fn log_ast_part(part: &ASTPart, prefix: String) {
    match part {
        ASTPart::Number(number) => println!("{}{}: Number: {}", prefix, number.pos, number.value),
        ASTPart::String(str) => println!("{}{}: String: {}", prefix, str.pos, str.value),
        ASTPart::Boolean(bool) => println!("{}{}: Boolean: {}", prefix, bool.pos, bool.value),
        ASTPart::Null(null) => println!("{}{}: Null", prefix, null.pos),
        ASTPart::Assigment(assigment) => {
            println!("{}{}: Assigment: {}", prefix, assigment.pos, assigment.variable);
            println!("{} Value:", prefix);
            log_ast_part(&assigment.value, format!("{}  ", prefix));
        },
        ASTPart::VarUpdate(v_update) => {
            println!("{}{}: Update: {}", prefix, v_update.pos, v_update.variable);
            println!("{} Value:", prefix);
            log_ast_part(&v_update.value, format!("{}  ", prefix));
        },
        ASTPart::Operation(operation) => {
            println!("{}{}: Operation: {}", prefix, operation.pos, operation.operator);
            println!("{} Left:", prefix);
            log_ast_part(&operation.left, format!("{}  ", prefix));
            println!("{} Right:", prefix);
            log_ast_part(&operation.right, format!("{}  ", prefix));
        },
        ASTPart::VarRead(var_read) => println!("{}{}: Variable Read: {}", prefix, var_read.pos, var_read.variable),
        ASTPart::Call(call) => {
            println!("{}{}: Call:", prefix, call.pos);
            println!("{} Function:", prefix);
            log_ast_part(&call.function, format!("{}  ", prefix));
            println!("{} Args:", prefix);
            for arg in &call.args {
                log_ast_part(&arg, format!("{}  ", prefix));
            }
        },
        ASTPart::Function(func) => {
            println!("{}{}: Function:", prefix, func.pos);
            println!("{} Args: {}", prefix, func.args.join(", "));
            println!("{} Body:", prefix);
            for part in &func.body {
                log_ast_part(part, format!("{}  ", prefix));
            }
        },
        ASTPart::If(if_part) => {
            println!("{}{}: If:", prefix, if_part.pos);
            println!("{} Condition:", prefix);
            log_ast_part(&if_part.condition, format!("{}  ", prefix));
            println!("{} Body:", prefix);
            for part in &if_part.body {
                log_ast_part(part, format!("{}  ", prefix));
            }
        },
        ASTPart::While(while_part) => {
            println!("{}{}: While:", prefix, while_part.pos);
            println!("{} Condition:", prefix);
            log_ast_part(&while_part.condition, format!("{}  ", prefix));
            println!("{} Body:", prefix);
            for part in &while_part.body {
                log_ast_part(part, format!("{}  ", prefix));
            }
        },
        ASTPart::Break(brk) => println!("{}{}: Break", prefix, brk.pos),
        ASTPart::For(fr) => {
            println!("{}{}: For:", prefix, fr.pos);
            println!("{} Init:", prefix);
            log_ast_part(&fr.init, format!("{}  ", prefix));
            println!("{} Condition:", prefix);
            log_ast_part(&fr.condition, format!("{}  ", prefix));
            println!("{} Update:", prefix);
            log_ast_part(&fr.update, format!("{}  ", prefix));
            println!("{} Body:", prefix);
            for part in &fr.body {
                log_ast_part(part, format!("{}  ", prefix));
            }
        },
        ASTPart::Continue(cnt) => println!("{}{}: Continue", prefix, cnt.pos),
        ASTPart::NOOP => println!("{}NOOP", prefix)
    }
}

fn main() {
    let inp = fs::read_to_string("./test.as");
    match inp {
        Result::Ok(data) => {
            let lexed = lexer::lex(data);
            println!("Lexer output: ");
            for token in &lexed {
                println!("  {}: {:?}: {}", token.pos, token.typ, token.value);
            }
            let ast = parser::parse(lexed);
            println!("AST: ");
            for part in &ast {
                log_ast_part(part, String::from("  "));
            }
        },
        Result::Err(err) => {
            panic!("Error while reading file: {}", err)
        }
    }
}