'''
Created on June 22, 2011
@author: Dilum Bandara
@version: 0.1
@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)
selectivity = float(sys.argv[3])

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 pick_new_attri(att_set): 
    '''
    Pick an attribute based on given distribution
    @param use_distri:
    @param att_set:
    '''
    while 1:
        tmp_index = random.randint(0, len(valid_atts) - 1)
        if valid_atts[tmp_index] not in att_set: return valid_atts[tmp_index]

                
def pick_attrib_range(attrib):
    '''
    Pick attribute range
    @param attrib:
    '''
    distri = []
    min = 0.0
    max = 0.0
    if attrib == 'CUse' :
        half_svt = (Config.MAX_CPU_USE - Config.MIN_CPU_USE) * selectivity / 2  
        middle = random.uniform(Config.MIN_CPU_USE + half_svt, Config.MAX_CPU_USE - half_svt) 
        min = middle - half_svt
        max = middle + half_svt
    elif attrib == 'CSp':
        half_svt = (Config.MAX_CPU_SPEED - Config.MIN_CPU_SPEED) * selectivity / 2  
        middle = random.uniform(Config.MIN_CPU_SPEED + half_svt, Config.MAX_CPU_SPEED - half_svt) 
        min = middle - half_svt
        max = middle + half_svt
    elif attrib == 'DFree':
        half_svt = (Config.MAX_DISK_FREE - Config.MIN_DISK_FREE) * selectivity / 2  
        middle = random.uniform(Config.MIN_DISK_FREE + half_svt, Config.MAX_DISK_FREE - half_svt) 
        min = middle - half_svt
        max = middle + half_svt        
    elif attrib == 'Drift' :
        half_svt = (Config.MAX_DRIFT - Config.MIN_DRIFT) * selectivity / 2  
        middle = random.uniform(Config.MIN_DRIFT + half_svt, Config.MAX_DRIFT - half_svt) 
        min = middle - half_svt
        max = middle + half_svt        
    elif attrib == '5mLd' :
        half_svt = (Config.MAX_5_MIN_LOAD - Config.MIN_5_MIN_LOAD) * selectivity / 2  
        middle = random.uniform(Config.MIN_5_MIN_LOAD + half_svt, Config.MAX_5_MIN_LOAD - half_svt) 
        min = middle - half_svt
        max = middle + half_svt        
    elif attrib == 'CFree' :
        half_svt = (Config.MAX_CPU_FREE - Config.MIN_CPU_FREE) * selectivity / 2  
        middle = random.uniform(Config.MIN_CPU_FREE + half_svt, Config.MAX_CPU_FREE - half_svt) 
        min = middle - half_svt
        max = middle + half_svt        
    elif attrib == 'MFree' :
        half_svt = (Config.MAX_MEM_FREE - Config.MIN_MEM_FREE) * selectivity / 2  
        middle = random.uniform(Config.MIN_MEM_FREE + half_svt, Config.MAX_MEM_FREE - half_svt) 
        min = middle - half_svt
        max = middle + half_svt        
    elif attrib == 'TAve' :
        half_svt = (Config.MAX_TIMER_AVE - Config.MIN_TIMER_AVE) * selectivity / 2  
        middle = random.uniform(Config.MIN_TIMER_AVE + half_svt, Config.MAX_TIMER_AVE - half_svt) 
        min = middle - half_svt
        max = middle + half_svt        
    elif attrib == 'MSize' :
        half_svt = (Config.MAX_MEM_SIZE - Config.MIN_MEM_SIZE) * selectivity / 2  
        middle = random.uniform(Config.MIN_MEM_SIZE + half_svt, Config.MAX_MEM_SIZE - half_svt) 
        min = middle - half_svt
        max = middle + half_svt        
    elif attrib == '1mLd' :
        half_svt = (Config.MAX_1_MIN_LOAD - Config.MIN_1_MIN_LOAD) * selectivity / 2  
        middle = random.uniform(Config.MIN_1_MIN_LOAD + half_svt, Config.MAX_1_MIN_LOAD - half_svt) 
        min = middle - half_svt
        max = middle + half_svt        
    elif attrib == 'RspT' :
        half_svt = (Config.MAX_RESP_TIME - Config.MIN_RESP_TIME) * selectivity / 2  
        middle = random.uniform(Config.MIN_RESP_TIME + half_svt, Config.MAX_RESP_TIME - half_svt) 
        min = middle - half_svt
        max = middle + half_svt        
    elif attrib == 'UpT':
        half_svt = (Config.MAX_UPTIME - Config.MIN_UPTIME) * selectivity / 2  
        middle = random.uniform(Config.MIN_UPTIME + half_svt, Config.MAX_UPTIME - half_svt) 
        min = middle - half_svt
        max = middle + half_svt        
    elif attrib == 'BWLim' :
        half_svt = (Config.MAX_BW_LIMIT - Config.MIN_BW_LIMIT) * selectivity / 2  
        middle = random.uniform(Config.MIN_BW_LIMIT + half_svt, Config.MAX_BW_LIMIT - half_svt) 
        min = int(math.ceil(middle - half_svt))
        max = int(math.ceil(middle + half_svt))        
    elif attrib == 'NType':
        half_svt = (Config.MAX_NODE_TYPE - Config.MIN_NODE_TYPE) * selectivity / 2  
        middle = random.uniform(Config.MIN_NODE_TYPE + half_svt, Config.MAX_NODE_TYPE - half_svt) 
        min = int(math.ceil(middle - half_svt))
        max = int(math.ceil(middle + half_svt))        
    elif attrib == 'Boot' :
        half_svt = (Config.MAX_BOOT - Config.MIN_BOOT) * selectivity / 2  
        middle = random.uniform(Config.MIN_BOOT + half_svt, Config.MAX_BOOT - half_svt) 
        min = int(math.ceil(middle - half_svt))
        max = int(math.ceil(middle + half_svt))        
    elif attrib == 'KVer' :
        half_svt = (Config.MAX_KERN_VER - Config.MIN_KERN_VER) * selectivity / 2  
        middle = random.uniform(Config.MIN_KERN_VER + half_svt, Config.MAX_KERN_VER - half_svt) 
        min = int(math.ceil(middle - half_svt))
        max = int(math.ceil(middle + half_svt))        
    elif attrib == 'Loc' :
        half_svt = (Config.MAX_LOCATION - Config.MIN_LOCATION) * selectivity / 2  
        middle = random.uniform(Config.MIN_LOCATION + half_svt, Config.MAX_LOCATION - half_svt) 
        min = int(math.ceil(middle - half_svt))
        max = int(math.ceil(middle + half_svt))        
    elif attrib == 'NSlice' :
        half_svt = (Config.MAX_NUM_SLICES - Config.MIN_NUM_SLICES) * selectivity / 2  
        middle = random.uniform(Config.MIN_NUM_SLICES + half_svt, Config.MAX_NUM_SLICES - half_svt) 
        min = int(math.ceil(middle - half_svt))
        max = int(math.ceil(middle + half_svt))        
    elif attrib == 'FCName' :
        half_svt = (Config.MAX_FC_NAMEX - Config.MIN_FC_NAMEX) * selectivity / 2  
        middle = random.uniform(Config.MIN_FC_NAMEX + half_svt, Config.MAX_FC_NAMEX - half_svt) 
        min = int(math.ceil(middle - half_svt))
        max = int(math.ceil(middle + half_svt))        
    elif attrib == 'Tx':
        half_svt = (Config.MAX_TX_RATE - Config.MIN_TX_RATE) * selectivity / 2  
        middle = random.uniform(Config.MIN_TX_RATE + half_svt, Config.MAX_TX_RATE - half_svt) 
        min = int(math.ceil(middle - half_svt))
        max = int(math.ceil(middle + half_svt))        
    elif attrib == 'Rx':
        half_svt = (Config.MAX_RX_RATE - Config.MIN_RX_RATE) * selectivity / 2  
        middle = random.uniform(Config.MIN_RX_RATE + half_svt, Config.MAX_RX_RATE - half_svt) 
        min = int(math.ceil(middle - half_svt))
        max = int(math.ceil(middle + half_svt))        
    elif attrib == 'Lati':
        half_svt = (Config.MAX_LATITUDE - Config.MIN_LATITUDE) * selectivity / 2  
        middle = random.uniform(Config.MIN_LATITUDE + half_svt, Config.MAX_LATITUDE - half_svt) 
        min = middle - half_svt
        max = middle + half_svt        
    elif attrib == 'Longi':
        half_svt = (Config.MAX_LONGITUDE - Config.MIN_LONGITUDE) * selectivity / 2  
        middle = random.uniform(Config.MIN_LONGITUDE + half_svt, Config.MAX_LONGITUDE - half_svt) 
        min = middle - half_svt
        max = middle + half_svt
    elif attrib == 'NCore' :
        half_svt = (Config.MAX_NUM_CORES - Config.MIN_NUM_CORES) * selectivity / 2  
        middle = random.uniform(Config.MIN_NUM_CORES + half_svt, Config.MAX_NUM_CORES - half_svt) 
        min = int(math.ceil(middle - half_svt))
        max = int(math.ceil(middle + half_svt))        
    elif attrib == 'CorePC' :
        half_svt = (Config.MAX_CORES_PER_CPU - Config.MIN_CORES_PER_CPU) * selectivity / 2  
        middle = random.uniform(Config.MIN_CORES_PER_CPU + half_svt, Config.MAX_CORES_PER_CPU - half_svt) 
        min = int(math.ceil(middle - half_svt))
        max = int(math.ceil(middle + half_svt))        
    elif attrib == 'DSize':
        half_svt = (Config.MAX_DISK_SIZE - Config.MIN_DISK_SIZE) * selectivity / 2  
        middle = random.uniform(Config.MIN_DISK_SIZE + half_svt, Config.MAX_DISK_SIZE - half_svt) 
        min = middle - half_svt
        max = middle + half_svt
    else: print 'Unknown attribute ' + attrib

    if min > max: print "Min > Max"
    return [min, max]


#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 different no of attributes in a query
attri_use_1 = []
for i in range(0, len(valid_atts)):
    if valid_atts[i] in Config.OCCUR_1: attri_use_1.append(valid_atts[i])
#Build attribute distribution for each occurance list
attri_use_distri_1 = []
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]


#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([])] #Pick 1st attribute

    #Add other attributes
    for j in range(1, m): att_set.append(pick_new_attri(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()    
