import os, subprocess, re, tempfile
from subprocess import Popen, PIPE, STDOUT

import buffer, buffer.about
import default, dirutil, regex, util, window
from point import Point
from mode import Fundamental
from method import Method, Argument

class ShowMode(Method):
    '''Show helpful information for the current mode'''

    def _execute(self, w, **vargs):
        a = w.application
        m = w.mode
        f = Fundamental(w)

        lines = ['%s mode' % m.name, '']

        if hasattr(m, 'description'):
            lines.append('Description:')
            lines.extend(m.description.split('\n'))

        seen    = set()
        triples = []
        l1, l2 = 0, 0
        for keys in m.bindings:
            if f.bindings.get(keys) == m.bindings.get(keys):
                continue
            name = m.bindings[keys]
            seen.add(name)
            l1 = max(l1, len(name))
            l2 = max(l2, len(keys))
            triples.append([name, keys, a.methods[name].help])

        for cls in m.actions:
            name = cls._name()
            if name in seen:
                continue
            triples.append([name, '', a.methods[name].help])

        last = None
        lines.extend(('Key Bindings:', ''))
        for triple in sorted(triples):
            name, keys, _help = triple
            if name == last:
                name = ''
            else:
                last = name
            lines.append('    %-*s  %-*s  %s' % (l1, name, l2, keys, _help))
        lines.append('')

        data = '\n'.join(lines)
        w.application.data_buffer("*Mode-Help*", data, switch_to=True)

class ShowBindingsBuffer(Method):
    '''Dump all keybindings for current mode into a new buffer'''
    def _execute(self, w, **vargs):
        lines = []
        mode_name = w.mode.name

        lines.append('Key bindings for mode %r:' % (mode_name))
        lines.append('')

        names_to_sequences = {}

        seq_len = len('BINDINGS')
        name_len = len('ACTION')
        for seq in w.mode.bindings:
            name = w.mode.bindings[seq]
            # we aren't going to show all the generic keypress actions
            if 'insert-string-' in name:
                continue
            elif 'overwrite-char-' in name:
                continue
            # determine this for formatting
            seq_len = max(seq_len, len(seq))
            name_len = max(name_len, len(name))

            # set up our new data structure
            names_to_sequences.setdefault(name, [])
            names_to_sequences[name].append(seq)

        # generate the format string (note the 'meta formatting')
        format_str = '%%-%ds  %%-%ds  %%s' % (seq_len, name_len)

        lines.append(format_str % ('BINDINGS', 'ACTIONS', 'HELP'))

        names = list(names_to_sequences.keys())
        names.sort()
        for name in names:
            sequences = names_to_sequences[name]
            sequences.sort()
            seq = sequences[0]
            help = w.application.methods[name].help
            if help is None:
                help = ''

            lines.append(format_str % (seq, name, help))
            for seq2 in sequences[1:]:
                lines.append(format_str % (seq2, '', ''))
        
        data = '\n'.join(lines)
        w.application.data_buffer("*Bindings-Help*", data, switch_to=True)

class ShowFunctionsBuffer(Method):
    '''Dump all keybindings for current mode into a new buffer'''
    def _execute(self, w, **vargs):
        app      = w.application
        name_len = len('ACTIONS')
        pairs    = []
        for name in app.methods:
            # we aren't going to show all the generic keypress actions
            if 'insert-string-' in name:
                continue
            elif 'overwrite-char-' in name:
                continue
            # determine this for formatting
            name_len = max(name_len, len(name))
            pairs.append((name, app.methods[name].help))

        # generate the format string (note the 'meta formatting')
        format_str = '%%-%ds  %%s' % name_len
        lines = [format_str % ('FUNCTION', 'HELP')]
        for pair in sorted(pairs):
            lines.append(format_str % pair)
        data = '\n'.join(lines)
        w.application.data_buffer("*Functions-Help*", data, switch_to=True)

class CmdHelpBuffer(Method):
    '''Get help with the specified command'''
    args = [Argument('method', datatype="method", prompt="Help for command: ")]
    def _execute(self, w, **vargs):
        lines = []
        name = vargs['method']
        if name not in w.application.methods:
            w.set_error("No command called %r" % name)
            return

        m = w.application.methods[name]
        lines.append('HELP FOR %r' % name)
        lines.append('')

        # sequences
        sequences = []
        for seq in w.mode.bindings:
            if w.mode.bindings[seq] == name:
                sequences.append(seq)
        sequences.sort()
        lines.append('Keys bound to this command:')
        for seq in sequences:
            lines.append('    %s' % (seq))
        lines.append('')

        # arguments
        if m.args:
            lines.append('Arguments for this command:')
            for arg in m.args:
                if arg.datatype is None:
                    if arg.type == type(""):
                        t = 'str'
                    elif arg.type == type(0):
                        t = 'int'
                    elif arg.type == type(0.0):
                        t = 'float'
                    else:
                        t = 'str'
                else:
                    t = arg.datatype
                if arg.help:
                    lines.append('    %s %r: %s' % (t, arg.name, arg.help))
                else:
                    lines.append('    %s %r' % (t, arg.name))
            lines.append('')

        # help text
        lines.append('Help text for this command:')
        h = m.help
        if not h:
            h = 'No help available'
        lines.append('    %s' % h)
        data = '\n'.join(lines)
        w.application.data_buffer("*Command-Help*", data, switch_to=True)

class WhichCommand(Method):
    '''Display which command is run for a given key-sequence'''
    def _execute(self, w, **vargs):
        self.old_window = w
        s = 'Enter a key sequence to be explained: '
        w.application.open_mini_buffer(s, lambda x: None, self, None, 'which')

class AboutPmacs(Method):
    '''print some information about pmacs'''
    def _execute(self, w, **vargs):
        a = w.application
        if not a.has_buffer_name('*About*'):
            b = buffer.about.AboutBuffer()
            a.add_buffer(b)
            window.Window(b, a)
        b = a.bufferlist.get_buffer_by_name('*About*')
        if a.window().buffer is not b:
            a.switch_buffer(b)