#!/usr/bin/python
"""Client tool for interacting with Kickstand server"""

import configargparse
import json
import os
import subprocess
import sys

from kickstand import Communicator
from kickstand import inventory
from kickstand.inventory import Machine
from kickstand.inventory import Status

COMMAND_UNAME = '/bin/uname'
FLAGS_UNAME = '--all'

COMMAND_IFCONFIG = '/sbin/ifconfig'

PROPERTY_DEFINITIONS = [
  { 'name': 'Hardware',
    'short_name': 'hardware',
    'components': [
      { 'name': 'Memory',
        'short_name': 'memory',
        'properties': [
          { 'name': 'Total',
            'short_name': 'memoryTotal',
          },
          { 'name': 'Free',
            'short_name': 'memoryFree',
          },
        ]
      },
    ]
  }
]

META_PROPERTIES = {}

def parseArgs():
  arg_parser = configargparse.ArgumentParser(prog='kickstand-client',
      default_config_files=['/etc/kickstand.ini', '~/.kickstand.ini'],
      description='Client tool to interact with Kickstand server.')
  arg_parser.add_argument('--ifconfig-bin', dest='BIN_IFCONFIG', default='/sbin/ifconfig', help='Location of the ifconfig binary.')
  arg_parser.add_argument('--uname-bin', dest='BIN_UNAME', default='/bin/uname', help='Location of the uname binary.')
  arg_parser.add_argument('--hostname-bin', dest='BIN_HOSTNAME', default='/bin/hostname', help='Location of the hostname binary.')

  arg_parser.add_argument('-s', '--server', dest='SERVER', help='Kickstand server.')

  return arg_parser.parse_args()

def createComponentCategory(communicator, name, shortname):
  return communicator.post('/inventory/componentcategories', data={'name': name, 'short_name':shortname}).json()

def getComponentCategory(communicator, shortname):
  result = communicator.get('/inventory/componentcategories').json()
  for component in result:
    if( component['short_name'] == shortname ):
      return component
  return None

def createComponent(communicator, category_id, name, shortname):
  return communicator.post('/inventory/componentcategories/%d/components' % category_id, data={'name':name, 'short_name':shortname}).json()

def getComponent(communicator, category_id, shortname):
  result = communicator.get('/inventory/componentcategories/%d/components' % category_id).json()
  for category in result:
    if( category['short_name'] == shortname ):
      return category
  return None

def createProperty(communicator, category_id, component_id, name, shortname):
  return communicator.post('/inventory/componentcategories/%d/components/%d/properties' % (category_id, component_id), data={'name':name, 'short_name':shortname}).json()

def getProperty(communicator, category_id, component_id, shortname):
  result = communicator.get('/inventory/componentcategories/%d/components/%d/properties' % (category_id, component_id)).json()
  for property in result:
    if( property['short_name'] == shortname ):
      return property
  return None

def createMachine(communicator, fqdn):
  return communicator.post('/inventory/machines', data={'fqdn':fqdn,'status':4,'group':1}).json()

def getMachine(communicator, fqdn):
  result = communicator.get('/inventory/machines?fqdn=%s' % fqdn).json()
  if( len(result) == 1 ):
    return result[0]
  else:
    return None

def setMachineProperties(communicator, machine_id, property_list):
  """Sets the properties for a machine
  property_list: list
    example: [ category_id: [
                 component_id: [
                   property_id: value,
                    property_id: value
                  ]]]
  """
  for category_id in property_list:
    for component_id in property_list[category_id]:
      list = []
      for property_id in property_list[category_id][component_id]:
        list.append({'property': property_id, 'value': property_list[category_id][component_id][property_id]})
      print list
      communicator.post('/inventory/machines/%d/componentcategories/%d/components/%d/properties' % (machine_id, category_id, component_id), data=json.dumps(list))

def ensureProperties(communicator):
  for category in PROPERTY_DEFINITIONS:
    cat = getComponentCategory(communicator, category['short_name'])
    if( cat is None ):
      cat = createComponentCategory(communicator, category['name'], category['short_name'])
    META_PROPERTIES[cat['short_name']] = {'id': cat['id'], 'components': {}}
    for component in category['components']:
      comp = getComponent(communicator, cat['id'], component['short_name'])
      if( comp is None ):
        comp = createComponent(communicator, cat['id'], component['name'], component['short_name'])
      META_PROPERTIES[cat['short_name']]['components'][comp['short_name']] = {'id': comp['id'], 'properties':{}}
      for property in component['properties']:
        prop = getProperty(communicator, cat['id'], comp['id'], property['short_name'])
        if( prop is None ):
          prop = createProperty(communicator, cat['id'], comp['id'], property['name'], property['short_name'])
        META_PROPERTIES[cat['short_name']]['components'][comp['short_name']]['properties'][prop['short_name']] = {'id': prop['id']}

def run(command):
  """Runs a command
  command: list of command parts
  """
  output,error = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
  return output.split('\n')

def main(args):
  """Main function for client tool"""
  communicator = Communicator(args.SERVER)
  ensureProperties(communicator)

  fqdn = run([args.BIN_HOSTNAME, '-f'])[0]

  machine = getMachine(communicator, fqdn)
  if( machine is None ):
    createMachine(communicator, fqdn)
    machine = getMachine(communicator, fqdn)

  # Man this is a terrible chunk of code.
  memory_info = run(['cat', '/proc/meminfo'])
  mem_temp_info = {}
  for line in memory_info:
    if( ':' not in line ):
      continue
    spli = line.split(':')
    mem_temp_info[spli[0]] = spli[1].lstrip(' ')
  # Like, seriously, who uses a final name for temporary data only to replace it?
  # Wasteful
  memory_info = mem_temp_info

  setMachineProperties(communicator, machine['id'], {
    META_PROPERTIES['hardware']['id']: {
      META_PROPERTIES['hardware']['components']['memory']['id']: {
        META_PROPERTIES['hardware']['components']['memory']['properties']['memoryTotal']['id']: memory_info['MemTotal'],
        META_PROPERTIES['hardware']['components']['memory']['properties']['memoryFree']['id']: memory_info['MemFree'],
      },
    },
  })

if( __name__ == '__main__' ):
  args = parseArgs()
  main(args)
