import commands, os
from subprocess import Popen, PIPE, STDOUT
import color, default, mode, tab
from lex import Grammar, PatternRule, RegionRule
from mode.python import StringGrammar2
from tab import StackTabber2
from method import Method, Argument, arg
from method.shell import Exec, Pipe

class RegexGrammar(Grammar):
    rules = [
        PatternRule(r'escaped', r'\\.'),
        PatternRule(r'data', r'[^\\/]+'),
    ]

class AwkGrammar(Grammar):
    rules = [
        PatternRule(r'comment', r'#.*\n$'),
        PatternRule(r'spaces', r' +'),
        RegionRule(r'awk_regex', r'/(?! )', RegexGrammar, r'/'),
        PatternRule(r'awk_global', r'(?:TEXTDOMAIN|SUBSEP|RLENGTH|RSTART|RT|RS|PROCINFO|ORS|OFS|OFMT|NR|NF|LINT|IGNORECASE|FS|FNR|FILENAME|FIELDWIDTHS|ERRNO|ENVIRON|CONVFMT|BINMODE|ARGV|ARGIND|ARGC)(?![a-zA-Z0-9_])'),
        PatternRule(r'delimiter', r'(?:[\{\}()\[\]?:;,]|=(?!=)|\+=|-=|\*=|/=|\%=|\^=)'),
        PatternRule(r'keyword', r'(?:BEGIN|END|if|else|while|do|for|break|continue|delete|exit)(?![a-zA-Z0-9_])'),
        PatternRule(r'builtin', r'(?:close|getline|nextfile|next|printf|print|system|fflush|atan2|cos|exp|int|log|rand|sin|sqrt|srand|asorti|asort|gensub|gsub|index|length|match|split|sprintf|strtonum|substr|sub|tolower|toupper|mktime|strftime|systime|and|compl|lshift|or|xor|rshift|bindtextdomain|dcgettext|dcngettext|function|extension)(?![a-zA-Z0-9_])'),

        PatternRule(r'awk_field', r'\$\d*'),

        PatternRule(r'number', r'-?0x[0-9A-Fa-f]+'),
        PatternRule(r'number', r'-?0[0-7]*'),
        PatternRule(r'number', r'-?[0-9]+\.?[0-9]*'),
        PatternRule(r'number', r'-?\.[0-9]+'),

        PatternRule(r'unop', r'!(?![=~])|--|\+\+'),
        PatternRule(r'binop', r'(?:&&|\|\||<=|>=|!=|!~|==|\^|%|[-~/+*<>])'),
        RegionRule(r'string', r'"', StringGrammar2, r'"'),
        PatternRule(r'awk_function', r'[a-zA-Z_][a-zA-Z0-9_]*(?=\()'),
        PatternRule(r'awk_identifier', r'[a-zA-Z_][a-zA-Z0-9_]*'),
        
        PatternRule(r'continuation', r'\\\n$'),
        PatternRule(r'eol', r'\n'),
    ]

class AwkTabber(StackTabber2):
    open_tokens    = {'delimiter': {'{': '}', '(': ')', '[': ']'}}
    close_tokens   = {'delimiter': {'}': '{', ')': '(', ']': '['}}
    control_tokens = {
        'keyword': {'if': 1, 'else': 1, 'while': 1, 'do': 1, 'for': 1},
    }
    end_at_eof    = True
    end_at_tokens = {}
    def _is_base(self, y):
        if y == 0:
            return True
        t = self._get_tokens(y)[0]
        if t.fqname() == 'awk_regex.start':
            return True
        elif t.name in ('awk_field', 'awk_global'):
            return True
        elif t.name == 'keyword' and t.string in ('BEGIN', 'END'):
            return True
        else:
            return False
    def _is_indent(self, t):
        return t.name == 'spaces'
    def _is_ignored(self, t):
        return t.name in ('spaces', 'eol', 'comment')

class AwkFilterFile(Exec):
    show_success = True
    args = [arg('path', dt="path", p="Filter File: ", dv=default.path_dirname, ld=True, h="file to open")]
    def _execute(self, w, **vargs):
        if not hasattr(w.buffer, 'path'):
            w.set_error("Buffer %r has no program" % w.buffer.name())
            return
        elif w.buffer.changed():
            w.set_error("Buffer %r is not saved" % w.buffer.name())
            return
        elif not os.path.exists(vargs['path']):
            w.set_error("File %r not found" % vargs['path'])
            return

        cmd     = 'awk -f %r %r' % (w.buffer.path, vargs['path'])
        pipe    = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT)
        outdata = pipe.stdout.read()
        status  = pipe.wait() >> 8
        w.application.data_buffer('*Awk-Output*', outdata, switch_to=True)
        w.set_error("awk exited with status %d" % status)

class AwkFilterBuffer(Pipe):
    args = [arg('name', dt="buffer", p="Filter Buffer: ", h="name of the buffer to switch to")]
    def _execute(self, w, **vargs):
        if not hasattr(w.buffer, 'path'):
            w.set_error("Buffer %r has no program" % w.buffer.name())
            return
        elif w.buffer.changed():
            w.set_error("Buffer %r is not saved" % w.buffer.name())
            return
        elif not w.application.has_buffer_name(vargs['name']):
            w.set_error("Buffer %r not found" % vargs['name'])
            return

        b    = w.application.bufferlist.get_buffer_by_name(vargs['name'])
        opts = w.application.config['awk.cmd-opts']
        cmd  = 'awk %s -f %r' % (opts, w.buffer.path)
        pipe = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
        pipe.stdin.write(b.make_string())
        pipe.stdin.close()
        output = pipe.stdout.read()
        status = pipe.wait() >> 8
        w.application.data_buffer('*Awk-Output*', output, switch_to=True)
        w.set_error("awk exited with status %d" % status)

class AwkFilterInput(Method):
    args = [arg('input', p="Data To Filter: ", h="data to filter")]
    def _execute(self, w, **vargs):
        if not hasattr(w.buffer, 'path'):
            w.set_error("Buffer %r has no program" % w.buffer.name())
            return
        elif w.buffer.changed():
            w.set_error("Buffer %r is not saved" % w.buffer.name())
            return

        opts = w.application.config['awk.cmd-opts']
        cmd  = 'awk %s -f %r' % (opts, w.buffer.path)
        pipe = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
        pipe.stdin.write(vargs['input'])
        pipe.stdin.close()
        output = pipe.stdout.read()
        status = pipe.wait() >> 8
        w.application.data_buffer('*Awk-Output*', output, switch_to=True)
        w.set_error("awk exited with status %d" % status)

class Awk(mode.Fundamental):
    tabbercls   = AwkTabber
    modename   = 'awk'
    extensions = ['.awk']
    grammar    = AwkGrammar
    colors     = {
        'awk_global':      ('yellow', 'default', 'bold'),
        'awk_function':    ('magenta', 'default', 'bold'),
        'awk_field':       ('yellow', 'default', 'bold'),
        'awk_identifier':  ('yellow', 'default', 'bold'),
        'awk_regex.start': ('cyan', 'default', 'bold'),
        'awk_regex.null':  ('cyan', 'default', 'bold'),
        'awk_regex.data':  ('cyan', 'default', 'bold'),
        'awk_regex.end':   ('cyan', 'default', 'bold'),
    }
    config  = {'awk.cmd-opts': ""}
    actions = [AwkFilterFile, AwkFilterBuffer, AwkFilterInput]

install = Awk.install