#!/usr/bin/env python
# coding=utf-8
"""
A simple example demonstrating how to enable tab completion by assigning a completer function to do_* commands.
This also demonstrates capabilities of the following completer features included with cmd2:
- CompletionError exceptions
- delimiter_complete()
- flag_based_complete() (see note below)
- index_based_complete() (see note below)

flag_based_complete() and index_based_complete() are basic methods and should only be used if you are not
familiar with argparse. The recommended approach for tab completing positional tokens and flags is to use
argparse-based completion. For an example integrating tab completion with argparse, see argparse_completion.py
"""

import functools
from typing import (
    List,
)

import cmd2

# List of strings used with completion functions
food_item_strs = ['Pizza', 'Ham', 'Ham Sandwich', 'Potato']
sport_item_strs = ['Bat', 'Basket', 'Basketball', 'Football', 'Space Ball']

# This data is used to demonstrate delimiter_complete
file_strs = [
    '/home/user/file.db',
    '/home/user/file space.db',
    '/home/user/another.db',
    '/home/other user/maps.db',
    '/home/other user/tests.db',
]


class BasicCompletion(cmd2.Cmd):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def do_flag_based(self, statement: cmd2.Statement):
        """Tab completes arguments based on a preceding flag using flag_based_complete
        -f, --food [completes food items]
        -s, --sport [completes sports]
        -p, --path [completes local file system paths]
        """
        self.poutput("Args: {}".format(statement.args))

    def complete_flag_based(self, text, line, begidx, endidx) -> List[str]:
        """Completion function for do_flag_based"""
        flag_dict = {
            # Tab complete food items after -f and --food flags in command line
            '-f': food_item_strs,
            '--food': food_item_strs,
            # Tab complete sport items after -s and --sport flags in command line
            '-s': sport_item_strs,
            '--sport': sport_item_strs,
            # Tab complete using path_complete function after -p and --path flags in command line
            '-p': self.path_complete,
            '--path': self.path_complete,
        }

        return self.flag_based_complete(text, line, begidx, endidx, flag_dict=flag_dict)

    def do_index_based(self, statement: cmd2.Statement):
        """Tab completes first 3 arguments using index_based_complete"""
        self.poutput("Args: {}".format(statement.args))

    def complete_index_based(self, text, line, begidx, endidx) -> List[str]:
        """Completion function for do_index_based"""
        index_dict = {
            1: food_item_strs,  # Tab complete food items at index 1 in command line
            2: sport_item_strs,  # Tab complete sport items at index 2 in command line
            3: self.path_complete,  # Tab complete using path_complete function at index 3 in command line
        }

        return self.index_based_complete(text, line, begidx, endidx, index_dict=index_dict)

    def do_delimiter_complete(self, statement: cmd2.Statement):
        """Tab completes files from a list using delimiter_complete"""
        self.poutput("Args: {}".format(statement.args))

    # Use a partialmethod to set arguments to delimiter_complete
    complete_delimiter_complete = functools.partialmethod(cmd2.Cmd.delimiter_complete, match_against=file_strs, delimiter='/')

    def do_raise_error(self, statement: cmd2.Statement):
        """Demonstrates effect of raising CompletionError"""
        self.poutput("Args: {}".format(statement.args))

    def complete_raise_error(self, text, line, begidx, endidx) -> List[str]:
        """
        CompletionErrors can be raised if an error occurs while tab completing.

        Example use cases
            - Reading a database to retrieve a tab completion data set failed
            - A previous command line argument that determines the data set being completed is invalid
        """
        raise cmd2.CompletionError("This is how a CompletionError behaves")


if __name__ == '__main__':
    import sys

    app = BasicCompletion()
    sys.exit(app.cmdloop())
