'''
Created on Jan 22, 2011
Modified on Apr 24, 2011
@author: Dilum Bandara
@version: 0.12
@copyright: Copyright(c) 2011, Dilum Bandara
@license: GPL

Corrected PULP_hash
'''

import math
import BaseConfig
import sys
import copy

class BaseHash(object):
    '''
    Base Hash class. 
    '''
    def __init__(self):
        self.max_key = long(math.pow(2, BaseConfig.KEY_LENGTH) - 1)
        self.p_max_key = long(math.pow(2, BaseConfig.KEY_LENGTH - \
                                       BaseConfig.ATT_KEY_LENGTH) - 1)


    def ULP_hash(self, att):
        '''
        Uniform Locality Preserving hash for given attribute (extracted from LORM paper)        
        @param att: Attribute to hash
        @return: Hash value
        '''
        attrib = copy.deepcopy(att)
        if attrib[0] == 'RspT':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_RESP_TIME
            return long(((attrib[1] - BaseConfig.MIN_RESP_TIME)/float(BaseConfig.MAX_RESP_TIME - BaseConfig.MIN_RESP_TIME)) * self.max_key)
        elif attrib[0] == 'SIn':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_SWAP_IN
            return long(((attrib[1] - BaseConfig.MIN_SWAP_IN)/float(BaseConfig.MAX_SWAP_IN - BaseConfig.MIN_SWAP_IN)) * self.max_key)
        elif attrib[0] == 'SOut':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_SWAP_OUT
            return long(((attrib[1] - BaseConfig.MIN_SWAP_OUT)/float(BaseConfig.MAX_SWAP_OUT - BaseConfig.MIN_SWAP_OUT)) * self.max_key)
        elif attrib[0] == 'DIn':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_DISK_IN
            return long(((attrib[1] - BaseConfig.MIN_DISK_IN)/float(BaseConfig.MAX_DISK_IN - BaseConfig.MIN_DISK_IN)) * self.max_key)
        elif attrib[0] == 'DOut':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_DISK_OUT
            return long(((attrib[1] - BaseConfig.MIN_DISK_OUT)/float(BaseConfig.MAX_DISK_OUT - BaseConfig.MIN_DISK_OUT)) * self.max_key)
        elif attrib[0] == 'DSvc':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_DISK_SVC
            return long(((attrib[1] - BaseConfig.MIN_DISK_SVC)/float(BaseConfig.MAX_DISK_SVC - BaseConfig.MIN_DISK_SVC)) * self.max_key)
        elif attrib[0] == 'DUtil':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_DISK_UTIL
            return long(((attrib[1] - BaseConfig.MIN_DISK_UTIL)/float(BaseConfig.MAX_DISK_UTIL - BaseConfig.MIN_DISK_UTIL)) * self.max_key)
        elif attrib[0] == 'UpT':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_UPTIME
            return long(((attrib[1] - BaseConfig.MIN_UPTIME)/float(BaseConfig.MAX_UPTIME - BaseConfig.MIN_UPTIME)) * self.max_key)
        elif attrib[0] == '1mLd':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_1_MIN_LOAD
            return long(((attrib[1] - BaseConfig.MIN_1_MIN_LOAD)/float(BaseConfig.MAX_1_MIN_LOAD - BaseConfig.MIN_1_MIN_LOAD)) * self.max_key)
        elif attrib[0] == '5mLd':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_5_MIN_LOAD
            return long(((attrib[1] - BaseConfig.MIN_5_MIN_LOAD)/float(BaseConfig.MAX_5_MIN_LOAD - BaseConfig.MIN_5_MIN_LOAD)) * self.max_key)
        elif attrib[0] == '15mLd':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_15_MIN_LOAD
            return long(((attrib[1] - BaseConfig.MIN_15_MIN_LOAD)/float(BaseConfig.MAX_15_MIN_LOAD - BaseConfig.MIN_15_MIN_LOAD)) * self.max_key)
        elif attrib[0] == 'TMax':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_TIMER_MAX
            return long(((attrib[1] - BaseConfig.MIN_TIMER_MAX)/float(BaseConfig.MAX_TIMER_MAX - BaseConfig.MIN_TIMER_MAX)) * self.max_key)
        elif attrib[0] == 'TAve':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_TIMER_AVE
            return long(((attrib[1] - BaseConfig.MIN_TIMER_AVE)/float(BaseConfig.MAX_TIMER_AVE - BaseConfig.MIN_TIMER_AVE)) * self.max_key)
        elif attrib[0] == 'MFree':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_MEM_FREE
            return long(((attrib[1] - BaseConfig.MIN_MEM_FREE)/float(BaseConfig.MAX_MEM_FREE - BaseConfig.MIN_MEM_FREE)) * self.max_key)
        elif attrib[0] == 'DUsed':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_DISK_USED
            return long(((attrib[1] - BaseConfig.MIN_DISK_USED)/float(BaseConfig.MAX_DISK_USED - BaseConfig.MIN_DISK_USED)) * self.max_key)
        elif attrib[0] == 'DFree':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_DISK_FREE
            return long(((attrib[1] - BaseConfig.MIN_DISK_FREE)/float(BaseConfig.MAX_DISK_FREE - BaseConfig.MIN_DISK_FREE)) * self.max_key)
        elif attrib[0] == 'DSize':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_DISK_SIZE
            return long(((attrib[1] - BaseConfig.MIN_DISK_SIZE)/float(BaseConfig.MAX_DISK_SIZE - BaseConfig.MIN_DISK_SIZE)) * self.max_key)
        elif attrib[0] == 'MAct':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_MEM_ACTIVE
            return long(((attrib[1] - BaseConfig.MIN_MEM_ACTIVE)/float(BaseConfig.MAX_MEM_ACTIVE - BaseConfig.MIN_MEM_ACTIVE)) * self.max_key)
        elif attrib[0] == 'MSize':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_MEM_SIZE
            return long(((attrib[1] - BaseConfig.MIN_MEM_SIZE)/float(BaseConfig.MAX_MEM_SIZE - BaseConfig.MIN_MEM_SIZE)) * self.max_key)
        elif attrib[0] == 'SUsed':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_SWAP_USED
            return long(((attrib[1] - BaseConfig.MIN_SWAP_USED)/float(BaseConfig.MAX_SWAP_USED - BaseConfig.MIN_SWAP_USED)) * self.max_key)
        elif attrib[0] == 'KVer':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_KERN_VER
            return long(((attrib[1] - BaseConfig.MIN_KERN_VER)/float(BaseConfig.MAX_KERN_VER - BaseConfig.MIN_KERN_VER)) * self.max_key)
#            return long(((kernVer - BaseConfig.MIN_KERN_VER)/float(BaseConfig.MAX_KERN_VER - BaseConfig.MIN_KERN_VER)) * self.max_key)
        elif attrib[0] == 'CFree':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_CPU_FREE
            return long(((attrib[1] - BaseConfig.MIN_CPU_FREE)/float(BaseConfig.MAX_CPU_FREE - BaseConfig.MIN_CPU_FREE)) * self.max_key)
        elif attrib[0] == 'CSp':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_CPU_SPEED
            return long(((attrib[1] - BaseConfig.MIN_CPU_SPEED)/float(BaseConfig.MAX_CPU_SPEED - BaseConfig.MIN_CPU_SPEED)) * self.max_key)
        elif attrib[0] == 'NCore':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_NUM_CORES
            return long(((attrib[1] - BaseConfig.MIN_NUM_CORES)/float(BaseConfig.MAX_NUM_CORES - BaseConfig.MIN_NUM_CORES)) * self.max_key)
        elif attrib[0] == 'CorePC':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_CORES_PER_CPU
            return long(((attrib[1] - BaseConfig.MIN_CORES_PER_CPU)/float(BaseConfig.MAX_CORES_PER_CPU - BaseConfig.MIN_CORES_PER_CPU)) * self.max_key)
        elif attrib[0] == 'FCName':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_FC_NAMEX
            return long(((attrib[1] - BaseConfig.MIN_FC_NAMEX)/float(BaseConfig.MAX_FC_NAMEX - BaseConfig.MIN_FC_NAMEX)) * self.max_key)
        elif attrib[0] == 'Tx':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_TX_RATE
            return long(((attrib[1] - BaseConfig.MIN_TX_RATE)/float(BaseConfig.MAX_TX_RATE - BaseConfig.MIN_TX_RATE)) * self.max_key)
        elif attrib[0] == 'Rx':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_RX_RATE
            return long(((attrib[1] - BaseConfig.MIN_RX_RATE)/float(BaseConfig.MAX_RX_RATE - BaseConfig.MIN_RX_RATE)) * self.max_key)
        elif attrib[0] == 'Boot':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_BOOT
            return long(((attrib[1] - BaseConfig.MIN_BOOT)/float(BaseConfig.MAX_BOOT - BaseConfig.MIN_BOOT)) * self.max_key)
        elif attrib[0] == 'NType':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_NODE_TYPE
            return long(((attrib[1] - BaseConfig.MIN_NODE_TYPE)/float(BaseConfig.MAX_NODE_TYPE - BaseConfig.MIN_NODE_TYPE)) * self.max_key)
        elif attrib[0] == 'BWLim':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_BW_LIMIT
            return long(((attrib[1] - BaseConfig.MIN_BW_LIMIT)/float(BaseConfig.MAX_BW_LIMIT - BaseConfig.MIN_BW_LIMIT)) * self.max_key)
        elif attrib[0] == 'Lati':
            if attrib[1] < BaseConfig.MIN_LATITUDE : attrib[1] = BaseConfig.MIN_LATITUDE
            return long(((attrib[1] - BaseConfig.MIN_LATITUDE)/float(BaseConfig.MAX_LATITUDE - BaseConfig.MIN_LATITUDE)) * self.max_key)
        elif attrib[0] == 'Longi':
            if attrib[1] < BaseConfig.MIN_LONGITUDE : attrib[1] = BaseConfig.MIN_LONGITUDE
            return long(((attrib[1] - BaseConfig.MIN_LONGITUDE)/float(BaseConfig.MAX_LONGITUDE - BaseConfig.MIN_LONGITUDE)) * self.max_key)
        elif attrib[0] == 'Loc':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_LOCATION
            return long(((attrib[1] - BaseConfig.MIN_LOCATION)/float(BaseConfig.MAX_LOCATION - BaseConfig.MIN_LOCATION)) * self.max_key)
        elif attrib[0] == 'Drift':
            if attrib[1] < BaseConfig.MIN_DRIFT : attrib[1] = BaseConfig.MIN_DRIFT
            return long(((attrib[1] - BaseConfig.MIN_DRIFT)/float(BaseConfig.MAX_DRIFT - BaseConfig.MIN_DRIFT)) * self.max_key)
        else:
            print 'Unknown attribute %s' % attrib[0]
            sys.exit(0)


    def PULP_hash(self, att, att_list):
        '''
        Partitioned Uniform Locality Preserving hash for given attribute (extracted from 
        LORM paper). First assign partition number based on attribute        
        @param att: Attribute
        @param att_list: List of valid attributes 
        @return: Hash value
        '''
        attrib = copy.deepcopy(att)
        if attrib[0] == 'RspT':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_RESP_TIME
            suffix = long(((attrib[1] - BaseConfig.MIN_RESP_TIME)/float(BaseConfig.MAX_RESP_TIME - BaseConfig.MIN_RESP_TIME)) * self.p_max_key)
            return (att_list.index('RspT') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'SIn':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_SWAP_IN
            suffix = long(((attrib[1] - BaseConfig.MIN_SWAP_IN)/float(BaseConfig.MAX_SWAP_IN - BaseConfig.MIN_SWAP_IN)) * self.p_max_key)
            return (att_list.index('SIn') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'SOut':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_SWAP_OUT
            suffix=  long(((attrib[1] - BaseConfig.MIN_SWAP_OUT)/float(BaseConfig.MAX_SWAP_OUT - BaseConfig.MIN_SWAP_OUT)) * self.p_max_key)
            return (att_list.index('SOut') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'DIn':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_DISK_IN
            suffix = long(((attrib[1] - BaseConfig.MIN_DISK_IN)/float(BaseConfig.MAX_DISK_IN - BaseConfig.MIN_DISK_IN)) * self.p_max_key)
            return (att_list.index('DIn') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'DOut':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_DISK_OUT
            suffix = long(((attrib[1] - BaseConfig.MIN_DISK_OUT)/float(BaseConfig.MAX_DISK_OUT - BaseConfig.MIN_DISK_OUT)) * self.p_max_key)
            return (att_list.index('DOut') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'DSvc':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_DISK_SVC
            suffix = long(((attrib[1] - BaseConfig.MIN_DISK_SVC)/float(BaseConfig.MAX_DISK_SVC - BaseConfig.MIN_DISK_SVC)) * self.p_max_key)
            return (att_list.index('DSvc') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'DUtil':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_DISK_UTIL
            suffix = long(((attrib[1] - BaseConfig.MIN_DISK_UTIL)/float(BaseConfig.MAX_DISK_UTIL - BaseConfig.MIN_DISK_UTIL)) * self.p_max_key)
            return (att_list.index('DUtil') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'UpT':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_UPTIME
            suffix = long(((attrib[1] - BaseConfig.MIN_UPTIME)/float(BaseConfig.MAX_UPTIME - BaseConfig.MIN_UPTIME)) * self.p_max_key)
            return (att_list.index('UpT') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == '1mLd':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_1_MIN_LOAD
            suffix = long(((attrib[1] - BaseConfig.MIN_1_MIN_LOAD)/float(BaseConfig.MAX_1_MIN_LOAD - BaseConfig.MIN_1_MIN_LOAD)) * self.p_max_key)
            return (att_list.index('1mLd') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == '5mLd':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_5_MIN_LOAD
            suffix = long(((attrib[1] - BaseConfig.MIN_5_MIN_LOAD)/float(BaseConfig.MAX_5_MIN_LOAD - BaseConfig.MIN_5_MIN_LOAD)) * self.p_max_key)
            return (att_list.index('5mLd') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == '15mLd':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_15_MIN_LOAD
            suffix = long(((attrib[1] - BaseConfig.MIN_15_MIN_LOAD)/float(BaseConfig.MAX_15_MIN_LOAD - BaseConfig.MIN_15_MIN_LOAD)) * self.p_max_key)
            return (att_list.index('15mLd') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'TMax':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_TIMER_MAX
            suffix = long(((attrib[1] - BaseConfig.MIN_TIMER_MAX)/float(BaseConfig.MAX_TIMER_MAX - BaseConfig.MIN_TIMER_MAX)) * self.p_max_key)
            return (att_list.index('TMax') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'TAve':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_TIMER_AVE
            suffix = long(((attrib[1] - BaseConfig.MIN_TIMER_AVE)/float(BaseConfig.MAX_TIMER_AVE - BaseConfig.MIN_TIMER_AVE)) * self.p_max_key)
            return (att_list.index('TAve') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'MFree':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_MEM_FREE
            suffix = long(((attrib[1] - BaseConfig.MIN_MEM_FREE)/float(BaseConfig.MAX_MEM_FREE - BaseConfig.MIN_MEM_FREE)) * self.p_max_key)
            return (att_list.index('MFree') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'DUsed':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_DISK_USED
            suffix = long(((attrib[1] - BaseConfig.MIN_DISK_USED)/float(BaseConfig.MAX_DISK_USED - BaseConfig.MIN_DISK_USED)) * self.p_max_key)
            return (att_list.index('DUsed') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'DFree':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_DISK_FREE
            suffix = long(((attrib[1] - BaseConfig.MIN_DISK_FREE)/float(BaseConfig.MAX_DISK_FREE - BaseConfig.MIN_DISK_FREE)) * self.p_max_key)
            return (att_list.index('DFree') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'DSize':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_DISK_SIZE
            suffix = long(((attrib[1] - BaseConfig.MIN_DISK_SIZE)/float(BaseConfig.MAX_DISK_SIZE - BaseConfig.MIN_DISK_SIZE)) * self.p_max_key)
            return (att_list.index('DSize') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'MAct':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_MEM_ACTIVE
            suffix = long(((attrib[1] - BaseConfig.MIN_MEM_ACTIVE)/float(BaseConfig.MAX_MEM_ACTIVE - BaseConfig.MIN_MEM_ACTIVE)) * self.p_max_key)
            return (att_list.index('MAct') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'MSize':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_MEM_SIZE
            suffix = long(((attrib[1] - BaseConfig.MIN_MEM_SIZE)/float(BaseConfig.MAX_MEM_SIZE - BaseConfig.MIN_MEM_SIZE)) * self.p_max_key)
            return (att_list.index('MSize') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'SUsed':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_SWAP_USED
            suffix = long(((attrib[1] - BaseConfig.MIN_SWAP_USED)/float(BaseConfig.MAX_SWAP_USED - BaseConfig.MIN_SWAP_USED)) * self.p_max_key)
            return (att_list.index('SUsed') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'KVer':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_KERN_VER
            suffix = long(((attrib[1] - BaseConfig.MIN_KERN_VER)/float(BaseConfig.MAX_KERN_VER - BaseConfig.MIN_KERN_VER)) * self.p_max_key)
            return (att_list.index('KVer') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'CFree':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_CPU_FREE
            suffix = long(((attrib[1] - BaseConfig.MIN_CPU_FREE)/float(BaseConfig.MAX_CPU_FREE - BaseConfig.MIN_CPU_FREE)) * self.p_max_key)
            return (att_list.index('CFree') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'CSp':
            if attrib[1] < 0.0 : attrib[1] = BaseConfig.MIN_CPU_SPEED
            suffix = long(((attrib[1] - BaseConfig.MIN_CPU_SPEED)/float(BaseConfig.MAX_CPU_SPEED - BaseConfig.MIN_CPU_SPEED)) * self.p_max_key)
            return (att_list.index('CSp') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'NCore':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_NUM_CORES
            suffix = long(((attrib[1] - BaseConfig.MIN_NUM_CORES)/float(BaseConfig.MAX_NUM_CORES - BaseConfig.MIN_NUM_CORES)) * self.p_max_key)
            return (att_list.index('NCore') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'CorePC':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_CORES_PER_CPU
            suffix = long(((attrib[1] - BaseConfig.MIN_CORES_PER_CPU)/float(BaseConfig.MAX_CORES_PER_CPU - BaseConfig.MIN_CORES_PER_CPU)) * self.p_max_key)
            return (att_list.index('CorePC') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'FCName':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_FC_NAMEX
            suffix = long(((attrib[1] - BaseConfig.MIN_FC_NAMEX)/float(BaseConfig.MAX_FC_NAMEX - BaseConfig.MIN_FC_NAMEX)) * self.p_max_key)
            return (att_list.index('FCName') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'Tx':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_TX_RATE
            suffix = long(((attrib[1] - BaseConfig.MIN_TX_RATE)/float(BaseConfig.MAX_TX_RATE - BaseConfig.MIN_TX_RATE)) * self.p_max_key)
            return (att_list.index('Tx') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'Rx':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_RX_RATE
            suffix = long(((attrib[1] - BaseConfig.MIN_RX_RATE)/float(BaseConfig.MAX_RX_RATE - BaseConfig.MIN_RX_RATE)) * self.p_max_key)
            return (att_list.index('Rx') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'Boot':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_BOOT
            suffix = long(((attrib[1] - BaseConfig.MIN_BOOT)/float(BaseConfig.MAX_BOOT - BaseConfig.MIN_BOOT)) * self.p_max_key)
            return (att_list.index('Boot') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'NType':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_NODE_TYPE
            suffix = long(((attrib[1] - BaseConfig.MIN_NODE_TYPE)/float(BaseConfig.MAX_NODE_TYPE - BaseConfig.MIN_NODE_TYPE)) * self.p_max_key)
            return (att_list.index('NType') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'BWLim':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_BW_LIMIT
            suffix = long(((attrib[1] - BaseConfig.MIN_BW_LIMIT)/float(BaseConfig.MAX_BW_LIMIT - BaseConfig.MIN_BW_LIMIT)) * self.p_max_key)
            return (att_list.index('BWLim') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'Lati':
            if attrib[1] < BaseConfig.MIN_LATITUDE : attrib[1] = BaseConfig.MIN_LATITUDE
            suffix = long(((attrib[1] - BaseConfig.MIN_LATITUDE)/float(BaseConfig.MAX_LATITUDE - BaseConfig.MIN_LATITUDE)) * self.p_max_key)
            return (att_list.index('Lati') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'Longi':
            if attrib[1] < BaseConfig.MIN_LONGITUDE : attrib[1] = BaseConfig.MIN_LONGITUDE
            suffix = long(((attrib[1] - BaseConfig.MIN_LONGITUDE)/float(BaseConfig.MAX_LONGITUDE - BaseConfig.MIN_LONGITUDE)) * self.p_max_key)
            return (att_list.index('Longi') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'Loc':
            if attrib[1] < 0 : attrib[1] = BaseConfig.MIN_LOCATION
            suffix = long(((attrib[1] - BaseConfig.MIN_LOCATION)/float(BaseConfig.MAX_LOCATION - BaseConfig.MIN_LOCATION)) * self.p_max_key)
            return (att_list.index('Loc') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        elif attrib[0] == 'Drift':
            if attrib[1] < BaseConfig.MIN_DRIFT : attrib[1] = BaseConfig.MIN_DRIFT
            suffix = long(((attrib[1] - BaseConfig.MIN_DRIFT)/float(BaseConfig.MAX_DRIFT - BaseConfig.MIN_DRIFT)) * self.p_max_key)
            return (att_list.index('Drift') << (BaseConfig.KEY_LENGTH - BaseConfig.ATT_KEY_LENGTH)) + suffix
        else:
            print 'PULP hashing - Unknown attribute %s' % attrib[0]
            sys.exit(0)


    def cell_id(self, attrib, num_cells):
        '''
        Find node location on d-Torus based on static attributes
        @param attrib: Attribute
        @param num_cells: Number of cells
        @return: Cell ID
        '''    
        tmp_id = []
        for i in range(0, len(attrib)):
            if attrib[i][0] == 'Loc':
                tmp_val = ((int(attrib[i][1]) - BaseConfig.MIN_LOCATION) / float(BaseConfig.MAX_LOCATION - 
                            BaseConfig.MIN_LOCATION)) * num_cells
                for j in range(1, num_cells + 1):
                    if tmp_val <= j: 
                        tmp_id.append(j)
                        break
            elif attrib[i][0] == 'Lati':
                if attrib[i][1] == 'None': latitude = BaseConfig.MIN_LATITUDE
                else: latitude = float(attrib[i][1])
                tmp_val = ((latitude - BaseConfig.MIN_LATITUDE) / float(BaseConfig.MAX_LATITUDE - \
                            BaseConfig.MIN_LATITUDE)) * num_cells
                for j in range(1, num_cells + 1):
                    if tmp_val <= j: 
                        tmp_id.append(j)
                        break
            elif attrib[i][0] == 'Longi':
                if attrib[i][1] == 'None': longitude = BaseConfig.MIN_LATITUDE
                else: longitude = float(attrib[i][1])
                tmp_val = ((longitude - BaseConfig.MIN_LONGITUDE) / float(BaseConfig.MAX_LONGITUDE - \
                            BaseConfig.MIN_LONGITUDE)) * num_cells
                for j in range(1, num_cells + 1):
                    if tmp_val <= j:
                        tmp_id.append(j)
                        break
            elif attrib[i][0] == 'NType':
                tmp_val = ((int(attrib[i][1]) - BaseConfig.MIN_NODE_TYPE) / float(BaseConfig.MAX_NODE_TYPE - \
                            BaseConfig.MIN_NODE_TYPE)) * num_cells
                for j in range(1, num_cells + 1):
                    if tmp_val <= j:
                        tmp_id.append(j)
                        break
            elif attrib[i][0] == 'KVer':
                tmp_val = ((int(attrib[i][1]) - BaseConfig.MIN_KERN_VER) / float(BaseConfig.MAX_KERN_VER - \
                            BaseConfig.MIN_KERN_VER)) * num_cells
                for j in range(1, num_cells + 1):
                    if tmp_val <= j:
                        tmp_id.append(j)
                        break
            elif attrib[i][0] == 'FCName':
                tmp_val = ((int(attrib[i][1]) - BaseConfig.MIN_FC_NAMEX) / float(BaseConfig.MAX_FC_NAMEX - \
                            BaseConfig.MIN_FC_NAMEX)) * num_cells
                for j in range(1, num_cells + 1):
                    if tmp_val <= j:
                        tmp_id.append(j)
                        break
            elif attrib[i][0] == 'CSp':
                tmp_val = ((float(attrib[i][1]) - BaseConfig.MIN_CPU_SPEED) / float(BaseConfig.MAX_CPU_SPEED - \
                            BaseConfig.MIN_CPU_SPEED)) * num_cells
                for j in range(1, num_cells + 1):
                    if tmp_val <= j:
                        tmp_id.append(j)
                        break
            elif attrib[i][0] == 'NCore':
                for j in range(1, num_cells + 1):
                    if float(attrib[i][1]) <= (BaseConfig.MAX_NUM_CORES/float(math.pow(2, num_cells - j))) :
                        tmp_id.append(j)
                        break
            elif attrib[i][0] == 'CorePC':
                tmp_val = ((int(attrib[i][1]) - BaseConfig.MIN_CORES_PER_CPU) / float(BaseConfig.MAX_CORES_PER_CPU - \
                            BaseConfig.MIN_CORES_PER_CPU)) * num_cells
                for j in range(1, num_cells + 1):
                    if tmp_val <= j:
                        tmp_id.append(j)
                        break
            elif attrib[i][0] == 'MSize':
                for j in range(1, num_cells + 1):
                    if float(attrib[i][1]) <= (BaseConfig.MAX_MEM_SIZE/float(math.pow(2, num_cells - j))) :
                        tmp_id.append(j)
                        break
            elif attrib[i][0] == 'DSize':
                for j in range(1, num_cells + 1):
                    if float(attrib[i][1]) <= (BaseConfig.MAX_DISK_SIZE/float(math.pow(2, num_cells - j))) :
                        tmp_id.append(j)
                        break
            elif attrib[i][0] == 'BWLim':
                if attrib[i][1] == 'none': bwLimit = BaseConfig.MAX_BW_LIMIT
                else: bwLimit = int(attrib[i][1])
                for j in range(1, num_cells + 1):
                    if bwLimit <= (BaseConfig.MAX_BW_LIMIT/float(math.pow(2, num_cells - j))) :
                        tmp_id.append(j)
                        break
        return tmp_id 
