#!/usr/bin/env python
from __future__ import print_function
from optparse import OptionParser

import sys
import os


# Messages
NO_ORDER = "No order given. Type 'fix -l' for a list of orders\n"
VERSION = 'LittleChef {0}'
INSTALL_ERROR = "LittleChef was not correctly installed: "\
              "Couldn't import littlechef.py"

## Try to import package and set the fabfile path ##
fabfile = None
try:
    import littlechef
    # Get absolute directory for imported littlechef package
    dirname = os.path.dirname(os.path.abspath(littlechef.__file__))
    # Build path to the runner fabfile to pass to fabric
    fabfile = os.path.join(dirname, 'runner.py')
except ImportError:
    print(INSTALL_ERROR)
    sys.exit(1)


class LittlechefOptionParser(OptionParser):

    def print_help(self, file=None):
        from fabric.main import list_commands, state, load_fabfile
        OptionParser.print_help(self, file)
        docstring, callables, default = load_fabfile(fabfile)
        state.commands.update(callables)
        for c in list_commands("\n", "normal"):
            print(c)
        sys.exit(0)

# commandline options
parser = LittlechefOptionParser()
parser.add_option(
    "-v", "--version", dest="version", action="store_true", default=False,
    help="Print littlechef version"
)
parser.add_option(
    "-l", dest="list_commands", action="store_true", default=False,
    help="List all available orders"
)
parser.add_option(
    "--no-report", dest="no_report", action="store_true", default=False,
    help="Don't save the chef-solo output as a report on the node"
)
parser.add_option(
    "--why-run", dest="whyrun", action="store_true", default=False,
    help="Do a configuration Whyrun, where no changes are performed to the node"
)
parser.add_option(
    "--verbose", dest="verbose", action="store_true", default=False,
    help="Output 'processing' statements"
)
parser.add_option(
    "--debug", dest="debug", action="store_true", default=False,
    help="Ask chef-solo for verbose and debugging output"
)
parser.add_option(
    "--env", dest="environment", default=None,
    help="Using a certain chef environment"
)
parser.add_option(
    "--concurrency", dest="concurrency", default=False,
    help="Executes commands concurrently"
)
(options, args) = parser.parse_args()


## Process args list and call fabric's main() ##
if not sys.argv:
    print(NO_ORDER)
else:
    if (os.path.basename(sys.argv[0]).startswith('fix')):
        # In windows, the first argument may be just "fix"
        fix_cmd = sys.argv[0]
    else:
        fix_cmd = None
    if len(sys.argv) == 1 and fix_cmd:
        # All that is in sys.argv is the fix command.
        print(NO_ORDER)
    else:
        # Check for version, that overrides everything else.
        if options.version:
            print(VERSION.format(littlechef.__version__))
            sys.exit(0)
        if options.no_report:
            littlechef.enable_logs = False
            sys.argv.remove('--no-report')
        if options.whyrun:
            littlechef.whyrun = True
            sys.argv.remove('--why-run')
        if options.concurrency:
            # --concurrency 5
            # --concurrency=5
            try:
                c = int(options.concurrency)
                littlechef.concurrency = c
                try:
                    sys.argv.remove('--concurrency={0}'.format(options.concurrency))
                except ValueError:
                    sys.argv.remove('--concurrency'.format(options.concurrency))
                    sys.argv.remove(options.concurrency)
            except ValueError:
                # --concurrency node:nodename
                try:
                    sys.argv.remove('--concurrency')
                    littlechef.concurrency = 0
                except ValueError:
                    pass

        if options.verbose:
            littlechef.verbose = True
            sys.argv.remove('--verbose')
        if options.debug:
            littlechef.loglevel = 'debug'
            littlechef.verbose = True
            sys.argv.remove('--debug')
        if options.environment is not None:
            # Check for mistakes:
            # * fix --env list_nodes
            # * fix --env nodes_with_role:bla role:authorization
            littlechef.chef_environment = options.environment
            try:
                # --env=ENV
                sys.argv.remove("--env={0}".format(options.environment))
            except ValueError:
                # --env ENV
                idx = sys.argv.index("--env")
                sys.argv.pop(idx)
                sys.argv.pop(idx)
                if not len(args) or ":" in options.environment:
                    parser.error("No value given for --env")

        # Otherwise, insert our fabfile at the correct place
        if fix_cmd:
            sys.argv[1:1] = ['-f', fabfile]
        else:
            sys.argv[0:0] = ['-f', fabfile]
        # Pass control over to fabric
        # Fabric should now import runner with COOKING = True
        littlechef.__cooking__ = True
        from fabric import main
        main.main()
