'''
Created on Mar 6, 2012
Modified on May 18, 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.
'''

from USubscription import USubscription

class UserSubscriptions(object):
    '''
    Table that tracks interest messages send by users at proxy.
    '''

    def __init__(self):
        '''
        Constructor
        '''
        self._ST = {} #{userID: [subscriptions]}


    def handleQuery(self, userID, query, validTime, interval, currentTime):
        '''
        Handle new user query. If 1st time add to subscription table, else
        try to answer query.
        @param userID: User ID 
        @param query: Query issued by user
        @param validTIme: Data need to be newer than this time
        @param interval: Subscription interval
        @param currentTime: Current time - when query is issued 
        @return: Query result if already answered or indicate query is pending
        '''
        if userID in self._ST: #User already in table. Check subscription
            for i in range(len(self._ST[userID])):
                if query == self._ST[userID][i].query: #same query
                    if self._ST[userID][i].queryTime != currentTime:
                        self._ST[userID][i].prepareNextRound()
                        return [False] #Result pending
#                        assert(False), 'Past query was not answered'
                    result = [True] #Result pending
                    if self._ST[userID][i].answerTime > -1: #Already answered
                        result = ['Que', currentTime, \
                                self._ST[userID][i].answerTime - currentTime,\
                                self._ST[userID][i].answerTime - \
                                self._ST[userID][i].genTime, \
                                self._ST[userID][i].totalData, \
                                self._ST[userID][i].hops]
                        self._ST[userID][i].prepareNextRound()
                    return result
            #Same user new query
            self._ST[userID].append(USubscription(query, validTime, interval, \
                                        currentTime))
        else: #first time - no queries
            self._ST[userID] = [USubscription(query, validTime, interval, \
                                         currentTime)]
        return []


    def addSubInter(self, userID, query, subQueries):
        '''
        Track sub-interests
        @param userID: User ID 
        @param query: Query issued by user    
        @param subQueries: Sub-queries in interest messages 
        '''
        for i in range(len(self._ST[userID])):
            if query == self._ST[userID][i].query: #Add sub-query
                self._ST[userID][i].addSubInter(subQueries)
                return


    def handleData(self, userID, query, subQuery, genTime, dataSize, hops, \
                   currentTime):
        '''
        Handle data received for interest message
        @param userID: User ID
        @param query: Query issued by user    
        @param subQueries: Sub-query in interest messages 
        @param genTime: When was data generated
        @param dataSize: Size of data   
        @param hops: No of hops required to resolve query
        @param currentTime: Current Time
        @return: Query result if already answered or indicate query is pending
        '''
        for i in range(len(self._ST[userID])):
            if self._ST[userID][i].query == query:
                result = self._ST[userID][i].handleData(subQuery, genTime, \
                                                    dataSize, hops, currentTime)
                if result == True: #This subscription found all sub interests
                    #Has the actual user interest already arrived?
                    if self._ST[userID][i].queryTime <= currentTime:#Answer now
                        result = ['Que', currentTime, \
                                self._ST[userID][i].answerTime - \
                                self._ST[userID][i].queryTime,\
                                self._ST[userID][i].answerTime - 
                                self._ST[userID][i].genTime, \
                                self._ST[userID][i].totalData, \
                                self._ST[userID][i].hops]
                        self._ST[userID][i].prepareNextRound() #Prepare for next round
                        return result
                else: return []
        return []


    def reset(self):
        '''
        Reset subscription table
        '''
        self._ST = {}


    def updateValidTime(self, users, subQuery, nextQueryTime, newInterval, \
                                                                    newDelay):
        '''
        Update valid time of existing user queries that have this sub-interest
        @param users: Dictionary of {userID:query} 
        @param subQuery: Sub-query in interest message
        @param nextQueryTime: Next query time
        @param interval: Interval that queries are generated
        '''
        for i in users:
            for j in range(len(self._ST[i])):
                if self._ST[i][j].query == users[i]: #Same query
                    if subQuery in self._ST[i][j].subInter: #Has sub-query
                        self._ST[i][j].updateValidTime(nextQueryTime, \
                                                       newInterval, newDelay)
                    return


    def getLength(self):
        '''
        @return: size of subscription table 
        '''
        return len(self._ST)