'''
Created on Aug 31, 2012
@version: 0.1
@author: Dilum Bandara
@email: dilumb@engr.colostate.edu
@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 math
import Config as Config
import PeerManager as PM

class NIC(object):
    '''
    Network Interface Card Class. Simulate the underlay
    Add & take events from discrete event engine
    '''


    def __init__(self, NID, loc, appType):
        '''
        Constructor
        @param NID: Node ID
        @param loc: Location of node
        @param allType: Application layer type of node (useful in stats) 
        '''
        self.NID = NID
        self.loc = loc
        self.type = appType #Useful in stat collection
        self._nextPacketTime = 0.0 #Time next message can be issued
        self.dataRec = 0
        self.dataFwd = 0


    def fwdMsg(self, msg, destNID):
        '''
        Forward message directly to given node.
        @param msg: Message 
        @param destNID: Node ID of destination node
        @return : success or failure  
        '''
        if destNID in PM.UNDERLAY:            
            PM.UNDERLAY[destNID].recMsg(msg, self.NID, self.loc)
            self.dataFwd += msg.size 
            return True
        else: return False


    def recMsg(self, msg, sourceNID, sourceLoc):
        '''
        Forward message directly to given node. 
        Consider packet service & arrival time
        @param msg: Message 
        @param sourceNID: Node ID of destination node
        @param sourceLoc: Location of destination node
        '''
        self.dataRec += msg.size
        latency = self._propDelay(self.loc, sourceLoc) #propagation delay
        #Delay due to limited bandwidth. Convert to bits
        latency += msg.size/Config.BANDWIDTH
        fwdTime = -1.0
        currentTime = PM.EVENTS.now
        if currentTime > self._nextPacketTime: fwdTime = currentTime + latency
        else: fwdTime = self._nextPacketTime + latency
        self._nextPacketTime = fwdTime #Reset when next message can be received
        PM.EVENTS.addEvent(fwdTime, 'UN2OV', self.NID, [msg, sourceNID], True)


    def _propDelay(self, source, dest):
        '''
        Calculate propagation delay based on geographic distance in (x, y) plane.
        @param source: Source location
        @param dest: Destination location
        @return: latency   
        '''
        dX = source[0] - dest[0]
        dY = source[1] - dest[1]
        d = math.sqrt(dX * dX + dY * dY)
        return d/Config.SPEED_LIGHT


    def getStat(self):
        '''
        Get statistics
        @return: results
        '''
        return [self.dataRec, self.dataFwd]