use logos::{Lexer, Logos};
use crate::ParseResult;

#[derive(Logos, Debug, PartialEq, Copy, Clone)]
pub enum C1Token {
    #[token("bool")]
    KwBoolean,

    #[token("do")]
    KwDo,

    #[token("else")]
    KwElse,

    #[token("float")]
    KwFloat,

    #[token("for")]
    KwFor,

    #[token("if")]
    KwIf,

    #[token("int")]
    KwInt,

    #[token("printf")]
    KwPrintf,

    #[token("return")]
    KwReturn,

    #[token("void")]
    KwVoid,

    #[token("while")]
    KwWhile,

    #[token("+")]
    Plus,

    #[token("-")]
    Minus,

    #[token("*")]
    Asterisk,

    #[token("/")]
    Slash,

    #[token("=")]
    /// =
    Assign,

    #[token("==")]
    /// ==
    Equal,

    #[token("!=")]
    /// !=
    NotEqual,

    #[token("<")]
    /// <
    Less,

    #[token(">")]
    /// >
    Greater,

    #[token("<=")]
    /// <=
    LessEqual,

    #[token(">=")]
    /// >=
    GreaterEqual,

    #[token("&&")]
    /// &&
    And,

    #[token("||")]
    /// ||
    Or,

    #[token(",")]
    Comma,

    #[token(";")]
    Semicolon,

    #[token("(")]
    /// (
    LeftParenthesis,

    #[token(")")]
    /// )
    RightParenthesis,

    #[token("{")]
    /// {
    LeftBrace,

    #[token("}")]
    /// }
    RightBrace,

    #[regex("[0-9]+")]
    ConstInt,

    #[regex(r"(\d+\.\d+)|(\.\d+([eE]([-+])?\d+)?)|(\d+[eE]([-+])?\d+)")]
    ConstFloat,

    #[regex("true|false")]
    ConstBoolean,

    #[regex("\"[^\n\"]*\"")]
    ConstString,

    #[regex("[a-zA-Z]+[0-9a-zA-Z]*")]
    Identifier,

    #[regex(r"/\*[^\*/]*\*/", logos::skip)]
    CComment,

    #[regex("//[^\n]*(\n)?", logos::skip)]
    CPPComment,

    // We can also use this variant to define whitespace,
    // or any other matches we wish to skip.
    #[regex(r"[ \t\f]+", logos::skip)]
    Whitespace,

    #[regex(r"[\n]")]
    Linebreak,

    // Logos requires one token variant to handle errors,
    // it can be named anything you wish.
    #[error]
    Error,
}


/// # Overview
/// Extended lexer based on the logos crate. The lexer keeps track of the current token and the next token
/// in the lexed text. Furthermore, the lexer keeps track of the line number in which each token is
/// located, and of the text associated with each token.
///
/// # Examples
/// ```
/// use cb_3::C1Lexer;
/// use cb_3::C1Token;
///     
/// let mut lexer = C1Lexer::new("void main() {
///                                 x = 4;
///                               }");
/// assert_eq!(lexer.current_token(), Some(C1Token::KwVoid));
/// assert_eq!(lexer.current_line_number(), Some(1));
/// assert_eq!(lexer.peek_token(), Some(C1Token::Identifier));
/// assert_eq!(lexer.peek_line_number(), Some(1));
///
/// lexer.eat();
/// // current token is 'main'
///
/// lexer.eat();
/// lexer.eat();
/// lexer.eat();
/// // current token is '{'
///
/// assert_eq!(lexer.current_token(), Some(C1Token::LeftBrace));
/// assert_eq!(lexer.current_line_number(), Some(1));
///
/// // next token is 'x'
/// assert_eq!(lexer.peek_token(), Some(C1Token::Identifier));
/// assert_eq!(lexer.peek_text(), Some("x"));
/// assert_eq!(lexer.peek_line_number(), Some(2));
/// ```
pub struct C1Lexer<'a> {
    logos_lexer: Lexer<'a, C1Token>,
    logos_line_number: usize,
    current_token: Option<TokenData<'a>>,
    peek_token: Option<TokenData<'a>>,
}

impl<'a> C1Lexer<'a> {
    /// Initialize a new C1Lexer for the given string slice
    pub fn new(text: &'a str) -> C1Lexer {
        let mut lexer = C1Lexer {
            logos_lexer: C1Token::lexer(text),
            logos_line_number: 1,
            current_token: None,
            peek_token: None,
        };
        lexer.current_token = lexer.next_token();
        lexer.peek_token = lexer.next_token();
        lexer
    }

    /// Return the C1Token variant of the current token without consuming it.
    /// ```
    /// use cb_3::{C1Lexer, C1Token};
    /// let lexer = C1Lexer::new("current next");
    ///
    /// assert_eq!(lexer.current_token(), Some(C1Token::Identifier));
    /// assert_eq!(lexer.current_text(), Some("current"));
    ///
    /// assert_eq!(lexer.current_token(), Some(C1Token::Identifier));
    /// assert_eq!(lexer.current_text(), Some("current"));
    /// ```
    pub fn current_token(&self) -> Option<C1Token> {
        self.current_token.token_type()
    }

    /// Return the C1Token variant of the next token without consuming it.
    ///```
    /// use cb_3::{C1Lexer, C1Token};
    /// let lexer = C1Lexer::new("current next");
    ///
    /// assert_eq!(lexer.peek_token(), Some(C1Token::Identifier));
    /// assert_eq!(lexer.peek_text(), Some("next"));
    ///
    /// assert_eq!(lexer.peek_token(), Some(C1Token::Identifier));
    /// assert_eq!(lexer.peek_text(), Some("next"));
    /// ```
    pub fn peek_token(&self) -> Option<C1Token> {
        self.peek_token.token_type()
    }

    /// Return the text of the current token
    pub fn current_text(&self) -> Option<&str> {
        self.current_token.text()
    }

    /// Return the text of the next token
    pub fn peek_text(&self) -> Option<&str> {
        self.peek_token.text()
    }

    /// Return the line number where the current token is located
    pub fn current_line_number(&self) -> Option<usize> {
        self.current_token.line_number()
    }

    /// Return the line number where the next token is located
    pub fn peek_line_number(&self) -> Option<usize> {
        self.peek_token.line_number()
    }

    /// Drop the current token and retrieve the next token in the text.
    /// ```
    /// use cb_3::{C1Lexer, C1Token};
    /// let mut lexer = C1Lexer::new("current next last");
    ///
    /// assert_eq!(lexer.current_text(), Some("current"));
    /// assert_eq!(lexer.peek_text(), Some("next"));
    ///
    /// lexer.eat();
    /// assert_eq!(lexer.current_text(), Some("next"));
    /// assert_eq!(lexer.peek_text(), Some("last"));
    ///
    /// lexer.eat();
    /// assert_eq!(lexer.current_text(), Some("last"));
    /// assert_eq!(lexer.peek_text(), None);
    ///
    /// lexer.eat();
    /// assert_eq!(lexer.current_text(), None);
    /// assert_eq!(lexer.peek_text(), None);
    /// ```
    pub fn eat(&mut self) {
        self.current_token = self.peek_token.take();
        self.peek_token = self.next_token();
    }

    /// Private method for reading the next token from the logos::Lexer and extracting the required data
    /// from it
    fn next_token(&mut self) -> Option<TokenData<'a>> {
        // Retrieve the next token from the internal lexer
        if let Some(c1_token) = self.logos_lexer.next() {
            match c1_token {
                C1Token::Linebreak => {
                    // If the token is a linebreak, increase the line number and get the next token
                    self.logos_line_number += 1;
                    self.next_token()
                }
                _ => Some(TokenData {
                    // If the token is not a linebreak, initialize and return a TokenData instance
                    token_type: c1_token,
                    token_text: self.logos_lexer.slice(),
                    token_line: self.logos_line_number,
                }),
            }
        } else {
            None
        }
    }
}

/// Hidden struct for capsuling the data associated with a token.
struct TokenData<'a> {
    token_type: C1Token,
    token_text: &'a str,
    token_line: usize,
}

/// Hidden trait that makes it possible to implemented the required getter functionality directly for
/// Option<TokenData>.
trait TokenDataProvider<'a> {
    /// Return the type of the token, aka. its C1Token variant.
    fn token_type(&self) -> Option<C1Token>;
    /// Return the text of the token
    fn text(&self) -> Option<&str>;
    /// Return the line number of the token
    fn line_number(&self) -> Option<usize>;
}

impl<'a> TokenDataProvider<'a> for Option<TokenData<'a>> {
    fn token_type(&self) -> Option<C1Token> {
        self.as_ref().map(|data| data.token_type)
    }

    fn text(&self) -> Option<&'a str> {
        self.as_ref().map(|data| data.token_text)
    }

    fn line_number(&self) -> Option<usize> {
        self.as_ref().map(|data| data.token_line)
    }
}

pub struct C1Parser<'a>{  
    lexer: C1Lexer<'a>,
    result: ParseResult,
}

impl<'a> C1Parser<'a>{
    pub fn parse(text: &'a str) -> ParseResult{
        let mut parser = C1Parser::new(text);
        parser.result = parser.programm();
        parser.result
    }

    pub fn new(text: &'a str) -> C1Parser {
        let parser = C1Parser {
            lexer: C1Lexer::new(text),
            result: Ok(()),
        };
        parser
    }


    fn programm(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(..) => {
                    self.result = self.functiondefinition();
                    self.result = self.programm();},
                None => {},
            };
        }
        self.result.clone()
    }

    fn functiondefinition(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::KwBoolean) => {
                    self.result = self.r#type(); 
                    self.result = self.chek_and_eat(C1Token::Identifier);
                    self.result = self.chek_and_eat(C1Token::LeftParenthesis); 
                    self.result = self.chek_and_eat(C1Token::RightParenthesis);
                    self.result = self.chek_and_eat(C1Token::LeftBrace); 
                    self.result = self.statementlist();
                    self.result = self.chek_and_eat(C1Token::RightBrace); 
                },
                Some(C1Token::KwFloat) => {
                    self.result = self.r#type(); 
                    self.result = self.chek_and_eat(C1Token::Identifier);
                    self.result = self.chek_and_eat(C1Token::LeftParenthesis); 
                    self.result = self.chek_and_eat(C1Token::RightParenthesis);
                    self.result = self.chek_and_eat(C1Token::LeftBrace); 
                    self.result = self.statementlist();
                    self.result = self.chek_and_eat(C1Token::RightBrace); 
                },
                Some(C1Token::KwInt) => {
                    self.result = self.r#type(); 
                    self.result = self.chek_and_eat(C1Token::Identifier);
                    self.result = self.chek_and_eat(C1Token::LeftParenthesis); 
                    self.result = self.chek_and_eat(C1Token::RightParenthesis);
                    self.result = self.chek_and_eat(C1Token::LeftBrace); 
                    self.result = self.statementlist();
                    self.result = self.chek_and_eat(C1Token::RightBrace); 
                },
                Some(C1Token::KwVoid) => {
                    self.result = self.r#type(); 
                    self.result = self.chek_and_eat(C1Token::Identifier);
                    self.result = self.chek_and_eat(C1Token::LeftParenthesis); 
                    self.result = self.chek_and_eat(C1Token::RightParenthesis);
                    self.result = self.chek_and_eat(C1Token::LeftBrace); 
                    self.result = self.statementlist();
                    self.result = self.chek_and_eat(C1Token::RightBrace); 
                },
                _other => {
                    let linenumber = self.lexer.current_line_number().unwrap().to_string();
                    self.result = Result::Err("expekted boolean, float, int or void got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                },
            };
        }
        self.result.clone() 
    }

    fn functioncall(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::Identifier) => {
                    self.eat();
                    self.result = self.chek_and_eat(C1Token::LeftParenthesis);
                    self.result = self.chek_and_eat(C1Token::LeftParenthesis);
                },
                _other => {
                    let linenumber = self.lexer.current_line_number().unwrap().to_string();
                    self.result = Result::Err("expekted Identifier got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                },
            };
        }
        self.result.clone()
    }

    fn statementlist(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::LeftBrace) => {
                    self.result = self.block();
                    self.result = self.statementlist()
                },
                Some(C1Token::KwIf) => {
                    self.result = self.block();
                    self.result = self.statementlist()
                },
                Some(C1Token::KwReturn) => {
                    self.result = self.block();
                    self.result = self.statementlist()
                },
                Some(C1Token::KwPrintf) => {
                    self.result = self.block();
                    self.result = self.statementlist()
                },
                Some(C1Token::Identifier) => {
                    self.result = self.block();
                    self.result = self.statementlist()
                },
                // TODO: hier fehlt noch die follows menge statementlist ist epsilon ableitbar
                // vermutlich eifach im other nicht teun und keine fehlerbehandlung
                // dann die Fehlerbehandlung der nächsten höheren funktion überlassen
                _other => {
                    //let linenumber = self.lexer.current_line_number().unwrap().to_string();
                    //self.result = Result::Err("expekted {, if, return, Print or identifier got: ".to_string() + self.lexer.current_text().unwrap() + &"at line".to_string() + &linenumber)
                }, // TODO: Fehlerbehandlung hinzufügen
            };
        }
        self.result.clone()
    }

    fn block(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::LeftBrace) => {
                    self.eat();
                    self.result = self.statementlist();
                    self.result = self.chek_and_eat(C1Token::RightBrace);
                },
                Some(C1Token::KwIf) => self.result = self.statement(),
                Some(C1Token::KwReturn) => self.result = self.statement(),
                Some(C1Token::KwPrintf) => self.result = self.statement(),
                Some(C1Token::Identifier) => self.result = self.statement(),
                _other => {
                    let linenumber = self.lexer.current_line_number().unwrap().to_string();
                    self.result = Result::Err("expekted {, if, return, Print or identifier got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                },
            };
        }
        self.result.clone()
    }

    fn statement(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::KwIf) => {
                    self.result = self.ifstatement();
                    self.result = self.chek_and_eat(C1Token::Semicolon);
                },
                Some(C1Token::KwReturn) => {
                    self.result = self.returnstatement();
                    self.result = self.chek_and_eat(C1Token::Semicolon);
                },
                Some(C1Token::KwPrintf) => {
                    self.result = self.printf();
                    self.result = self.chek_and_eat(C1Token::Semicolon);
                },
                Some(C1Token::Identifier) => {match self.lexer.peek_token(){
                        Some(C1Token::Assign) => { 
                            self.result = self.statassignment();
                            self.result = self.chek_and_eat(C1Token::Semicolon);
                        },
                        Some(C1Token::LeftParenthesis) => {
                            self.result = self.functioncall();
                            self.result = self.chek_and_eat(C1Token::Semicolon);
                        },
                        _other => {
                            let linenumber = self.lexer.current_line_number().unwrap().to_string();
                            self.result = Result::Err("expekted == or ( got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                        },
                    };
                },
                _other => {
                    let linenumber = self.lexer.current_line_number().unwrap().to_string();
                    self.result = Result::Err("expekted if, return, Print or identifier got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                },
            };
        }
        self.result.clone()
    }

    fn ifstatement(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::KwIf) => {self.eat();
                    self.result = self.chek_and_eat(C1Token::LeftParenthesis); 
                    self.result = self.assignment();
                    self.result = self.chek_and_eat(C1Token::LeftParenthesis); 
                    self.result = self.block();
                },
                _other => {
                    let linenumber = self.lexer.current_line_number().unwrap().to_string();
                    self.result = Result::Err("expekted if got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                },
            };
        }
        self.result.clone()
    }

    fn returnstatement(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::KwReturn) => {match self.lexer.peek_token() {
                    Some(C1Token::Minus) => self.result = self.assignment(),
                    Some(C1Token::ConstInt) => self.result = self.assignment(),
                    Some(C1Token::ConstFloat) => self.result = self.assignment(),
                    Some(C1Token::ConstBoolean) => self.result = self.assignment(),
                    Some(C1Token::LeftParenthesis) => self.result = self.assignment(),
                    Some(C1Token::Identifier) => self.result = self.assignment(),
                    Some(C1Token::Semicolon) => {},
                    _other => {
                        let linenumber = self.lexer.current_line_number().unwrap().to_string();
                        self.result = Result::Err("expekted -, int, float, boolean, (, identifier or ; got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                    },
                };},
                _other => {
                    let linenumber = self.lexer.current_line_number().unwrap().to_string();
                    self.result = Result::Err("expekted return got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                },
            };
        }
        self.result.clone()
    }

    fn printf(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::KwPrintf) => {
                    self.eat();
                    self.result = self.chek_and_eat(C1Token::LeftParenthesis);
                    self.result = self.assignment();
                    self.result = self.chek_and_eat(C1Token::RightParenthesis);
                },
                _other => {
                    let linenumber = self.lexer.current_line_number().unwrap().to_string();
                    self.result = Result::Err("expekted print got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                },
            };
        }
        self.result.clone()
    }

    fn r#type(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match &self.lexer.current_token() {
                Some(C1Token::KwBoolean) => self.eat(),
                Some(C1Token::KwFloat) => self.eat(),
                Some(C1Token::KwInt) => self.eat(),
                Some(C1Token::KwVoid) => self.eat(),
                _other => {
                    let linenumber = self.lexer.current_line_number().unwrap().to_string();
                    self.result = Result::Err("expekted Boolean, float, int or void got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                },
            };
        }
        self.result.clone()
    }

    fn statassignment(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match&self.lexer.current_token() {
                Some(C1Token::Identifier) => {
                    self.eat();
                    self.result = self.chek_and_eat(C1Token::Assign);
                    self.result = self.assignment();
                },
                _other => {
                    let linenumber = self.lexer.current_line_number().unwrap().to_string();
                    self.result = Result::Err("expekted identifier got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                },
            };
        }
        self.result.clone()
    }

    fn assignment(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::Identifier) => {
                    match self.lexer.peek_token(){
                        Some(C1Token::Assign) => {
                                self.eat();
                                self.eat();
                                self.result = self.assignment();
                            }
                        _other => self.result = self.expr(),
                    };
                },
                Some(C1Token::Minus) => self.result = self.expr(),
                Some(C1Token::ConstInt) => self.result = self.expr(),
                Some(C1Token::ConstFloat) => self.result = self.expr(),
                Some(C1Token::ConstBoolean) => self.result = self.expr(),
                Some(C1Token::LeftParenthesis) => self.result = self.expr(),
                _other => {
                    let linenumber = self.lexer.current_line_number().unwrap().to_string();
                    self.result = Result::Err("expekted identifier, -, int, float, Boolean or ( got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                },
            }
        }
        self.result.clone()
    }

    fn expr(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::Minus) => {
                    self.result = self.simpexpr();
                    self.result = self.helpexpr();
                },
                Some(C1Token::ConstInt) => {
                    self.result = self.simpexpr();
                    self.result = self.helpexpr();
                },
                Some(C1Token::ConstFloat) => {
                    self.result = self.simpexpr();
                    self.result = self.helpexpr();
                },
                Some(C1Token::ConstBoolean) => {
                    self.result = self.simpexpr();
                    self.result = self.helpexpr();
                },
                Some(C1Token::LeftParenthesis) => {
                    self.result = self.simpexpr();
                    self.result = self.helpexpr();
                },
                Some(C1Token::Identifier) => {
                    self.result = self.simpexpr();
                    self.result = self.helpexpr();
                },
                _other => {
                    let linenumber = self.lexer.current_line_number().unwrap().to_string();
                    self.result = Result::Err("expekted -, int, float, boolean, ( or identifier got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                },
            };
        }
        self.result.clone()
    }

    fn helpexpr(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::Equal) => {self.eat(); self.result = self.simpexpr();},
                Some(C1Token::NotEqual) => {self.eat(); self.result = self.simpexpr();},
                Some(C1Token::LessEqual) => {self.eat(); self.result = self.simpexpr();},
                Some(C1Token::GreaterEqual) => {self.eat(); self.result = self.simpexpr();},
                Some(C1Token::Less) => {self.eat(); self.result = self.simpexpr();},
                Some(C1Token::Greater) => {self.eat(); self.result = self.simpexpr();},
                // TODO: hier fehlt noch die follows menge helpexpr ist epsilon ableitbar
                // vermutlich eifach im other nicht teun und keine fehlerbehandlung
                // dann die Fehlerbehandlung der nächsten höheren funktion überlassen
                _other => {}, // TODO: Fehlerbehanddlung hinzufügen
            };
        }
        self.result.clone()
    }

    fn simpexpr(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::Minus) => {
                    self.eat();
                    self.result = self.term();
                    self.result = self.helpsimpexpr();
                },
                Some(C1Token::ConstInt) => {
                    self.result = self.term();
                    self.result = self.helpsimpexpr()
                },
                Some(C1Token::ConstFloat) => {
                    self.result = self.term();
                    self.result = self.helpsimpexpr()
                },
                Some(C1Token::ConstBoolean) => {
                    self.result = self.term();
                    self.result = self.helpsimpexpr()
                },
                Some(C1Token::LeftParenthesis) => {
                    self.result = self.term();
                    self.result = self.helpsimpexpr()
                },
                Some(C1Token::Identifier) => {
                    self.result = self.term();
                    self.result = self.helpsimpexpr()
                },
                _other => {
                    let linenumber = self.lexer.current_line_number().unwrap().to_string();
                    self.result = Result::Err("expekted -, int, float, boolen, ( or identifier got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                },
            };
        }
        self.result.clone()
    }

    fn helpsimpexpr(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::Plus) => {
                    self.eat();
                    self.result = self.term();
                    self.result = self.helpsimpexpr();
                },
                Some(C1Token::Minus) => {
                    self.eat();
                    self.result = self.term();
                    self.result = self.helpsimpexpr();
                },
                Some(C1Token::Or) => {
                    self.eat();
                    self.result = self.term();
                    self.result = self.helpsimpexpr();
                },
                // TODO: hier fehlt noch die follows menge helpsimpexpr ist epsilon ableitbar
                // vermutlich eifach im other nicht teun und keine fehlerbehandlung
                // dann die Fehlerbehandlung der nächsten höheren funktion überlassen
                _other => {}, // TODO: Fehlerbehandlung hinzufügen
            };
        } 
        self.result.clone()
    }

    fn term(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::ConstInt) => {
                    self.result = self.factor();
                    self.result = self.helpterm();
                },
                Some(C1Token::ConstFloat) => {
                    self.result = self.factor();
                    self.result = self.helpterm();
                },
                Some(C1Token::ConstBoolean) => {
                    self.result = self.factor();
                    self.result = self.helpterm();
                },
                Some(C1Token::LeftParenthesis) => {
                    self.result = self.factor();
                    self. result = self.helpterm();
                }
                Some(C1Token::Identifier) => {
                    self.result = self.factor();
                    self.result = self.helpterm();
                }, 
                _other => {
                    let linenumber = self.lexer.current_line_number().unwrap().to_string();
                    self.result = Result::Err("expekted int, float, boolean, ( or identifier got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                },
            };
        }
        self.result.clone()
    }

    fn helpterm(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::Asterisk) => {
                    self.eat();
                    self.result = self.factor();
                    self.result = self.helpterm();
                },
                Some(C1Token::Slash) => {
                    self.eat();
                    self.result = self.factor();
                    self.result = self.helpterm();
                },
                Some(C1Token::And) => {
                    self.eat();
                    self.result = self.factor();
                    self.result = self.helpterm();
                },
                // TODO: hier fehlt noch die follows menge helpterm ist epsilon ableitbar
                // vermutlich eifach im other nicht teun und keine fehlerbehandlung
                // dann die Fehlerbehandlung der nächsten höheren funktion überlassen
                _other => {}, // TODO: fehlerbehandlung hinzufügen
            };
        }
        self.result.clone()
    }

    fn factor(&mut self) -> ParseResult{
        if self.result == Ok(()){
            match self.lexer.current_token() {
                Some(C1Token::ConstInt) => self.eat(),
                Some(C1Token::ConstFloat) => self.eat(),
                Some(C1Token::ConstBoolean) => self.eat(),
                Some(C1Token::LeftParenthesis) => {
                    self.eat();
                    self.result = self.assignment();
                    self.result = self.chek_and_eat(C1Token::LeftParenthesis);
                },
                Some(C1Token::Identifier) => {
                    match self.lexer.peek_token() {
                        Some(C1Token::LeftParenthesis) => self.result = self.functioncall(),
                        _other => self.eat(),
                    };
                },
                _other => {
                    let linenumber = self.lexer.current_line_number().unwrap().to_string();
                    self.result = Result::Err("expekted int, float, boolean, ( or identifier got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber)
                },
            };
        }
        self.result.clone()
    }



    fn eat(&mut self) {
        self.lexer.eat();
    }

    fn chek_and_eat(&mut self, token: C1Token) -> ParseResult{
        if self.result == Ok(()) {
            match self.lexer.current_token(){
                Some(value) => {if value == token {
                        self.eat()
                    }else{
                        let linenumber = self.lexer.current_line_number().unwrap().to_string();
                        self.result = Result::Err("expekted another token got: ".to_string() + self.lexer.current_text().unwrap() + "at line" + &linenumber);
                    }
                },
                None => {
                    self.result = Result::Err("there ist no more token to eat".to_string())
                },
            };
        }
        self.result.clone()
    }
}



#[cfg(test)]
mod tests {
    use crate::lexer::C1Lexer;
    use crate::C1Token;

    #[test]
    fn lines_are_counted() {
        let mut lexer1 = C1Lexer::new("Hello\nTest");
        assert_eq!(lexer1.current_line_number(), Some(1));
        assert_eq!(lexer1.peek_line_number(), Some(2));
        lexer1.eat();
        assert_eq!(lexer1.current_line_number(), Some(2));
        assert_eq!(lexer1.peek_line_number(), None);
        lexer1.eat();
        assert_eq!(lexer1.current_line_number(), None);
        assert_eq!(lexer1.peek_line_number(), None);
    }


    #[test]
    fn line_count_is_reset() {
        {
            let mut lexer1 = C1Lexer::new("Hello\nTest\nbla\nfoo");
            lexer1.eat();
            lexer1.eat();
            assert_eq!(lexer1.current_line_number(), Some(3));
            assert_eq!(lexer1.peek_line_number(), Some(4));
        }
        let lexer2 = C1Lexer::new("bool foo()");
        assert_eq!(lexer2.current_line_number(), Some(1));
        assert_eq!(lexer2.peek_line_number(), Some(1));
    }

    #[test]
    fn float_recognition() {
        let lexer = C1Lexer::new("1.2");
        assert_eq!(lexer.current_token(), Some(C1Token::ConstFloat));

        let lexer = C1Lexer::new("1.000");
        assert_eq!(lexer.current_token(), Some(C1Token::ConstFloat));

        let lexer = C1Lexer::new(".2");
        assert_eq!(lexer.current_token(), Some(C1Token::ConstFloat));

        let lexer = C1Lexer::new("1.2e4");
        assert_eq!(lexer.current_token(), Some(C1Token::ConstFloat));

        let lexer = C1Lexer::new("1.2e+4");
        assert_eq!(lexer.current_token(), Some(C1Token::ConstFloat));

        let lexer = C1Lexer::new("1.2e-10");
        assert_eq!(lexer.current_token(), Some(C1Token::ConstFloat));

        let lexer = C1Lexer::new("1.2E-10");
        assert_eq!(lexer.current_token(), Some(C1Token::ConstFloat));

        let lexer = C1Lexer::new("33E+2");
        assert_eq!(lexer.current_token(), Some(C1Token::ConstFloat));
    }
}