from yezdi.lexer.token import TokenType
from yezdi.parser.ast import Program, Statement, Participant, Title, LineStatement


class Parser:
    def __init__(self, lexer):
        self.lexer = lexer
        self.current_token = None
        self.peek_token = None
        self.next_token()
        self.next_token()
        self.participants = {}

    def next_token(self):
        self.current_token, self.peek_token = self.peek_token, self.lexer.next_token()

    def parse_program(self):
        program = Program()
        while self.current_token.type != TokenType.EOF:
            statement = self.parse_statement()
            if statement:
                program.statements.append(statement)
            self.next_token()
        return program

    def parse_statement(self):
        if self.current_token.type == TokenType.IDENTIFIER:
            return self.parse_line_statement()
        elif self.current_token.type == TokenType.TITLE:
            return self.parse_title()
        return None

    def parse_line_statement(self):
        participant_literal = self.current_token.literal

        if not self.peek_token.type in [TokenType.SOLID_LINE, TokenType.DASHED_LINE]:
            return None
        self.next_token()

        participant = Participant(participant_literal)
        line = LineStatement(self.current_token.type)
        line.set_source(participant)
        if not self.expect_peek(TokenType.IDENTIFIER):
            return None
        target = Participant(self.current_token.literal)
        line.set_target(target)
        if not self.expect_peek(TokenType.COLON):
            return None
        if self.expect_peek(TokenType.IDENTIFIER):
            line.set_info(self.current_token.literal)
        if self.peek_token.type not in [TokenType.NEWLINE, TokenType.EOF]:
            return None
        statement = Statement(line)
        return statement

    def get_participant(self, value):
        if value in self.participants:
            return self.participants[value]
        else:
            participant = Participant(value)
            self.participants[value] = participant
        return participant

    def expect_peek(self, token_type):
        if self.peek_token.type == token_type:
            self.next_token()
            return True
        else:
            return False

    def parse_title(self):
        if not self.expect_peek(TokenType.IDENTIFIER):
            return None
        title = Title(self.current_token.literal)
        return Statement(title)


class ParserError(Exception):
    pass

[((18, 18, 18, 27), 'yezdi.parser.ast.Program', 'Program', ({}, {}), '()', False, 'from yezdi.parser.ast import Program, Statement, Participant, Title, LineStatement\n'), ((40, 22, 40, 54), 'yezdi.parser.ast.Participant', 'Participant', ({(40, 34, 40, 53): 'participant_literal'}, {}), '(participant_literal)', False, 'from yezdi.parser.ast import Program, Statement, Participant, Title, LineStatement\n'), ((41, 15, 41, 53), 'yezdi.parser.ast.LineStatement', 'LineStatement', ({(41, 29, 41, 52): 'self.current_token.type'}, {}), '(self.current_token.type)', False, 'from yezdi.parser.ast import Program, Statement, Participant, Title, LineStatement\n'), ((45, 17, 45, 56), 'yezdi.parser.ast.Participant', 'Participant', ({(45, 29, 45, 55): 'self.current_token.literal'}, {}), '(self.current_token.literal)', False, 'from yezdi.parser.ast import Program, Statement, Participant, Title, LineStatement\n'), ((53, 20, 53, 35), 'yezdi.parser.ast.Statement', 'Statement', ({(53, 30, 53, 34): 'line'}, {}), '(line)', False, 'from yezdi.parser.ast import Program, Statement, Participant, Title, LineStatement\n'), ((74, 16, 74, 49), 'yezdi.parser.ast.Title', 'Title', ({(74, 22, 74, 48): 'self.current_token.literal'}, {}), '(self.current_token.literal)', False, 'from yezdi.parser.ast import Program, Statement, Participant, Title, LineStatement\n'), ((75, 15, 75, 31), 'yezdi.parser.ast.Statement', 'Statement', ({(75, 25, 75, 30): 'title'}, {}), '(title)', False, 'from yezdi.parser.ast import Program, Statement, Participant, Title, LineStatement\n'), ((60, 26, 60, 44), 'yezdi.parser.ast.Participant', 'Participant', ({(60, 38, 60, 43): 'value'}, {}), '(value)', False, 'from yezdi.parser.ast import Program, Statement, Participant, Title, LineStatement\n')]