from .. project import data_maker, project
from .. util import data_file, deprecated, log, pid_context

"""Common command line arguments for run and demo."""

COMPONENTS = 'driver', 'layout', 'animation'
PRESET_LIBRARY_DEFAULT = '~/.bibliopixel'
ENABLE_PRESETS = False
NUMBER_TYPES = ('python',) + data_maker.NUMPY_TYPES
ADD_REDUNDANT_ARGUMENTS = True


def add_arguments(parser):
    pid_context.add_arguments(parser)
    if ADD_REDUNDANT_ARGUMENTS:
        _add_redundant_arguments(parser)

    parser.add_argument(
        '-b', '--brightness', default=None,
        help='Override project brightness value')

    parser.add_argument(
        '--dump', action='store_true',
        help='Dump the full project as DATA_FILE after loading but ' +
             'before running')

    parser.add_argument(
        '--dry_run', action='store_true',
        help='Load projects but do not run them')

    parser.add_argument(
        '-f', '--fail_on_exception', action='store_true',
        help='If true, bp fail if any subanimation fails to construct')

    if deprecated.allowed():
        parser.add_argument(
            '-g', '--gif', default='', nargs='?', help=GIF_HELP)

    parser.add_argument(
        '-i', '--ignore_exceptions', action='store_true',
        help='If true, continue running the next project if one project fails')

    parser.add_argument(
        '-j', '--json', action='store_true',
        help='Use Json when dumping description data')

    parser.add_argument(
        '-m', '--movie', default='', nargs='?', help=MOVIE_HELP)

    parser.add_argument(
        '--pause', default=0, help='Time to pause between running animations')

    parser.add_argument(
        '--project_lengths', '--pl', default=None, help=PROJECT_LENGTHS_HELP)

    parser.add_argument(
        '-s', action='store_true', help='Run SimPixel at the default URL')

    parser.add_argument(
        '--simpixel', help='Run SimPixel at a specific URL')

    parser.add_argument(
        '--animation_lengths', '--at', default=None,
        help='Set run length for each animation')

    parser.add_argument(
        '-t', '--ledtype', default=None,
        help='Default LED type if no LED type is specified')


def _add_redundant_arguments(parser):
    """
    These arguments are redundant with just using a project, and we should
    encouraging that as you don't have to learn any dumb flags!

    For example, instead of

       bp foo.yml --animation=wombat --numbers=float

    use

       bp foo.yml + '{animation: wombat, numbers: float}'

    """
    parser.add_argument(
        '-a', '--animation', default=None,
        help='Default animation type if no animation is specified')

    if deprecated.allowed():  # pragma: no cover
        parser.add_argument(
            '--dimensions', '--dim', default=None,
            help='DEPRECATED: x, (x, y) or (x, y, z) dimensions for project')

    parser.add_argument(
        '--shape', default=None,
        help='x, (x, y) or (x, y, z) dimensions for project')

    parser.add_argument(
        '-l', '--layout', default=None,
        help='Default layout class if no layout is specified')

    parser.add_argument(
        '--numbers', '-n', default='python', choices=NUMBER_TYPES,
        help=NUMBERS_HELP)

    parser.add_argument('-p', '--path', default=None, help=PATH_HELP)


def _make_project_flags(args):
    def get_value(name):
        value = getattr(args, name, None)
        if not value:
            return {}

        if '{' in value:
            return data_file.loads(value)

        return {'typename': value}

    project_flags = {name: get_value(name) for name in COMPONENTS}
    if args.ledtype:
        project_flags['driver']['ledtype'] = args.ledtype

    if args.brightness:
        project_flags['layout']['brightness'] = int(args.brightness)

    if args.v4:
        log.printer('*** Using v4 forward compatibility mode.')
        project_flags['numbers'] = 'float'
    elif args.numbers != 'python':
        project_flags['numbers'] = args.numbers

    if args.project_lengths is not None:
        run = project_flags.setdefault('run', {})
        run['seconds'] = float(args.project_lengths)

    if args.animation_lengths is not None:
        animation = project_flags.setdefault('animation', {})
        length = [float(i) for i in args.animation_lengths.split(',')]
        animation['length'] = length

    if deprecated.allowed():
        if args.dimensions is not None:
            deprecated.deprecated('Use --shape instead of --dimensions')
        shape = args.shape or args.dimensions
    else:
        shape = args.shape

    if shape is not None:
        shape = shape.split(',')
        try:
            project_flags['shape'] = [int(i) for i in shape]
        except:
            raise ValueError('--shape must be one to three numbers '
                             'separated by commas.')

    return project_flags


def make_project(args, *descs, root_file=None):
    project_flags = _make_project_flags(args)
    descs += (project_flags,)
    return project.project(*descs, root_file=root_file)


# Help messages.

PATH_HELP = """\
A list of directories, separated by colons, 'which are added to the end of
`sys.path`.

You can also use loady-style paths which start with `//git/` to
dynamically load a library from a public git repository.

See https://github.com/ManiacalLabs/BiblioPixel/wiki/BiblioPixel-Paths
for more information.
"""

NUMBERS_HELP = """
The type of numbers that are used in color list calculations.

  `python` means to use the classic Python lists of (r, g, b) tuples.

  Anything else is a numpy type, which means that bp uses numpy arrays, which
  use much faster arithmetic.

  numpy types include:
    """ + ' '.join(data_maker.NUMPY_TYPES)

PRESET_HELP = """Filenames for preset library"""

PROJECT_LENGTHS_HELP = """\
How long to run the animation (overrides runner.seconds)"""

MOVIE_HELP = """
Write a movie file (animated GIF or mp4).

If --gif has no argument, the name of the movie file is the same as the name of
the project, with a .gif added to the end.

If it has a single string argument, then it's the name of the GIF file.

Otherwise, the argument is read as JSON and used to construct a GifWriter class.
"""

# TODO: this should go somewhere else
"""
Set defaults for projects using YAML or JSON data files.

A Project is a data file or equivalently a Python dictionary that describes
a BibliopPixel installation.  The top-level keys in a Project are called the
sections and a Project might have the following sections:

    {sections}

Often some sections of your project correspond to hardware and thus rarely
change, so the `bp default` command allows you to set defaults so you
don't have to mention these from your project at all.
"""

GIF_HELP = """
--gif/-g is a deprecated name for the --movie/-m flag."
""" + MOVIE_HELP
