'''
Created on Jan 12, 2011
Modified on Apr 25
@author: Dilum Bandara
@version: 0.2
@copyright: Copyright(c) 2011, Dilum Bandara
@license: GPL
'''

import random
import Config
import sys
import math
import copy

valid_atts = ['Loc', 'Lati', 'Longi', 'NType', 'KVer', 'FCName', 'CSp', \
                'NCore', 'CorePC', 'MSize', 'DSize', 'BWLim', 'CFree', 'DFree', 'Tx', \
              'MFree', 'RspT', 'UpT', '1mLd', 'TAve', 'Drift', '5mLd', 'Boot', 'Rx']

num_que = int(sys.argv[1])
if len(sys.argv) > 2 : 
    random.seed(sys.argv[2])
else: random.seed(12345)

def gen_distri(attribs):
    '''
    Generate empirical CDF
    @param attribs: Set of attributes to use
    '''
    tmp_total = 0
    distri = []
    for i in range(0, len(attribs)):
        if attribs[i][1] in valid_atts:
            distri.append([attribs[i][1], attribs[i][0] + tmp_total])
            tmp_total += attribs[i][0]
    return distri

def gen_range_distri(attribs):
    '''
    Generate query range
    @param attribs: Attribute to generate for
    '''
    tmp_total = 0
    distri = []
    for i in range(0, len(attribs)):
        distri.append([attribs[i][0] + tmp_total, attribs[i][1:]])
        tmp_total = tmp_total + attribs[i][0]
    return distri


def pick_new_attri(use_distri, att_set): 
    '''
    Pick an attribute based on given distribution
    @param use_distri:
    @param att_set:
    '''
    while 1:
        tmp_index = random.randint(1, use_distri[-1][1])
        for k in range(0, len(use_distri)):
            if tmp_index <= use_distri[k][1]:
                if use_distri[k][0] in att_set: break #Same attri 
                else : return use_distri[k][0]


def pick_next_attri(use_distri, att_set):
    '''
    Pick next attribute given distribution & attri list
    @param use_distri:
    @param att_set:
    '''
    while 1:
        tmp_index = random.randint(1, use_distri[-1][1])
        for k in range(0, len(use_distri)) :
            if tmp_index <= use_distri[k][1] :
                if use_distri[k][0] in att_set: #Already in 
                    l = 0
                    for tmp_att in use_distri:
                        if tmp_att[0] not in att_set: break #Atleast 1 attrib not in list
                        else: l = l + 1
                    if l == len(use_distri): #No candidate
                        return pick_new_attri(attri_use_distri_1, att_set)
                    else: break #Break for loop & retry
                else: 
                    return use_distri[k][0]

def pick_attrib_range(attrib):
    '''
    Pick attribute range
    @param attrib:
    '''
    distri = []
    min = 0.0
    max = 0.0
    if attrib == 'CUse' :
        distri = copy.deepcopy(cpu_use_range_distri)
        min = random.random() * Config.MAX_CPU_USE
        max = random.random() * Config.MAX_CPU_USE
    elif attrib == 'CSp':
        distri = copy.deepcopy(cpu_speed_range_distri)
        min = random.random() * Config.MAX_CPU_SPEED
        max = random.random() * Config.MAX_CPU_SPEED
    elif attrib == 'DFree':
        distri = copy.deepcopy(disk_free_range_distri)
        min = random.random() * Config.MAX_DISK_FREE
        max = random.random() * Config.MAX_DISK_FREE
    elif attrib == 'Drift' :
        distri = copy.deepcopy(disk_free_range_distri)
        min = random.random() * Config.MAX_DRIFT
        max = random.random() * Config.MAX_DRIFT
    elif attrib == '5mLd' :
        distri = copy.deepcopy(five_min_load_range_distri)
        min = random.random() * Config.MAX_5_MIN_LOAD
        max = random.random() * Config.MAX_5_MIN_LOAD
    elif attrib == 'CFree' :
        distri = copy.deepcopy(cpu_free_range_distri)
        min = random.random() * Config.MAX_CPU_FREE
        max = random.random() * Config.MAX_CPU_FREE
    elif attrib == 'MFree' :
        distri = copy.deepcopy(mem_free_range_distri)
        min = random.random() * Config.MAX_MEM_FREE
        max = random.random() * Config.MAX_MEM_FREE
    elif attrib == 'TAve' :
        distri = copy.deepcopy(timer_ave_range_distri)
        min = random.random() * Config.MAX_TIMER_AVE
        max = random.random() * Config.MAX_TIMER_AVE
    elif attrib == 'MSize' :
        distri = copy.deepcopy(mem_size_range_distri)
        min = random.random() * Config.MAX_MEM_SIZE
        max = random.random() * Config.MAX_MEM_SIZE
    elif attrib == '1mLd' :
        distri = copy.deepcopy(one_min_load_range_distri)
        min = random.random() * Config.MAX_1_MIN_LOAD
        max = random.random() * Config.MAX_1_MIN_LOAD
    elif attrib == 'RspT' :
        distri = copy.deepcopy(resp_time_range_distri)
        min = random.random() * Config.MAX_RESP_TIME
        max = random.random() * Config.MAX_RESP_TIME
    elif attrib == 'UpT':
        distri = copy.deepcopy(uptime_range_distri)
        min = random.random() * Config.MAX_UPTIME
        max = random.random() * Config.MAX_UPTIME
    elif attrib == 'BWLim' :
        distri = copy.deepcopy(bw_limit_range_distri)
        min = int(math.ceil(random.random() * Config.MAX_BW_LIMIT))
        max = int(math.ceil(random.random() * Config.MAX_BW_LIMIT))
    elif attrib == 'NType':
        distri = copy.deepcopy(node_type_range_distri)
        min = int(math.ceil(random.random() * Config.MAX_NODE_TYPE))
        max = int(math.ceil(random.random() * Config.MAX_NODE_TYPE))
    elif attrib == 'Boot' :
        distri = copy.deepcopy(boot_range_distri)
        min = int(math.ceil(random.random() * Config.MAX_BOOT))
        max = int(math.ceil(random.random() * Config.MAX_BOOT))
    elif attrib == 'KVer' :
        distri = copy.deepcopy(kern_ver_range_distri)
        min = int(math.ceil(random.random() * Config.MAX_KERN_VER))
        max = int(math.ceil(random.random() * Config.MAX_KERN_VER))
    elif attrib == 'Loc' :
        distri = copy.deepcopy(location_range_distri)
        min = int(math.ceil(random.random() * Config.MAX_LOCATION))
        max = int(math.ceil(random.random() * Config.MAX_LOCATION))
    elif attrib == 'NSlice' :
        distri = copy.deepcopy(num_slices_range_distri)
        min = int(math.ceil(random.random() * Config.MAX_NUM_SLICES))
        max = int(math.ceil(random.random() * Config.MAX_NUM_SLICES))
    elif attrib == 'FCName' :
        distri = copy.deepcopy(fc_namex_range_distri)
        min = int(math.ceil(random.random() * Config.MAX_FC_NAMEX))
        max = int(math.ceil(random.random() * Config.MAX_FC_NAMEX))
    elif attrib == 'Tx':
        distri = copy.deepcopy(tx_rate_range_distri)
        min = int(math.ceil(random.random() * Config.MAX_TX_RATE))
        max = int(math.ceil(random.random() * Config.MAX_TX_RATE))
    elif attrib == 'Rx':
        min = int(math.ceil(random.random() * Config.MAX_RX_RATE))
        max = int(math.ceil(random.random() * Config.MAX_RX_RATE))
    elif attrib == 'Lati':
        min = random.random() * 2 * Config.MAX_LATITUDE - Config.MAX_LATITUDE
        max = random.random() * 2 * Config.MAX_LATITUDE - Config.MAX_LATITUDE
    elif attrib == 'Longi':
        min = random.random() * 2 * Config.MAX_LONGITUDE - Config.MAX_LONGITUDE
        max = random.random() * 2 * Config.MAX_LONGITUDE - Config.MAX_LONGITUDE
    elif attrib == 'NCore' :
        min = int(math.ceil(random.random() * Config.MAX_NUM_CORES))
        max = int(math.ceil(random.random() * Config.MAX_NUM_CORES))
    elif attrib == 'CorePC' :
        min = int(math.ceil(random.random() * Config.MAX_CORES_PER_CPU))
        max = int(math.ceil(random.random() * Config.MAX_CORES_PER_CPU))
    elif attrib == 'DSize':
        min = random.random() * Config.MAX_DISK_SIZE
        max = random.random() * Config.MAX_DISK_SIZE
    else: print 'Unknown attribute ' + attrib

    if len(distri) > 0: #which one is smaller
        if min <= max: distri.append([distri[-1][0] + int(math.ceil(distri[-1][0]/10.0)),\
                                       [min, max]])
        else: distri.append([distri[-1][0] + int(math.ceil(distri[-1][0]/10.0)), [max, min]])
    else: #Only attribute value range
        if min <= max: distri.append([1, [min, max]])
        else: distri.append([1, [max, min]])

    tmp_index = random.randint(1, distri[-1][0]) #Pick random no
    for i in range(0, len(distri)) :
        if tmp_index <= distri[i][0] :    
            return distri[i][1]

#resource distribution
resource_distri = [Config.NUM_RESOURCES_FREQ[0]]
for i in range(1, len(Config.NUM_RESOURCES_FREQ)):
    resource_distri.append(resource_distri[i - 1] + Config.NUM_RESOURCES_FREQ[i])

#Attribute distribution
attrib_distri = [Config.NUM_ATTRIBS[0]]
for i in range(1, len(Config.NUM_ATTRIBS)):
    attrib_distri.append(attrib_distri[i - 1] + Config.NUM_ATTRIBS[i])

#Generate list of valid attributes for differnt no of attributes in a query
attri_use_1 = []
'''
attri_use_2 = []
attri_use_3 = []
attri_use_4 = []
attri_use_5 = []
attri_use_6 = []
attri_use_7 = []
'''
for i in range(0, len(valid_atts)):
    if valid_atts[i] in Config.OCCUR_1: attri_use_1.append(valid_atts[i])
'''
for i in range(0, len(valid_atts)):
    if valid_atts[i] in Config.OCCUR_2: attri_use_2.append(valid_atts[i])
for i in range(0, len(valid_atts)):
    if valid_atts[i] in Config.OCCUR_3: attri_use_3.append(valid_atts[i])
for i in range(0, len(valid_atts)):
    if valid_atts[i] in Config.OCCUR_4: attri_use_4.append(valid_atts[i])
for i in range(0, len(valid_atts)):
    if valid_atts[i] in Config.OCCUR_5: attri_use_5.append(valid_atts[i])
for i in range(0, len(valid_atts)):
    if valid_atts[i] in Config.OCCUR_6: attri_use_6.append(valid_atts[i])
for i in range(0, len(valid_atts)):
    if valid_atts[i] in Config.OCCUR_7: attri_use_7.append(valid_atts[i])
'''
#Build attribute distribution for each occurance list
attri_use_distri_1 = []
'''
attri_use_distri_2 = []
attri_use_distri_3 = []
attri_use_distri_4 = []
attri_use_distri_5 = []
attri_use_distri_6 = []
attri_use_distri_7 = []
'''
tmp_total = 0
for i in range(len(attri_use_1)):
    for j in range(len(Config.ATTRIBS)):
        if attri_use_1[i] == Config.ATTRIBS[j][1]: 
            attri_use_distri_1.append([Config.ATTRIBS[j][1], Config.ATTRIBS[j][0] + tmp_total])
            tmp_total = tmp_total + Config.ATTRIBS[j][0]
'''
tmp_total = 0
for i in range(0, len(attri_use_2)):
    for j in range(0, len(Config.ATTRIBS)):
        if attri_use_2[i] == Config.ATTRIBS[j][1]: 
            attri_use_distri_2.append([Config.ATTRIBS[j][1], Config.ATTRIBS[j][0] + tmp_total])
            tmp_total = tmp_total + Config.ATTRIBS[j][0]
tmp_total = 0
for i in range(0, len(attri_use_3)):
    for j in range(0, len(Config.ATTRIBS)):
        if attri_use_3[i] == Config.ATTRIBS[j][1]: 
            attri_use_distri_3.append([Config.ATTRIBS[j][1], Config.ATTRIBS[j][0] + tmp_total])
            tmp_total = tmp_total + Config.ATTRIBS[j][0]
tmp_total = 0
for i in range(0, len(attri_use_4)):
    for j in range(0, len(Config.ATTRIBS)):
        if attri_use_4[i] == Config.ATTRIBS[j][1]: 
            attri_use_distri_4.append([Config.ATTRIBS[j][1], Config.ATTRIBS[j][0] + tmp_total])
            tmp_total = tmp_total + Config.ATTRIBS[j][0]
tmp_total = 0
for i in range(0, len(attri_use_5)):
    for j in range(0, len(Config.ATTRIBS)):
        if attri_use_5[i] == Config.ATTRIBS[j][1]: 
            attri_use_distri_5.append([Config.ATTRIBS[j][1], Config.ATTRIBS[j][0] + tmp_total])
            tmp_total = tmp_total + Config.ATTRIBS[j][0]
tmp_total = 0
for i in range(0, len(attri_use_6)):
    for j in range(0, len(Config.ATTRIBS)):
        if attri_use_6[i] == Config.ATTRIBS[j][1]: 
            attri_use_distri_6.append([Config.ATTRIBS[j][1], Config.ATTRIBS[j][0] + tmp_total])
            tmp_total = tmp_total + Config.ATTRIBS[j][0]
tmp_total = 0
for i in range(0, len(attri_use_7)):
    for j in range(0, len(Config.ATTRIBS)):
        if attri_use_7[i] == Config.ATTRIBS[j][1]: 
            attri_use_distri_7.append([Config.ATTRIBS[j][1], Config.ATTRIBS[j][0] + tmp_total])
            tmp_total = tmp_total + Config.ATTRIBS[j][0]
'''
#Build conditional distributions for x
cpu_free_distri = gen_distri(Config.CPU_FREE)
disk_free_distri =  gen_distri(Config.DISK_FREE)
tx_rate_distri =  gen_distri(Config.TX_RATE)
mem_free_distri =  gen_distri(Config.MEM_FREE)
cpu_speed_distri =  gen_distri(Config.CPU_SPEED)
mem_size_distri =  gen_distri(Config.MEM_SIZE)
resp_time_distri =  gen_distri(Config.RESP_TIME)
one_min_load_distri =  gen_distri(Config.ONE_MIN_LOAD)
location_distri =  gen_distri(Config.LOCATION)
uptime_distri =  gen_distri(Config.UPTIME)
bw_limit_distri =  gen_distri(Config.BW_LIMIT)
fc_name_distri =  gen_distri(Config.FC_NAMEX)
five_min_load_distri =  gen_distri(Config.FIVE_MIN_LOAD)
kern_ver_distri =  gen_distri(Config.KERN_VER)
timer_ave_distri =  gen_distri(Config.TIMER_AVE)
drift_distri =  gen_distri(Config.DRIFT)
num_slice_distri =  gen_distri(Config.NUM_SLICES)

#cpu_use_range_distri = gen_range_distri(Config.RANGE_CPU_USE)
bw_limit_range_distri = gen_range_distri(Config.RANGE_BW_LIMIT)
cpu_speed_range_distri = gen_range_distri(Config.RANGE_CPU_SPEED)
disk_free_range_distri = gen_range_distri(Config.RANGE_DISK_FREE)
drift_range_distri = gen_range_distri(Config.RANGE_DRIFT)
five_min_load_range_distri = gen_range_distri(Config.RANGE_5_MIN_LOAD)
cpu_free_range_distri = gen_range_distri(Config.RANGE_CPU_FREE)
mem_free_range_distri = gen_range_distri(Config.RANGE_MEM_FREE)
node_type_range_distri = gen_range_distri(Config.RANGE_NODE_TYPE)
boot_range_distri = gen_range_distri(Config.RANGE_BOOT)
kern_ver_range_distri = gen_range_distri(Config.RANGE_KERN_VER)
timer_ave_range_distri = gen_range_distri(Config.RANGE_TIMER_AVE)
location_range_distri = gen_range_distri(Config.RANGE_LOCATION)
mem_size_range_distri = gen_range_distri(Config.RANGE_MEM_SIZE)
num_slices_distri = gen_range_distri(Config.RANGE_NUM_SLICES)
one_min_load_range_distri = gen_range_distri(Config.RANGE_1_MIN_LOAD)
fc_namex_range_distri = gen_range_distri(Config.RANGE_FC_NAMEX)
resp_time_range_distri = gen_range_distri(Config.RANGE_RESP_TIME)
tx_rate_range_distri = gen_range_distri(Config.RANGE_TX_RATE)
uptime_range_distri = gen_range_distri(Config.RANGE_UPTIME)


#generate queries
fdOut = open(Config.QUERY_FILE, 'w')

for i in range(0, num_que):   
    n = 0 #Num of resources queried for
    idx = -1
    tmp = random.randint(1, resource_distri[-1])    
    for j in range(len(resource_distri)):
        if tmp <= resource_distri[j]:
            idx = j
            break
    n = Config.NUM_RESOURCES[idx]

    m = 0 #Num of attributes
    tmp = random.randint(1, attrib_distri[-1])
    for j in range(len(attrib_distri)):
        if tmp <= attrib_distri[j]:
            m = j + 1
            break
    att_set = [pick_new_attri(attri_use_distri_1, [])] #Pick 1st attribute

    for j in range(1, m):
        not_found = True
        if att_set[j - 1] == 'CFree' and len(cpu_free_distri) > 0:
            att_set.append(pick_next_attri(cpu_free_distri, att_set))
        elif att_set[j - 1] == 'DFree' and len(disk_free_distri) > 0:
            att_set.append(pick_next_attri(disk_free_distri, att_set))
        elif att_set[j - 1] == 'Tx' and len(tx_rate_distri) > 0:
            att_set.append(pick_next_attri(tx_rate_distri, att_set))
        elif att_set[j - 1] == 'MFree' and len(mem_free_distri) > 0:
            att_set.append(pick_next_attri(mem_free_distri, att_set))
        elif att_set[j - 1] == 'CSp' and len(cpu_speed_distri) > 0:
            att_set.append(pick_next_attri(cpu_speed_distri, att_set))
        elif att_set[j - 1] == 'MSize' and len(mem_size_distri) > 0:      
            att_set.append(pick_next_attri(mem_size_distri, att_set))
        elif att_set[j - 1] == 'RspT' and len(resp_time_distri) > 0:
            att_set.append(pick_next_attri(resp_time_distri, att_set))
        elif att_set[j - 1] == '1mLd' and len(one_min_load_distri) > 0:
            att_set.append(pick_next_attri(one_min_load_distri, att_set))
        elif att_set[j - 1] == 'Loc' and len(location_distri) > 0:
            att_set.append(pick_next_attri(location_distri, att_set))
        elif att_set[j - 1] == 'UpT' and len(uptime_distri) > 0:
            att_set.append(pick_next_attri(uptime_distri, att_set))
        elif att_set[j - 1] == 'BWLim' and len(bw_limit_distri) > 0:
            att_set.append(pick_next_attri(bw_limit_distri, att_set))
        elif att_set[j - 1] == 'FCName' and len(fc_name_distri) > 0:
            att_set.append(pick_next_attri(fc_name_distri, att_set))
        elif att_set[j - 1] == '5mLd' and len(five_min_load_distri) > 0:
            att_set.append(pick_next_attri(five_min_load_distri, att_set))
        elif att_set[j - 1] == 'KVer' and len(kern_ver_distri) > 0:
            att_set.append(pick_next_attri(kern_ver_distri, att_set))
        elif att_set[j - 1] == 'TAve' and len(timer_ave_distri) > 0:
            att_set.append(pick_next_attri(timer_ave_distri, att_set))
        elif att_set[j - 1] == 'Drift' and len(drift_distri) > 0:
            att_set.append(pick_next_attri(drift_distri, att_set))
        elif att_set[j - 1] == 'NSlice' and len(num_slice_distri) > 0:
            att_set.append(pick_next_attri(num_slice_distri, att_set))
        else: #Unable to find attribute. Pick another random one
            att_set.append(pick_new_attri(attri_use_distri_1, att_set))

    tmp_str = 'n\t' + str(n)
    for j in range (0, len(att_set)):
        tmp_range = pick_attrib_range(att_set[j])
        tmp_str = tmp_str + '\t' + str(att_set[j]) + '\t' + str(tmp_range[0]) + '\t' + \
                    str(tmp_range[1])
    fdOut.write(tmp_str + '\n')

fdOut.close()    
