'''
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 random
import Config as Config
import PeerManager as PM
from CCNInterest import CCNInterest


class User(object):
    '''
    End user class
    '''
    
    def __init__(self, UID, loc, uType, AOI, inOverlay = False):
        '''
        Constructor
        @param UID: User ID
        @param loc: Location
        @param uType: Type of user (NWS (National Weather Service), EM 
        (Emergency Manager), RES (Researcher), MED (Media), etc
        @param AOI: User's AOI
        @param inOverlay: Is node part of overlay        
        '''
        self.UID = UID
        self.loc = loc
        self.type = uType
        self.AOT = AOI
        self.inOverlay = inOverlay
        self._idx = {}      #Index of sensor readings. In case added to overlay        
        self._numQueSend = 0
        self._numQueAns = 0
        self._pendInter = {} #Pending interest messages
        self._results = []

        
    def __del__(self):
        '''
        Destructor
        '''
        self._results = None


    def genInterest(self, query, cTime):
        '''
        Query for sensor data
        @param query: Query 
        @param cTime: Current time
        @param delta: Time interval that past content is considered valid 
        '''
        vTime = cTime - query[2] #Data generate after this time is acceptable
        if vTime < 0.0 : vTime = 0.0

        minQueArea = PM.HASH.que2Area(query[3:]) #Minimum area to query
        orderdQueAreas = PM.HASH.area2SFC(minQueArea, 'ascending')
        names = self._genName(orderdQueAreas, vTime, query[3:])
        self._pendInter[names[1]] = cTime   #Track query interest messages
        remainingAreas = orderdQueAreas[1:]
        newMsg = CCNInterest(names[0], names[1], orderdQueAreas[0][1], \
                    orderdQueAreas[0][2], vTime, 'QUE', self.UID, \
                    [query[3:], remainingAreas])
        reply = PM.OVERLAY[self.UID].fwdInter(newMsg)
        if reply != None: #Data on local node
            print 'Data on local node' #TODO
        else: self._numQueSend += 1


    def _genName(self, areas, vTime, query):
        '''
        Generate name based on given parameters
        @param sortedArea: Areas to query as a list of [[SFC index, 
        [(lower left) x, y, z, ...], [(upper right) x, y, z]], [...] ]
        @param vTime: Sensor readings is valid until this time
        @param query: [partial query, actual query]. Partial query useful in 
        handling cache entries
        '''
        tmpStr = ''
        for i in areas[0][1]: tmpStr += '/' + str(round(i, 3)) #Lower left
        for i in areas[0][2]: tmpStr += '/' + str(round(i, 3)) #Upper right
        tmpStr += '/QUE/'
        tmpStr2 = tmpStr + str(vTime)
        for i in query:
            tmpStr2 += '/' + i[0] + '/' + str(i[1]) + '/' + str(i[2])
        if Config.APPEND_TO_VISIT == True: #Append names of areas to visit
            for i in range(1, len(areas)): #Skip 1st one which is already used
                for j in areas[i][1]: tmpStr2 += '/' + str(j) #Lower left
                for j in areas[i][2]: tmpStr2 += '/' + str(j) #Upper right
        else: #Add a nonce to make message unique
            nonce = random.randint(0, 100000000)
            tmpStr2 += str(nonce)
        tmpStr2 += '/'
        return [tmpStr, tmpStr2]


    def recMsg(self, msg):
        '''
        Receive message from overlay/CCN
        @param msg: Message
        '''
        assert(msg.msgType == 'CCND'), 'Wrong message type ' + msg.msgType
        if msg.realName not in self._pendInter:
            print 'User:recMsg No pending interest', msg.name
            return
        #Track ['Que', current time, time to get response, no of results, hops]
        self._results.append(['Que', self._pendInter[msg.realName], \
                PM.EVENTS.now - self._pendInter[msg.realName], len(msg.data), \
                msg.hops])
        del self._pendInter[msg.realName]
        self._numQueAns += 1


    def dumpResults(self):
        '''
        Dump current results & reset collector
        @return: Results
        '''
        tmp = self._results
        self._results = []
        return tmp


    def getStat(self):
        '''
        Get statistics 
        '''
        return [len(self._pendInter), len(self._idx), self._numQueSend, \
                    self._numQueAns]
