use token;
use roolang_regex;
use common::ParseError as ParseError;

mod test;

#[derive(Clone)]
#[derive(PartialEq)]
pub enum Constant {
    IntegerConst {value: i32},
    BooleanConst {value: bool},
    CharSeqConst {value: String},
    DecimalConst {value: f64}
}


pub fn get_constant(tokens: &Vec<token::Token>, start: usize) -> (Result<Constant, ParseError>, usize) {
    let first_token = &tokens[start].text;

    if roolang_regex::is_numeric(first_token) {
        return as_number(&tokens, start, false);
    } else if first_token == "-" {
        if tokens.len() < start + 1 {
            return bad_token(&tokens[start], "Unexcpected end");
        } else if roolang_regex::is_numeric(&tokens[start + 1].text) {
            return as_number(&tokens, start + 1, true);
        } else {
            return bad_token(&tokens[start], "Unexcpected token, expecting a number");
        }
    } else if roolang_regex::is_boolean(first_token) {
        return as_boolean(&tokens, start);
    } else if roolang_regex::is_string(first_token) {
        return as_string(&tokens, start);
    }
    return bad_token(&tokens[start], "Unexcpected token, expecting Int, Dec, String, Bool, or type");
}

fn as_number(tokens: &Vec<token::Token>, start: usize, negative: bool) -> (Result<Constant, ParseError>, usize) {
    let number = tokens[start].text.clone();


    if tokens.len() > start + 1 && &tokens[start + 1].text == "." {
        return as_decimal_number(&tokens, number, start + 2, negative);
    }

    let val = match number.parse::<i32>() {
        Ok(n) => if negative {n * -1} else {n},
        Err(_) => 0
    };

    return (Ok(Constant::IntegerConst {value: val}), start + 1);
}

fn as_decimal_number(tokens: &Vec<token::Token>, whole_number: String, start: usize, negative: bool) -> (Result<Constant, ParseError>, usize) {

    let mut number = whole_number.clone();
    number.push_str(".");
    if tokens.len() < start {
        return bad_token(&tokens[start], "Unexcpected end");
    } else if roolang_regex::is_numeric(&tokens[start].text) {
        number.push_str(&tokens[start].text);
    } else {
        return bad_token(&tokens[start], "Unexcpected token, expecting numeric value");
    }

    let val = match number.parse::<f64>() {
        Ok(n) => if negative {n * -1.0} else {n},
        Err(_) => 0.0
    };

    return (Ok(Constant::DecimalConst {value: val}), start + 1)
}

fn 
(tokens: &Vec<token::Token>, start: usize) -> (Result<Constant, ParseError>, usize) {
    return (Ok(Constant::BooleanConst {value: &tokens[start].text == "true"}), start + 1);
}

fn as_string(tokens: &Vec<token::Token>, start: usize) -> (Result<Constant, ParseError>, usize) {
    let mut val = tokens[start].text.clone();
    val.remove(tokens[start].text.len() - 1);
    val.remove(0);

    return (Ok(Constant::CharSeqConst{value: val.clone()}), start + 1);
}

fn bad_token(token: &token::Token, msg: &str) -> (Result<Constant, ParseError>, usize) {
    return (Err(ParseError::new(&token, msg)), 0);
}

as_boolean