__author__ = 'Dilum Bandara'
__version__ = "1.0"
__date__ = "03/14/2011"
__license__ = 'Python'
__copyright__ = "Copyright (c) 2011 Dilum Bandara, Colorado State University"

''' Use this tool to extract node data from CoMon raw data file generated using extractData.py
    Can be used to extract data for a given time instance or a range
'''
import re
import sys

#TODO Update following list based on attributes that are needed to be extracted. 
#Sequential Node IDs & time will be added automatically
attbs_to_extract = ['CPUSpeed', 'NumCores', 'CPUFree', '1MinLoad', 'MemSize', 'MemFree', 'DiskFree', 'TxRate', 'RxRate']
#attbs_to_extract = ['CPUSpeed', 'NumCores', 'CPUFree', '1MinLoad', '5MinLoad', '15MinLoad', 'MemSize', 'MemFree', \
#                    'DiskSize', 'DiskFree', 'TxRate', 'RxRate', 'Location', 'Latitude', 'Longitude', 'CoresPerCPU', \
#                    'BWLimit', 'RespTime', 'Uptime', 'TimerAve', 'Drift', 'TimerMax', 'SwapUsed']
fIn = sys.argv[1]
fOut = 'resources.txt' #Output file name
START_TIME = 86400.0 * 7 - 300.0 #TODO Start time of 1st data sample. Change following depending on time range
END_TIME = START_TIME + 1.0  #if -1.0 no time limit, extract what's available
SAMPLING_INTERVAL = 300.0
next_nid = 0 #ID of the next node. 0 based index

node_IP_list = []
node_ID_list = []
skip_node_list = [] #Nodes to skip because they were not active at least once
resources = []
count = 0

time = IP = respTime = swapIn = swapOut = diskIn = diskOut = diskSvc = diskUtil = upTime = oneMinLoad = \
fiveMinLoad = fifteenMinLoad = timerMax = timerAve = memPress = diskUsed = diskFree = diskSize = memSize = \
memActive = swapUsed = kernVer = cpuFree = cpuSpeed = fcNamex = numCores = coresPerCPU = txRtae = rxRate \
= bootState = nodeType = bwLimit = lati = longi = location = drift = '-1'
end = 0    #end of an entry 0 - no, 1 - yes
att_list = []
last_time = {}
fdIn = open(fIn, 'r')

for line in fdIn:
    #Modify following to extract attributes not defined below
    tmp = line.split()
    if len(att_list) == 0:       
        att_list = tmp #1st line
        continue
    tmp_time = float(tmp[2]) #Get time
    if tmp_time > END_TIME and END_TIME != -1: break #Don't need more than this
    elif tmp_time < START_TIME: continue #Don't need these

    for i in range(0, len(att_list)):
        if att_list[i] == 'IP' : IP = tmp[i]
        elif att_list[i] == 'time': time = tmp[i]
        elif att_list[i] == 'RespTime': respTime = tmp[i]
        elif att_list[i] == 'SwapIn': swapIn = tmp[i]
        elif att_list[i] == 'SwapOut': swapOut = tmp[i]
        elif att_list[i] == 'DiskIn': diskIn = tmp[i]
        elif att_list[i] == 'DiskOut': diskOut = tmp[i]
        elif att_list[i] == 'DiskSvc': diskSvc = tmp[i]
        elif att_list[i] == 'DiskUtil': diskUtil = tmp[i]
        elif att_list[i] == 'Uptime': upTime = tmp[i]
        elif att_list[i] == '1MinLoad': oneMinLoad = tmp[i]
        elif att_list[i] == '5MinLoad': fiveMinLoad = tmp[i]
        elif att_list[i] == '15MinLoad': fifteenMinLoad = tmp[i]
        elif att_list[i] == 'TimerMax': timerMax = tmp[i]
        elif att_list[i] == 'TimerAve': timerAve = tmp[i]
        elif att_list[i] == 'MemFree': memPress = tmp[i]
        elif att_list[i] == 'DiskUsed': diskUsed = tmp[i]
        elif att_list[i] == 'DiskFree': diskFree = tmp[i]
        elif att_list[i] == 'DiskSize': diskSize = tmp[i]
        elif att_list[i] == 'MemSize': memSize = tmp[i]
        elif att_list[i] == 'MemActive': memActive = tmp[i]
        elif att_list[i] == 'SwapUsed': swapUsed = tmp[i]
        elif att_list[i] == 'KernVer': kernVer = tmp[i]
        elif att_list[i] == 'CPUFree': cpuFree = tmp[i]
        elif att_list[i] == 'CPUSpeed': cpuSpeed = tmp[i]
        elif att_list[i] == 'FCNamex': fcNamex = tmp[i]
        elif att_list[i] == 'NumCores': numCores = tmp[i]
        elif att_list[i] == 'CoresPerCPU': coresPerCPU = tmp[i]
        elif att_list[i] == 'TxRate': txRate = tmp[i]
        elif att_list[i] == 'RxRate': rxRate = tmp[i]
        elif att_list[i] == 'BootState': bootState = tmp[i]
        elif att_list[i] == 'NodeType': nodeType = tmp[i]
        elif att_list[i] == 'BWLimit': bwLimit = tmp[i]
        elif att_list[i] == 'Latitude': lati = tmp[i]
        elif att_list[i] == 'Longitude': longi = tmp[i]
        elif att_list[i] == 'Location': location = tmp[i]
        elif att_list[i] == 'Drift': drift = tmp[i]

    if IP not in skip_node_list:
        #if valid response node is considered to be active
        if IP not in node_IP_list and float(time) == START_TIME: #New node. Add it`
            node_IP_list.append(IP)
            node_ID_list.append(next_nid)
            last_time[next_nid] = float(time)
            next_nid = next_nid + 1
        elif IP not in node_IP_list: #New but not at start time
            skip_node_list.append(IP) #Add to skip list
            continue
        index = node_IP_list.index(IP) #Find index
        if float(time) - last_time[node_ID_list[index]] < 2 * SAMPLING_INTERVAL: #No missing entry in the middle
            attribs = [str(node_ID_list[index]), str(float(time) - START_TIME)]
            for j in range(0, len(attbs_to_extract)):
                #extract requred attributes
                if attbs_to_extract[j] == 'RespTime': attribs.append(respTime)
                elif attbs_to_extract[j] == 'SwapIn': attribs.append(swapIn)
                elif attbs_to_extract[j] == 'SwapOut': attribs.append(swapOut)
                elif attbs_to_extract[j] == 'DiskIn': attribs.append(diskIn)
                elif attbs_to_extract[j] == 'DiskOut': attribs.append(diskOut)
                elif attbs_to_extract[j] == 'DiskSvc': attribs.append(diskSvc)
                elif attbs_to_extract[j] == 'DiskUtil': attribs.append(diskUtil)
                elif attbs_to_extract[j] == 'Uptime': attribs.append(upTime)
                elif attbs_to_extract[j] == '1MinLoad': attribs.append(oneMinLoad)
                elif attbs_to_extract[j] == '5MinLoad': attribs.append(fiveMinLoad)
                elif attbs_to_extract[j] == '15MinLoad': attribs.append(fifteenMinLoad)
                elif attbs_to_extract[j] == 'TimerMax': attribs.append(timerMax)
                elif attbs_to_extract[j] == 'TimerAve': attribs.append(timerAve)
                elif attbs_to_extract[j] == 'MemFree': attribs.append(memPress)
                elif attbs_to_extract[j] == 'DiskUsed': attribs.append(diskUsed)
                elif attbs_to_extract[j] == 'DiskFree': attribs.append(diskFree)
                elif attbs_to_extract[j] == 'DiskSize': attribs.append(diskSize)
                elif attbs_to_extract[j] == 'MemSize': attribs.append(memSize)
                elif attbs_to_extract[j] == 'MemActive': attribs.append(memActive)
                elif attbs_to_extract[j] == 'SwapUsed': attribs.append(swapUsed)
                elif attbs_to_extract[j] == 'KernVer': attribs.append(kernVer)
                elif attbs_to_extract[j] == 'CPUFree': attribs.append(cpuFree)
                elif attbs_to_extract[j] == 'CPUSpeed': attribs.append(cpuSpeed)
                elif attbs_to_extract[j] == 'NumCores': attribs.append(numCores)
                elif attbs_to_extract[j] == 'CoresPerCPU': attribs.append(coresPerCPU)
                elif attbs_to_extract[j] == 'FCNamex': attribs.append(fcNamex)
                elif attbs_to_extract[j] == 'TxRate': attribs.append(txRate)
                elif attbs_to_extract[j] == 'RxRate': attribs.append(rxRate)
                elif attbs_to_extract[j] == 'Boot': attribs.append(bootState)
                elif attbs_to_extract[j] == 'NodeType': attribs.append(nodeType)
                elif attbs_to_extract[j] == 'BWLimit': attribs.append(bwLimit)
                elif attbs_to_extract[j] == 'Latitude': attribs.append(lati)
                elif attbs_to_extract[j] == 'Longitude': attribs.append(longi)
                elif attbs_to_extract[j] == 'Location': attribs.append(location)
                elif attbs_to_extract[j] == 'Drift': attribs.append(drift)
            resources.append(attribs) 
            last_time[node_ID_list[index]] = float(time)
        else: #At least 1 missing data
            skip_node_list.append(IP) #Add to skip list
            if IP in node_IP_list : 
                index = node_IP_list.index(IP) #Remove from node list
                node_IP_list.remove(IP)
                node_ID_list.remove(node_ID_list[index])
        #Reset variables
    time = IP = respTime = swapIn = swapOut = diskIn = diskOut = diskSvc = diskUtil = upTime = oneMinLoad = \
    fiveMinLoad = fifteenmLoad = timerMax = timerAve = memPress = diskUsed = diskFree = diskSize = memSize = \
    memActive = swapUsed = kernVer = cpuFree = cpuSpeed = fcNamex = numCores = coresPerCPU = txRtae = rxRate \
    = bootState = nodeType = bwLimit = lati = longi = location = drift = '-1'
    end = 0
    if (count % 10000) == 1: print count #Indicate progress
    count = count + 1
fdIn.close()

print 'No of resources: %d' % len(node_ID_list)
print 'No of resources: %d' % len(node_IP_list)
print len(resources)
fdOut = open(fOut, 'w')
#write list of attributes in 1st line
tmp_str = 'nid\ttime'
for i in range(0, len(attbs_to_extract)): tmp_str = tmp_str + '\t' + attbs_to_extract[i] 
fdOut.write(tmp_str + '\n')

#Dump attributes of nodes that were active
for j in range(0, len(resources)):
    tmp_str = ''
    if int(resources[j][0]) in node_ID_list: #valid node
        for k in range(0, len(resources[j])): #each attribute
            #Pack nids before dumping to file. determoned by index
            if k == 0: tmp_str = str(node_ID_list.index(int(resources[j][k])))
            else: tmp_str = tmp_str + '\t' + resources[j][k]
        fdOut.write(tmp_str + '\n')

fdOut.close()
