#!/usr/bin/env python
import requests
import json
import subprocess
import shlex
import sys
import re
import os
from distutils.spawn import find_executable


def collect_profile_data(action_id=None):

    # - hardware
    #      - lshw
    # - packages
    #      - apt
    #      - dpkg
    #      - ...
    # - network
    #      - ...
    # - storage
    #      - device
    #           - size, usage, inodes

    data = {
        'hardware': {},
        'packages': {},
        'network': {},
        'storage': {}
    }

    if find_executable('dpkg'):
        data['packages']['dpkg'] = parse_dpkg()
    if find_executable('pip'):
        data['packages']['pip'] = parse_pip()

    if find_executable('gem'):
        data['packages']['gem'] = parse_gem()

    if find_executable('lshw'):
        lshw = run_command('lshw -json')
        data['hardware']['lshw'] = json.loads(lshw)

    if find_executable('npm'):
        data['packages']['npm-global'] = parse_npm_global()
        data['packages']['npm-local'] = parse_npm_local()

    # The UUID will only be present within an Action context
    action_id = action_id or os.environ.get('JUJU_ACTION_UUID')
    if action_id:
        url = "http://{{ host }}:{{ port }}/api/units/{{ unit }}?action=%s" % action_id
    else:
        url = "http://{{ host }}:{{ port }}/api/units/{{ unit }}"

    requests.post(url, data=json.dumps(data))


def parse_gem():
    packages = []
    output = run_command('gem list')
    if output:
        p = re.compile('^([A-Za-z.]+)\W+([0-9.]+)')

        for line in output.split('\n'):
            m = p.match(line)
            if m:
                package = {
                    'name': m.groups()[0],
                    'version': m.groups()[1]
                }
                packages.append(package)
    return packages


def parse_pip():
    packages = []
    output = run_command('pip list')
    if output:
        p = re.compile('^([A-Za-z.]+)\W+([0-9.]+)')

        for line in output.split('\n'):
            m = p.match(line)
            if m:
                package = {
                    'name': m.groups()[0],
                    'version': m.groups()[1]
                }
                packages.append(package)
    return packages


def parse_dpkg():
    """
    Parse the output of `dpkg -l` to build a list of installed packages
    and their version/architecture.
    """
    packages = []
    output = run_command('dpkg -l')
    p = re.compile('\s+')
    for line in output.split('\n'):
        fields = p.split(line)
        if(len(fields) >= 4):
            status = fields[0]
            if (status == 'ii'):
                name = fields[1]
                version = fields[2]
                arch = fields[3]
                desc = " ".join(fields[4:])
                package = {
                    'status': status,
                    'name': name,
                    'arch': arch,
                    'version': version,
                    'desc': desc,
                }
                packages.append(package)
    return packages


def parse_npm_global():
    # Globally-installed modules
    return json.loads(run_command('npm -g ls --json'))


def parse_npm_local():
    # Locally-installed modules
    return json.loads(run_command('npm ls --json'))


def run_command(cmd):
    output = None
    try:
        output = subprocess.check_output(shlex.split(cmd))
    except subprocess.CalledProcessError:
        pass
    except IOError:
        pass
    except OSError:
        pass
    return output


if __name__ == "__main__":
    action_id = sys.argv[1] if len(sys.argv) > 1 else None
    collect_profile_data(action_id=action_id)
