__author__ = 'epauben'

import subprocess

# flavor support methods
# flavors object contains a mapping of all tenant known flavors into a structure used to locate the 'best fit'
# for a VM's cpu/ram request.
#
# it is a container that sorted first by cpu count, then for each flavor of a cpu count and nother container
# hold the flavors of that cpu count sorted by ram.
# object is as follows
#
#   flavors = [
#               [
#                   cpuCount ,
#                    [
#                            [
#                               ram,
#                               flavor_name
#                           ],
#                           [
#                               ram,
#                               flavor_name
#                           ],
#                           ...
#                    ]
#               ],
#               [
#                   cpuCount ,
#                    [
#                            [
#                               ram,
#                               flavor_name
#                           ],
#                           [
#                               ram,
#                               flavor_name
#                           ],
#                           ...
#                    ]
#               ],
#               ...
#           ]
#
# the container is sorted on cpuCount. Each container under cpuCount is sorted by ram.
#
# Example:
# flavors = [
#               [ 1 , [ [ 1 , "m1.tiny"], [ 2, "m1.small" ] ] ],
#               [ 2 , [ [ 4 , "m1.medium" ] ] ],
#               [ 4 , [ [ 8,  "m1.large"  ] ] ],
#               [ 8 , [ [ 16, "m1.xlarge" ] ] ],
#           ]
#
#   Some key values then
#
#   len( flavors) - number of different CPU counts supported
#   for flavor in flavors:
#       flavor[0] = number of CPU's in this flavor family
#       for ramFlavor in flavor[1]:
#           ramFlavor[0] = Amount of RAM in this cpu/ram flavor
#           ramFlavor[1] = name of this cpu/ram pair

class openstackUtil:
    pass

flavors = []

def populateFlavors(server, tenantId):
    # populate the flavors container.

    global flavors

    with open('./.nfl.tmp','w') as n:
        retval = subprocess.call(['nova',
                                  '--os-auth-url', server['accessIP'],
                                  '--os-username', server['accessToken1'],
                                  '--os-password', server['accessToken2'],
                                  '--os-tenant-id',tenantId,
                                  'flavor-list'], stdout=n)
    if retval != 0:
        return False

    # parse the results
    for line in open('./.nfl.tmp','r'):
        if "+" not in line and 'Memory_MB' not in line:
        # then we want it.
        # do we have this cpu in the structure yet?
            s = line.split()
            cpu = int(s[12])
            ram = int(s[5])
            name = s[3]

            if ram > 1024:
                # then we'll take it.

                found = False
                for flavor in flavors:
                    if flavor[0] == cpu:
                        # yep! found it.
                        found = True
                        # append us.
                        flavor[1].append( [ ram, name ] )

                if not found:
                    # then we need to add a new cpu
                    flavors.append( [ cpu , [ [ ram, name] ] ])

    # now that they are in there - sort 'em.
    # this will sort on the cpu value.
    flavors = sorted(flavors)

    # now sort each of the cpu structures on the ram.
    for flavor in flavors:
        flavor[1] = sorted(flavor[1])

    return True


def getFlavor(vm,debug):
    # determine which flavor to give, based on the requested CPU and RAM.

    flavor = getFlavorObject(vm)

    if debug:
        print(". giving " + flavor[2] + " (cpu:"+str(flavor[0])+" ram:"+str(flavor[1])+") to vm " + vm["name"] + " at request for cpu:" + vm["cpu"] + " ram:" + vm["ram"])

    # return the flavor name
    return flavor[2]

def getFlavorObject(vm):
    # return an object that is the flavor details this vm would get.
    #   [ cpu, ram, name ]

    requestCpu = int(vm["cpu"])
    requestRam = int(vm["ram"])

    for flavor in flavors:
        if flavor[0] >= requestCpu:
            #this is the flavor
            break

    # ok - we now have the flavor - or have hit the end of the list and you're getting the best we got.
    for rams in flavor[1]:
        if rams[0] >= requestRam:
            # this is the ram
            break

    return [flavor[0], rams[0], rams[1]]



