#!/usr/bin/env python
# -*- coding: utf-8 -*-

# CAVEAT UTILITOR
#
# This file was automatically generated by Grako.
#
#    https://pypi.python.org/pypi/grako/
#
# Any changes you make to it will be overwritten the next time
# the file is generated.


from __future__ import print_function, division, absolute_import, unicode_literals

from grako.buffering import Buffer
from grako.parsing import graken, Parser
from grako.util import re, RE_FLAGS, generic_main  # noqa


__all__ = [
    'GnomicParser',
    'GnomicSemantics',
    'main'
]

KEYWORDS = {}


class GnomicBuffer(Buffer):
    def __init__(
        self,
        text,
        whitespace=re.compile('[\\t ]+', RE_FLAGS | re.DOTALL),
        nameguard=None,
        comments_re=None,
        eol_comments_re=None,
        ignorecase=None,
        namechars='',
        **kwargs
    ):
        super(GnomicBuffer, self).__init__(
            text,
            whitespace=whitespace,
            nameguard=nameguard,
            comments_re=comments_re,
            eol_comments_re=eol_comments_re,
            ignorecase=ignorecase,
            namechars=namechars,
            **kwargs
        )


class GnomicParser(Parser):
    def __init__(
        self,
        whitespace=re.compile('[\\t ]+', RE_FLAGS | re.DOTALL),
        nameguard=None,
        comments_re=None,
        eol_comments_re=None,
        ignorecase=None,
        left_recursion=False,
        parseinfo=True,
        keywords=None,
        namechars='',
        buffer_class=GnomicBuffer,
        **kwargs
    ):
        if keywords is None:
            keywords = KEYWORDS
        super(GnomicParser, self).__init__(
            whitespace=whitespace,
            nameguard=nameguard,
            comments_re=comments_re,
            eol_comments_re=eol_comments_re,
            ignorecase=ignorecase,
            left_recursion=left_recursion,
            parseinfo=parseinfo,
            keywords=keywords,
            namechars=namechars,
            buffer_class=buffer_class,
            **kwargs
        )

    @graken()
    def _SEQUENCE_VARIANT_(self):
        with self._choice():
            with self._option():
                self._DNA_SEQUENCE_VARIANT_()
            with self._option():
                self._PROTEIN_SEQUENCE_VARIANT_()
            self._error('no available options')

    @graken()
    def _DNA_SEQUENCE_VARIANT_(self):
        with self._group():
            with self._choice():
                with self._option():
                    self._token('g')
                with self._option():
                    self._token('c')
                with self._option():
                    self._token('n')
                self._error('expecting one of: c g n')
        self._token('.')
        with self._group():
            with self._choice():
                with self._option():
                    self._INTEGER_()
                    self._NUCLEOTIDE_()
                    self._token('>')
                    self._NUCLEOTIDE_()
                with self._option():
                    self._INTEGER_()
                    self._token('_')
                    self._INTEGER_()
                    self._token('del')
                with self._option():
                    self._INTEGER_()
                    self._token('_')
                    self._INTEGER_()
                    self._token('ins')
                    self._NUCLEOTIDE_SEQUENCE_()
                with self._option():
                    self._INTEGER_()
                    self._token('_')
                    self._INTEGER_()
                    self._token('delins')
                    self._NUCLEOTIDE_SEQUENCE_()
                with self._option():
                    self._INTEGER_()
                    self._token('_')
                    self._INTEGER_()
                    self._token('dup')
                self._error('no available options')

    @graken()
    def _NUCLEOTIDE_SEQUENCE_(self):
        self._NUCLEOTIDE_()

        def block0():
            self._NUCLEOTIDE_()
        self._closure(block0)

    @graken()
    def _NUCLEOTIDE_(self):
        self._pattern(r'[ACGTBDHKMNRSVWY]')

    @graken()
    def _PROTEIN_SEQUENCE_VARIANT_(self):
        self._token('p.')
        with self._group():
            with self._choice():
                with self._option():
                    self._AMINO_ACID_()
                    self._INTEGER_()
                    self._AMINO_ACID_()
                with self._option():
                    self._AMINO_ACID_()
                    self._INTEGER_()
                    self._token('*')
                self._error('no available options')

    @graken()
    def _AMINO_ACID_SEQUENCE_(self):
        self._AMINO_ACID_()

        def block0():
            self._AMINO_ACID_()
        self._closure(block0)

    @graken()
    def _AMINO_ACID_(self):
        self._pattern(r'[A-Z]([a-z]{2})?')

    @graken()
    def _start_(self):
        with self._group():
            with self._choice():
                with self._option():
                    self._change_()
                    self.add_last_node_to_name('@')

                    def block1():
                        with self._group():
                            with self._choice():
                                with self._option():
                                    self._sep_()
                                with self._option():
                                    self._list_separator_()
                                    with self._optional():
                                        self._sep_()
                                self._error('no available options')
                        self._change_()
                        self.add_last_node_to_name('@')
                    self._closure(block1)
                with self._option():
                    self._empty_closure()
                self._error('no available options')
        with self._optional():
            self._sep_()
        self._check_eof()

    @graken()
    def _change_(self):
        with self._choice():
            with self._option():
                self._insertion_()
            with self._option():
                self._replacement_()
            with self._option():
                self._deletion_()
            with self._option():
                self._PLASMID_()
            with self._option():
                self._PHENE_()
            self._error('no available options')

    @graken()
    def _insertion_(self):
        self._token('+')
        self._INSERTABLE_()
        self.name_last_node('new')
        with self._optional():
            self._MARKERS_()
            self.name_last_node('markers')
        self.ast._define(
            ['markers', 'new'],
            []
        )

    @graken()
    def _replacement_(self):
        with self._choice():
            with self._option():
                self._REPLACEABLE_()
                self.name_last_node('old')
                self._token('>')
                self.name_last_node('op')
                self._SUBSTITUTE_()
                self.name_last_node('new')
                with self._optional():
                    self._MARKERS_()
                    self.name_last_node('markers')
            with self._option():
                self._REPLACEABLE_()
                self.name_last_node('old')
                self._token('>>')
                self.name_last_node('op')
                self._SUBSTITUTE_()
                self.name_last_node('new')
                with self._optional():
                    self._MARKERS_()
                    self.name_last_node('markers')
            self._error('no available options')
        self.ast._define(
            ['markers', 'new', 'old', 'op'],
            []
        )

    @graken()
    def _deletion_(self):
        self._token('-')
        self._DELETABLE_()
        self.name_last_node('old')
        with self._optional():
            self._MARKERS_()
            self.name_last_node('markers')
        self.ast._define(
            ['markers', 'old'],
            []
        )

    @graken()
    def _INSERTABLE_(self):
        with self._choice():
            with self._option():
                self._FUSION_()
            with self._option():
                self._FEATURE_SET_()
                self.name_last_node('@')
            with self._option():
                self._FEATURE_()
            self._error('no available options')

    @graken()
    def _REPLACEABLE_(self):
        with self._choice():
            with self._option():
                self._FUSION_()
            with self._option():
                self._FEATURE_SET_()
                self.name_last_node('@')
            with self._option():
                self._FEATURE_()
            self._error('no available options')

    @graken()
    def _SUBSTITUTE_(self):
        with self._choice():
            with self._option():
                self._PLASMID_()
            with self._option():
                self._FUSION_()
            with self._option():
                self._FEATURE_SET_()
                self.name_last_node('@')
            with self._option():
                self._FEATURE_()
            self._error('no available options')

    @graken()
    def _DELETABLE_(self):
        with self._choice():
            with self._option():
                self._PLASMID_()
            with self._option():
                self._FUSION_()
            with self._option():
                self._FEATURE_SET_()
                self.name_last_node('@')
            with self._option():
                self._FEATURE_()
            self._error('no available options')

    @graken()
    def _PLASMID_(self):
        with self._choice():
            with self._option():
                self._IDENTIFIER_()
                self.name_last_node('name')
                self._FEATURE_SET_()
                self.name_last_node('contents')
                with self._optional():
                    self._MARKERS_()
                    self.name_last_node('markers')
            with self._option():
                self._IDENTIFIER_()
                self.name_last_node('name')
                self._token('{}')
                with self._optional():
                    self._MARKERS_()
                    self.name_last_node('markers')
            with self._option():
                self._token('(')
                self._IDENTIFIER_()
                self.name_last_node('name')
                self._FEATURE_SET_ITEMS_()
                self.name_last_node('contents')
                self._token(')')
                with self._optional():
                    self._MARKERS_()
                    self.name_last_node('markers')
            with self._option():
                self._token('(')
                self._IDENTIFIER_()
                self.name_last_node('name')
                self._token(')')
                with self._optional():
                    self._MARKERS_()
                    self.name_last_node('markers')
            self._error('no available options')
        self.ast._define(
            ['contents', 'markers', 'name'],
            []
        )

    @graken()
    def _PHENE_(self):
        with self._choice():
            with self._option():
                with self._optional():
                    self._FEATURE_ORGANISM_()
                    self.name_last_node('organism')
                self._IDENTIFIER_()
                self.name_last_node('name')
                self._ACCESSION_()
                self.name_last_node('accession')
                self._BINARY_VARIANT_()
                self.name_last_node('variant')
            with self._option():
                self._ACCESSION_()
                self.name_last_node('accession')
                self._BINARY_VARIANT_()
                self.name_last_node('variant')
            with self._option():
                with self._optional():
                    self._FEATURE_ORGANISM_()
                    self.name_last_node('organism')
                self._IDENTIFIER_()
                self.name_last_node('name')
                self._VARIANT_()
                self.name_last_node('variant')
            self._error('no available options')
        self.ast._define(
            ['accession', 'name', 'organism', 'variant'],
            []
        )

    @graken()
    def _PHENE_SET_(self):
        self._token('{')
        with self._optional():
            self._sep_()
        self._PHENE_()
        self.add_last_node_to_name('@')

        def block1():
            with self._group():
                with self._choice():
                    with self._option():
                        self._sep_()
                    with self._option():
                        self._list_separator_()
                        with self._optional():
                            self._sep_()
                    self._error('no available options')
            self._PHENE_()
            self.add_last_node_to_name('@')
        self._closure(block1)
        with self._optional():
            self._sep_()
        self._token('}')

    @graken()
    def _MARKERS_(self):
        self._token('::')
        with self._group():
            with self._choice():
                with self._option():
                    self._PHENE_()
                    self.add_last_node_to_name('@')
                with self._option():
                    self._PHENE_SET_()
                    self.name_last_node('@')
                self._error('no available options')

    @graken()
    def _FEATURE_(self):
        with self._choice():
            with self._option():
                with self._optional():
                    self._FEATURE_ORGANISM_()
                    self.name_last_node('organism')
                with self._optional():
                    self._IDENTIFIER_()
                    self.name_last_node('type')
                    self._token('.')
                self._IDENTIFIER_()
                self.name_last_node('name')
                with self._optional():
                    self._VARIANT_()
                    self.name_last_node('variant')
                with self._optional():
                    self._ACCESSION_()
                    self.name_last_node('accession')
                with self._optional():
                    self._RANGE_()
                    self.name_last_node('range')
            with self._option():
                self._ACCESSION_()
                self.name_last_node('accession')
                with self._optional():
                    self._RANGE_()
                    self.name_last_node('range')
            self._error('no available options')
        self.ast._define(
            ['accession', 'name', 'organism', 'range', 'type', 'variant'],
            []
        )

    @graken()
    def _FEATURE_ORGANISM_(self):
        self._ORGANISM_()
        self.name_last_node('@')
        self._token('/')

    @graken()
    def _FEATURE_SET_(self):
        self._token('{')
        self._FEATURE_SET_ITEMS_()
        self.name_last_node('@')
        self._token('}')

    @graken()
    def _FEATURE_SET_ITEMS_(self):
        with self._optional():
            self._sep_()
        with self._group():
            with self._choice():
                with self._option():
                    self._FEATURE_FUSION_()
                with self._option():
                    self._FEATURE_()
                self._error('no available options')
        self.add_last_node_to_name('@')

        def block2():
            with self._group():
                with self._choice():
                    with self._option():
                        self._sep_()
                    with self._option():
                        self._list_separator_()
                        with self._optional():
                            self._sep_()
                    self._error('no available options')
            with self._group():
                with self._choice():
                    with self._option():
                        self._FEATURE_FUSION_()
                    with self._option():
                        self._FEATURE_()
                    self._error('no available options')
            self.add_last_node_to_name('@')
        self._closure(block2)
        with self._optional():
            self._sep_()

    @graken()
    def _FUSION_(self):
        with self._group():
            with self._choice():
                with self._option():
                    self._FEATURE_SET_()
                with self._option():
                    self._FEATURE_()
                self._error('no available options')
        self.add_last_node_to_name('@')

        def block2():
            self._token(':')
            with self._group():
                with self._choice():
                    with self._option():
                        self._FEATURE_SET_()
                    with self._option():
                        self._FEATURE_()
                    self._error('no available options')
            self.add_last_node_to_name('@')
        self._positive_closure(block2)

    @graken()
    def _FEATURE_FUSION_(self):
        self._FEATURE_()
        self.add_last_node_to_name('@')

        def block1():
            self._token(':')
            self._FEATURE_()
            self.add_last_node_to_name('@')
        self._positive_closure(block1)

    @graken()
    def _VARIANT_(self):
        with self._choice():
            with self._option():
                self._token('(')
                self._VARIANT_LIST_()
                self.name_last_node('@')
                self._token(')')
            with self._option():
                self._BINARY_VARIANT_()
                self.name_last_node('@')
            self._error('no available options')

    @graken()
    def _VARIANT_LIST_(self):
        with self._group():
            with self._choice():
                with self._option():
                    self._SEQUENCE_VARIANT_()
                with self._option():
                    self._VARIANT_IDENTIFIER_()
                self._error('no available options')
        self.name_last_node('@')

        def block2():
            with self._group():
                with self._choice():
                    with self._option():
                        self._token(',')
                    with self._option():
                        self._token(';')
                    self._error('expecting one of: , ;')
            with self._optional():
                self._sep_()
            with self._group():
                with self._choice():
                    with self._option():
                        self._SEQUENCE_VARIANT_()
                    with self._option():
                        self._VARIANT_IDENTIFIER_()
                    self._error('no available options')
            self.name_last_node('@')
        self._closure(block2)

    @graken()
    def _BINARY_VARIANT_(self):
        with self._choice():
            with self._option():
                self._token('+')
            with self._option():
                self._token('-')
            self._error('expecting one of: + -')

    @graken()
    def _VARIANT_IDENTIFIER_(self):
        self._pattern(r'[A-Za-z0-9]+([A-Za-z0-9_\-]+[A-Za-z0-9])?')

    @graken()
    def _RANGE_(self):
        with self._choice():
            with self._option():
                self._token('[')
                with self._optional():
                    self._SEQUENCE_LEVEL_PREFIX_()
                    self.name_last_node('level')
                self._INTEGER_()
                self.name_last_node('start')
                self._token('_')
                self._INTEGER_()
                self.name_last_node('end')
                self._token(']')
            with self._option():
                self._token('[')
                with self._optional():
                    self._SEQUENCE_LEVEL_PREFIX_()
                    self.name_last_node('level')
                self._INTEGER_()
                self.name_last_node('pos')
                self._token(']')
            self._error('no available options')
        self.ast._define(
            ['end', 'level', 'pos', 'start'],
            []
        )

    @graken()
    def _SEQUENCE_LEVEL_PREFIX_(self):
        with self._group():
            with self._choice():
                with self._option():
                    self._token('g')
                with self._option():
                    self._token('c')
                with self._option():
                    self._token('p')
                self._error('expecting one of: c g p')
        self.name_last_node('@')
        self._token('.')

    @graken()
    def _ACCESSION_(self):
        with self._choice():
            with self._option():
                self._token('#')
                self._DATABASE_()
                self.name_last_node('db')
                self._token(':')
                with self._group():
                    with self._choice():
                        with self._option():
                            self._INTEGER_()
                        with self._option():
                            self._IDENTIFIER_()
                        self._error('no available options')
                self.name_last_node('id')
            with self._option():
                self._token('#')
                with self._group():
                    with self._choice():
                        with self._option():
                            self._INTEGER_()
                        with self._option():
                            self._IDENTIFIER_()
                        self._error('no available options')
                self.name_last_node('id')
            self._error('no available options')
        self.ast._define(
            ['db', 'id'],
            []
        )

    @graken()
    def _DATABASE_(self):
        self._pattern(r'[A-Za-z0-9-][A-Za-z0-9]+')

    @graken()
    def _INTEGER_(self):
        self._pattern(r'[0-9]+')
        self.name_last_node('@')

    @graken()
    def _IDENTIFIER_(self):
        self._pattern(r'[A-Za-z0-9]+([A-Za-z0-9_-]+[A-Za-z0-9])?')

    @graken()
    def _ORGANISM_(self):
        self._pattern(r'[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)?')

    @graken()
    def _list_separator_(self):
        self._token(',')

    @graken()
    def _sep_(self):
        self._pattern(r'[\t ]+')


class GnomicSemantics(object):
    def SEQUENCE_VARIANT(self, ast):
        return ast

    def DNA_SEQUENCE_VARIANT(self, ast):
        return ast

    def NUCLEOTIDE_SEQUENCE(self, ast):
        return ast

    def NUCLEOTIDE(self, ast):
        return ast

    def PROTEIN_SEQUENCE_VARIANT(self, ast):
        return ast

    def AMINO_ACID_SEQUENCE(self, ast):
        return ast

    def AMINO_ACID(self, ast):
        return ast

    def start(self, ast):
        return ast

    def change(self, ast):
        return ast

    def insertion(self, ast):
        return ast

    def replacement(self, ast):
        return ast

    def deletion(self, ast):
        return ast

    def INSERTABLE(self, ast):
        return ast

    def REPLACEABLE(self, ast):
        return ast

    def SUBSTITUTE(self, ast):
        return ast

    def DELETABLE(self, ast):
        return ast

    def PLASMID(self, ast):
        return ast

    def PHENE(self, ast):
        return ast

    def PHENE_SET(self, ast):
        return ast

    def MARKERS(self, ast):
        return ast

    def FEATURE(self, ast):
        return ast

    def FEATURE_ORGANISM(self, ast):
        return ast

    def FEATURE_SET(self, ast):
        return ast

    def FEATURE_SET_ITEMS(self, ast):
        return ast

    def FUSION(self, ast):
        return ast

    def FEATURE_FUSION(self, ast):
        return ast

    def VARIANT(self, ast):
        return ast

    def VARIANT_LIST(self, ast):
        return ast

    def BINARY_VARIANT(self, ast):
        return ast

    def VARIANT_IDENTIFIER(self, ast):
        return ast

    def RANGE(self, ast):
        return ast

    def SEQUENCE_LEVEL_PREFIX(self, ast):
        return ast

    def ACCESSION(self, ast):
        return ast

    def DATABASE(self, ast):
        return ast

    def INTEGER(self, ast):
        return ast

    def IDENTIFIER(self, ast):
        return ast

    def ORGANISM(self, ast):
        return ast

    def list_separator(self, ast):
        return ast

    def sep(self, ast):
        return ast


def main(filename, startrule, **kwargs):
    with open(filename) as f:
        text = f.read()
    parser = GnomicParser(parseinfo=False)
    return parser.parse(text, startrule, filename=filename, **kwargs)


if __name__ == '__main__':
    import json
    ast = generic_main(main, GnomicParser, name='Gnomic')
    print('AST:')
    print(ast)
    print()
    print('JSON:')
    print(json.dumps(ast, indent=2))
    print()
