import sys, string, os, time, getpass, sha, getopt

from Ft.Lib.CommandLine import Options, Command, CommandLineUtil
from xml.dom.html import htmlImplementation
from xml.dom.ext import PrettyPrint
import cStringIO, string


class CommandLineApp(Command.Command):
    global_options = [Options.Option('h',
                                     'help',
                                     "show detailed help message"),
                      #Options.Option(None,
                      #               'help-commands',
                      #               "list available commands"),
                      #Options.Option(None,
                      #               'help-options',
                      #               "list available options"),
                      ]


    def __init__(self,
                 name,
                 description,
                 verbose_description,
                 subCommands,
                 options=None,
                 authenticationFunction=None,
                 ourOptions=None,
                 enableShowCommands=1,
                 ):


        self.script_name = None
        self.script_args = None
        self.stream = sys.stdout
        self.authenticationFunction = authenticationFunction
        self.enableShowCommands = enableShowCommands

        #The options that come into an application, are global to all commands in the application
        #The application has no options (unless ourOptions is specifed) but the defaults
        if options is None:
            subOptions = []
        else:
            subOptions = options

        #The app options are the show-commands option and the global options
        options = Options.Options(self.global_options)
        if self.enableShowCommands:
            # Part of the global options
            options.append(Options.Option(None,
                                          'show-commands',
                                          "show system command tree"),
                           )
        if ourOptions:
            options.extend(ourOptions)

        Command.Command.__init__(self,
                                 name,
                                 description,
                                 None,
                                 verbose_description,
                                 options = options,
                                 subCommands = subCommands,
                                 )

        commands = self.flatten_command_tree(0)
        for (level,cmd,fullName) in commands[1:]:
            cmd.options[0:0] = self.global_options + subOptions
                
    def run(self,script_name=None,script_args = None):

        if not script_name:
            self.script_name = sys.argv[0]
        else:
            self.script_name = script_name
        self.script_name = os.path.basename(self.script_name or '')
        if not script_args:
            self.script_args = sys.argv[1:]
        else:
            self.script_args = script_args

        cmd = self.parse_command_line()

        if cmd:
            try:
                cmd.run_command(self.authenticationFunction)
            except KeyboardInterrupt:
                raise SystemExit('interrupted')
            except ImportError, exc:
                raise SystemExit(str(exc))
        return 
        
        
    def parse_command_line(self):
        finalCmd = self
        try:
            finalCmd =  self._parse_command_opts(self.script_args)
            if finalCmd and not finalCmd.function:
                raise CommandLineUtil.ArgumentError(finalCmd,"no subcommand specified")
            return finalCmd
        except CommandLineUtil.ArgumentError, msg:
            help = self.gen_usage(msg.args[0])
            raise SystemExit(help + '\n' + msg.args[1])

    def validate_arguments(self,args):
        if len(args):
            raise CommandLineUtil.ArgumentError(self,"Invalid Subcommand: %s" % args[0])
        return 1

    def validate_options(self,options):
        if options.get('show-commands'):
            self.stream.write(self.gen_command_tree() + '\n')
            return None

        return Command.Command.validate_options(self,options)


    def gen_usage(self,command = None):
        """Generate usage, this includes command line, options, arguments, """

        command = command or self

        #Make the options look nice

        #Rebuild the command string
        commandPath = map(lambda x:x.name,self._build_command_path(command))
        command_string = ""
        command_string = '  %s %s ' % (self.script_name, string.join(commandPath,' '))

        lines = [self.description, '\nUsage:']
        lines.extend(command._gen_usage(command_string))
        lines.append('')
        return string.join(lines,'\n')


    def gen_command_tree(self):
        #Generate the command tree (a show all commands look)
        commands = self.flatten_command_tree(0)
        max_cmd = 0
        for (level, cmd,fullName) in commands:
            if (len(cmd.name) + level*2) > max_cmd:
                max_cmd = len(cmd.name) + level*2
        
        # column width = longest command + gutter
        col_width = max_cmd + 2
        text_width = 78 - col_width
        big_indent = ' ' * col_width
        lines = []
        
        last_level = 0
        first_level = 1
        for (level, cmd,fullName) in commands:
            if last_level > level or level == 0:
                lines.append('')    # 
            last_level = level

            indent = '  ' * level
            padding = max_cmd - (level * 2)
            text = CommandLineUtil.wrap_text(cmd.description, text_width)
            lines.append('%s%-*s  %s' % (indent, padding, cmd.name, text[0]))
            for line in text[1:]:
                lines.append(big_indent + line)

            if first_level:
                lines.append('')
                lines.append('Available Commands:')
                lines.append('')
                first_level = 0
                
        lines.append('\nTo see help on a specific command:\n')
        lines.append('  %s command [sub-command]... --help\n' % self.script_name)
        
        return string.join(lines, '\n')


    def get_help_doc_info(self):
        return map(lambda x:(x[2],x[1]),self.flatten_command_tree(0))

    def _build_command_path(self,command):

        #Build parent relationship
        self.build_parent_relationship()

        path = []
        cur = command
        while cur != self:
            path.append(cur)
            cur = cur.parent

        path.reverse()

        self.break_parent_relationship()
            
        return path


def GenIndex(doc,name,command,namePrefix=''):

    df = doc.createDocumentFragment()
    df.appendChild(dt)

    df.appendChild(dd)

    return df
    

if __name__ == '__main__':
    if len(sys.argv) < 2:
        raise SystemExit('output filename required')
    answer = raw_input('Are you sure (yes/no)? ')
    if answer == 'yes':
        open(sys.argv[1], 'w').write(GenHtml())
