import os
import sys
from mode import Fundamental
from method import Method
from lex import Grammar, PatternRule, RegionRule
from mode.text import TextInsertSpace

class ArgumentGrammar(Grammar): rules = [PatternRule('data', '[^}]+')]
class StringGrammar1(Grammar): rules = [PatternRule('data', "[^']+")]
class StringGrammar2(Grammar): rules = [PatternRule('data', "(?:[^']|'(?!'))+")]

class FalseGrammar(Grammar):
    rules = [
        PatternRule('data', r'[^\\]+'),
        RegionRule('comment', r'\\if', None, r'\\fi'),
    ]

class LatexGrammar(Grammar):
    rules = [
        PatternRule('comment', r'\%.*$'),
        RegionRule('comment', r'\\iffalse', FalseGrammar, r'\\fi'),
        PatternRule('latex.wrapper', r'\\(?:begin|end)'),
        PatternRule('latex.control', r'\\[a-zA-Z]+'),
        RegionRule('latex.argument', r'{', ArgumentGrammar, r'}'),
        RegionRule('latex.string', r"``", StringGrammar2, r"''"),
        RegionRule('latex.string', r"`", StringGrammar1, r"'"),
        PatternRule('latex.escaped', r'\\.'),
        PatternRule('latex.special', r'[{}$^_%~#&]'),
        PatternRule('latex.data', r'[^{}$^_%~#&%\\`]+'),
    ]

class LatexBuild(Method):
    '''Insert a pair of LaTeX-style single-quotes into the buffer'''
    def _getcmd(self, w):
        return w.application.config.get('latex.buildcmd')
    def _build(self, w):
        if w.buffer.changed():
            return (True, 'Build Cancelled: unsaved buffer')
        app = w.application
        buildcmd = self._getcmd(w)
        cmd = "%s '\\batchmode\\input %s' >/dev/null 2>&1" % (buildcmd,
                                                              w.buffer.path)
        status = os.system(cmd)
        if status == 0:
            return (True, 'Build OK')
        else:
            return (False, 'Build Error')
    def _modpath(self, w, ext):
        return os.path.splitext(w.buffer.path)[0] + ext
    def _readlog(self, w):
        logpath = self._modpath(w, '.log')
        f = open(logpath, 'r')
        output = f.read()
        f.close()
        return output
    def _execute(self, w, **vargs):
        (ok, mesg) = self._build(w)
        w.set_error(mesg)
        if not ok:
            output = self._readlog(w)
            bufname = '*%s*' % self.name
            w.application.data_buffer(bufname, output, switch_to=not ok)
        return ok

class LatexBuildPdf(LatexBuild):
    '''Insert a pair of LaTeX-style single-quotes into the buffer'''
    def _getcmd(self, w):
        return w.application.config.get('latex.pdfbuildcmd')
class LatexViewPdf(LatexBuildPdf):
    '''Insert a pair of LaTeX-style single-quotes into the buffer'''
    def _execute(self, w, **vargs):
        ok = LatexBuildPdf._execute(self, w, **vargs)
        if ok:
            viewcmd = w.application.config.get('latex.pdfviewcmd')
            pid = os.fork()
            if pid == 0:
                # redirect stdout/stderr to a log file
                f = open('.pmacs-latex-pdf.err', 'a')
                sys.stderr.flush()
                os.dup2(f.fileno(), sys.stderr.fileno())
                sys.stdout.flush()
                os.dup2(f.fileno(), sys.stdout.fileno())
                # ok, now do the exec
                pdfpath = self._modpath(w, '.pdf')
                os.execvp(viewcmd, (viewcmd, pdfpath))

class LatexInsertSquotes(Method):
    '''Insert a pair of LaTeX-style single-quotes into the buffer'''
    def _execute(self, w, **vargs):
        w.insert_string_at_cursor("`'")
        w.backward()
class LatexInsertDquotes(Method):
    '''Insert a pair of LaTeX-style double-quotes into the buffer'''
    def _execute(self, w, **vargs):
        w.insert_string_at_cursor("``''")
        w.backward()
        w.backward()
class LatexInsertBraces(Method):
    '''Insert a pair of curly braces into the buffer'''
    def _execute(self, w, **vargs):
        w.insert_string_at_cursor("{}")
        w.backward()

class LatexInsertSpace(TextInsertSpace):
    pass

class LatexCheckSpelling(Method):
    """Check the spelling of the document via ispell -t"""
    def _execute(self, w, **vargs):
        # -x   no backup file
        # -M   show context menu
        # -t   treat input document as TeX
        w.application.run_external('ispell', '-x', '-M', '-t', w.buffer.path)
        if w.buffer.changed_on_disk():
            w.buffer.reload()

class Latex(Fundamental):
    name       = 'Latex'
    extensions = ['.latex', '.tex']
    commentc   = '%'
    grammar    = LatexGrammar
    colors     = {
        'latex.wrapper':       ('magenta', 'default', 'bold'),
        'latex.control':       ('blue', 'default', 'bold'),
        'latex.argument.null': ('cyan', 'default', 'bold'),
        'latex.argument.data': ('cyan', 'default', 'bold'),
    }
    config = {
        'latex.buildcmd':    'latex',
        'latex.pdfbuildcmd': 'pdflatex',
        'latex.pdfviewcmd':  'evince',
    }
    actions = [LatexInsertSquotes,
               LatexInsertDquotes, LatexInsertBraces, LatexBuild,
               LatexInsertSpace, LatexBuildPdf, LatexViewPdf,
               LatexCheckSpelling]
    _bindings = {
        'wrap-paragraph': ('M-q',),
        'latex-insert-squotes': ("M-'",),
        'latex-insert-dquotes': ('M-"',),
        'latex-insert-braces': ('M-{',),
        'latex-build': ("C-c C-c", 'C-c B'),
        'latex-insert-space': ('SPACE',),
        'latex-build-pdf': ("C-c C-p",),
        'latex-view-pdf': ('C-c C-v',),
    }

install = Latex.install