use crate::error::{Error, ErrorType};

#[derive(Debug)]
pub enum Token {
    Identifier(String),
    Section(String),
    Newline,
    Assign,

    Int(i64),
    Float(f64),
    StringVal(String),
    Bool(bool),
}

pub fn generate_tokens(source: String) -> Result<Vec<Token>, Error> {
    let mut tokens: Vec<Token> = Vec::new();
    let chars: Vec<char> = source.chars().collect();
    let mut index: usize = 0;

    while index < chars.len() {
        let current_character = chars[index];

        if current_character == '\n' {
            tokens.push(Token::Newline);
            index += 1;
        }

        else if current_character == ' ' {
            tokens.push(Token::Assign);
            index += 1;
        }

        else if current_character.is_alphabetic() {
            let mut buffer = String::new();

            while index < chars.len()
                && (chars[index].is_alphanumeric() || chars[index] == '_')
            {
                buffer.push(chars[index]);
                index += 1;
            }

            tokens.push(Token::Identifier(buffer));
        }

        else if current_character.is_numeric() {
            let mut number_string = String::new();

            while index < chars.len() &&
                  (chars[index].is_numeric() || chars[index] == '.') {

                number_string.push(chars[index]);
                index += 1;
            }

            let dot_count = number_string.chars()
                .filter(|&c| c == '.')
                .count();

            if dot_count == 0 {
                tokens.push(Token::Int(number_string.parse().unwrap()));
            }
            else if dot_count == 1 {
                tokens.push(Token::Float(number_string.parse().unwrap()));
            }
            else {
                return Err(Error {
                    error_type: ErrorType::IllegalCharacterError,
                    description: "Too many dots in float".to_string(),
                });
            }
        }

        else {
            return Err(Error {
                error_type: ErrorType::IllegalCharacterError,
                description: format!("Illegal character: {}", current_character),
            });
        }
    }

    Ok(tokens)
}