'''
Created on Jan 22, 2011
Modified on July 10, 2012
@author: Dilum Bandara
@version: 0.13
@license: Apache License v2.0

   Copyright 2012 H. M. N. Dilum Bandara and Anura P. Jayasumana, Colorado State
   University

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
'''

import BaseConfig
import copy

class BaseHash(object):
    '''
    Base Hash class. Locality preserving hash functions
    '''
    def __init__(self, maxKey):
        '''
        Constructor
        @param maxKey: Maximum key 
        '''
        self.maxKey = maxKey


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