#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright 2009 Canonical Ltd.
# Author 2009 Didier Roche
#
# This file is part of Quickly
#
#This program is free software: you can redistribute it and/or modify it 
#under the terms of the GNU General Public License version 3, as published 
#by the Free Software Foundation.

#This program is distributed in the hope that it will be useful, but 
#WITHOUT ANY WARRANTY; without even the implied warranties of 
#MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR 
#PURPOSE.  See the GNU General Public License for more details.

#You should have received a copy of the GNU General Public License along 
#with this program.  If not, see <http://www.gnu.org/licenses/>.


import os, re
import sys
import subprocess
import gettext
from gettext import gettext as _

# add quickly root directory (especially for trunk execution)
quickly_root_directory = os.path.dirname(sys.argv[0])
quickly_root_directory = os.path.abspath(quickly_root_directory + '/..')
if os.path.exists(quickly_root_directory + '/quickly') and quickly_root_directory not in sys.path:
    sys.path.insert(0, quickly_root_directory)
    os.putenv('PYTHONPATH', quickly_root_directory) # for subprocesses

from quickly import commands, configurationhandler, quicklyconfig, tools, version

gettext.textdomain('quickly')


def usage():
    print _("""Usage:
    quickly [OPTIONS] command ...

Options:
    -t, --template <template>  Template to use if it differs from default
                               project one
                               one used to create the project)
    --staging                  Target launchpad staging server
    --verbose                  Verbose mode
    -h, --help                 Show help information

Commands:
    create <template> <project-name> (template is mandatory for this command)
    quickly <template_origin> <template_dest> to create a create derived template
    getstarted to get some starting hints

Examples:
    quickly create ubuntu-project foobar
    quickly push 'awesome new comment system'
    quickly -t cool-template push 'awesome new comment system'""")

def process_command_line(argv):
    """Entry point for command line processing
    use sys.argv by default if no args to parse

    :return: options
    """

    opt_command = []
    opt_template = None
    i = 0

    while i < len(argv):
        arg = argv[i]

        if arg.startswith('-'):
            if arg == '--template' or arg == '-t':
                opt_template = argv[i + 1]
                i += 1
            elif arg == '--staging':
                oldenv = ""
                if os.environ.has_key('QUICKLY'):
                    oldenv = os.environ['QUICKLY']
                os.environ['QUICKLY'] = "staging:" + oldenv
            elif arg == '--verbose':
                oldenv = ""
                if os.environ.has_key('QUICKLY'):
                    oldenv = os.environ['QUICKLY']
                os.environ['QUICKLY'] = "verbose:" + oldenv
            elif arg == '--version':
                version.show_version()
                sys.exit(0)
            elif arg == '--help' or arg == '-h':
                usage()
                sys.exit(1)
            else:
                opt_command.append(arg) # temporary solution, see commit.
        else:
            opt_command.append(arg)
        i += 1

    if len(opt_command) == 0:
        print _("ERROR: No command provided in command line")
        usage()
        sys.exit(1)

    return (opt_command, opt_template)


def get_commands():
    """seek for available commands for shell completion

    : return tuples with list of available commands and origin (default or template)
    """

    available_completion = []

    # option completion
    if sys.argv[-1].startswith("-"):
        options = ("-h", "--help", "-t", "--template", "--staging", "--verbose", "--version")
        available_completion = [option for option in options if option.startswith(sys.argv[-1])]
        print " ".join(available_completion)
        return(0)

    # get available templates after option if needed
    if sys.argv[-2] in ("-t", "--template"):
        available_completion.extend(commands.get_all_templates())
        print " ".join(available_completion)
        return(0)        
    
    # treat commands and try to get the template from the project directory if we are in a project (if not already provided by the -t option)
    (opt_command, opt_template) = process_command_line(sys.argv[3:])
    if not opt_template and configurationhandler.loadConfig(can_stop=False) == 0:
        try:
            opt_template = configurationhandler.project_config['template']
        except KeyError:
            pass
    # if no command, check for available command
    if len(opt_command) == 1:
        # list available command in template if suit context
        if opt_template:
            available_completion.extend([command.name for command in commands.get_command_by_criteria(template=opt_template) if command.is_right_context(os.getcwd(), verbose=False)])
        # add builtins command and commands that are followed by template
        available_completion.extend([command.name for command in commands.get_command_by_criteria(template="builtins") if command.is_right_context(os.getcwd(), verbose=False)])
        available_completion.extend([command.name for command in commands.get_command_by_criteria(followed_by_template=True) if command.is_right_context(os.getcwd(), verbose=False)])      
        
    else:
        # ask for the command what she needs (it automatically handle the case of command followed by template and command followed by command)
        available_completion.extend([command.shell_completion(opt_template, opt_command[1:]) for command in commands.get_command_by_criteria(name=opt_command[0])]) # as 1: is '' or the begining of a word
        
    print " ".join(elem for elem in available_completion if elem is not None)
    return(0)

def main():
    """Main ubuntu command line processor

    :return: exit code of quickly command.
    """

    (opt_command, opt_template) = process_command_line(sys.argv[1:])
    command_name = opt_command[0]
    
    # try to get the template from the project directory if we are in a project (if not already provided by the -t option)
    if not opt_template and configurationhandler.loadConfig(can_stop=False) == 0:
        try:
            opt_template = configurationhandler.project_config['template']
        except KeyError:
            pass

    # check that the command exists in current template
    if opt_template:
        if not tools.check_template_exists(opt_template):
            return(1)

        # with this search, we are sure that only one command: (name,template) is unique
        try:
            command = commands.get_command_by_criteria(name=command_name, template=opt_template)[0]
        except IndexError:
            # if not found, try for builtins command
            try:
                command = commands.get_command_by_criteria(name=command_name, template='builtins')[0]
            except IndexError: 
                print _("ERROR: No %s command found in template %s.") % (command_name, opt_template)
                print _("Aborting.")
                return(1)
            
    # from this line, if we don't have a template, only builtins commands and template command followed_by_template are candidates
    else:
        # check for a builtin command (again, one solution only)
        try:
            command = commands.get_command_by_criteria(name=command_name, template='builtins')[0]    
            # if it's a builtin command which has to be followed by a template, check that everything is correct
            if command.followed_by_template:
                try:
                    # this condition is for the case of, for instance $ quickly help <builtin_command> (no template associated and can be followed by a builtin command)
                    if not (command.followed_by_command and len(opt_command) == 2):
                        opt_template = opt_command[1]
                        opt_command.remove(opt_command[1])
                        if not tools.check_template_exists(opt_template):
                            return(1)
                except IndexError:
                    print _("ERROR: %s command must be followed by a template and no template was found on the command line." % command_name)
                    print _("Candidates template are: %s") % ", ".join(commands.get_all_templates())
                    return(1)
        except IndexError:        
            # so, check for a template command followed by template
            try:
                command = commands.get_command_by_criteria(name=command_name, template=opt_command[1], followed_by_template=True)[0]
                opt_template = opt_command[1]
                opt_command.remove(opt_command[1])
            except IndexError:
                # to help the user, we can search if this command_name corresponds to a command in a template
                list_possible_commands = commands.get_command_by_criteria(name=command_name, followed_by_template=True)
                if list_possible_commands:
                   print _("ERROR: %s command must be followed by a template and no template was found on the command line." % command_name)
                   print _("Candidates template are: %s") % ", ".join([command.template for command in list_possible_commands])
                else:
                    list_possible_commands = commands.get_command_by_criteria(name=command_name, followed_by_template=False)
                    if list_possible_commands:
                       print _("No template were found on the command line for command %s." % command_name)
                       print _("Candidates template are: %s") % ", ".join([command.template for command in list_possible_commands])                        
                    else:
                        # there is really not such command, in any template
                        print _("ERROR: No %s command found.") % command_name
                print _("Aborting.")
                return(1)

    return(command.launch(os.getcwd(), opt_command[1:], opt_template))


if __name__ == '__main__':

    if len(sys.argv) == 1:
        usage()
        sys.exit(1)
    # process the command line to send the right instructions
    if sys.argv[1] == 'shell-completion':
        exit(get_commands())
    else:
        exit(main())

