#! /usr/bin/python
"""
get_entities.py

Usage: get_entities.py [OPTION] ... [ATTRIBUTE] ...

Query the Home Assistant API for available entities then print them and any
desired attributes to the screen.

Options:
    -h, --help                      display this text
        --password=PASS             use the supplied password
        --ask-password              prompt for password
    -a, --address=ADDR              use the supplied server address
    -p, --port=PORT                 use the supplied server port
"""
import sys
import getpass
try:
    from urllib2 import urlopen
    PYTHON = 2
except ImportError:
    from urllib.request import urlopen
    PYTHON = 3
import json


def main(password, askpass, attrs, address, port):
    """ fetch Home Assistant api json page and post process """
    # ask for password
    if askpass:
        password = getpass.getpass('Home Assistant API Password: ')

    # fetch API result
    url = mk_url(address, port, password)
    response = urlopen(url).read()
    if PYTHON == 3:
        response = response.decode('utf-8')
    data = json.loads(response)

    # parse data
    output = {'entity_id': []}
    output.update([(attr, []) for attr in attrs])
    for item in data:
        output['entity_id'].append(item['entity_id'])
        for attr in attrs:
            output[attr].append(item['attributes'].get(attr, ''))

    # output data
    print_table(output, ['entity_id'] + attrs)


def print_table(data, columns):
    """ format and print a table of data from a dictionary """
    # get column lengths
    lengths = {}
    for key, value in data.items():
        lengths[key] = max([len(str(val)) for val in value] + [len(key)])

    # print header
    for item in columns:
        itemup = item.upper()
        sys.stdout.write(itemup + ' ' * (lengths[item] - len(item) + 4))
    sys.stdout.write('\n')

    # print body
    for ind in range(len(data[columns[0]])):
        for item in columns:
            val = str(data[item][ind])
            sys.stdout.write(val + ' ' * (lengths[item] - len(val) + 4))
        sys.stdout.write("\n")


def mk_url(address, port, password):
    """ construct the url call for the api states page """
    url = ''
    if address.startswith('http://'):
        url += address
    else:
        url += 'http://' + address
    url += ':' + port + '/api/states?'
    if password is not None:
        url += 'api_password=' + password
    return url


def parse(option, all_options):
    """ either update the options or set it to be updated next time """
    if len(option) > 1:
        all_options[option[0]] = option[1]
        return (all_options, None)
    else:
        return (all_options, option)


if __name__ == "__main__":
    all_options = {'password': None, 'askpass': False, 'attrs': [],
                   'address': 'localhost', 'port': '8123'}

    # parse arguments
    next_key = None
    for arg in sys.argv[1:]:
        if next_key is None:
            option = arg.split('=')

            if option[0] in ['-h', '--help']:
                print(__doc__)
                sys.exit(0)

            elif option[0] == '--password':
                all_options['password'] = '='.join(option[1:])

            elif option[0] == '--ask-password':
                all_options['askpass'] = True

            elif option[0] == '-a':
                next_key = 'address'

            elif option[0] == '--address':
                all_options['address'] = '='.join(option[1:])

            elif option[0] == '-p':
                next_key = 'port'

            elif option[0] == '--port':
                all_options['port'] = '='.join(option[1])

            else:
                all_options['attrs'].append('='.join(option))

        else:
            all_options[next_key] = arg
            next_key = None

    main(**all_options)