'''
Created on Sep 4, 2012
@author: 'Dilum Bandara'
@version: '0.1'
@contact: 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 Config as Config


class ReadData(object):
    '''
    Read data class. Read sensor readings and & queries from input files
    '''
    def __init__(self, stationFile, sensorsFile, queFile):
        '''
        Constructor        
        @param stationFile: Weather station info file name        
        @param sensorsFile: Sensor readings file name
        @param queFile: Query file name
        '''
        self.fdInStation = open(stationFile, 'r')
        self.fdInSen = open(sensorsFile, 'r')
        self.fdInQue = open(queFile, 'r')        
        #Read 1st line containing attribute names
        self._attSetSta = self.fdInStation.readline().split()


    def __del__(self):
        '''
        Destructor
        '''
        self.fdInStation.close()
        self.fdInSen.close()
        self.fdInQue.close()


    def getWStation(self):
        '''
        Read information about weather next station
        @return: List of sensor readings. [[att name, value], ..., [att name, 
        value]]. [] if no data
        '''
        tmpAtts = self.fdInStation.readline().split()
        if len(tmpAtts) == 0: return []

        station = [] #[SID, X< Y, ELEV, sampling interval, [sensors]]
        for name in self._attSetSta:
            if name == 'SID': station.append([name, int(tmpAtts[0])])
            elif name == 'X': station.append([name, float(tmpAtts[1])])
            elif name == 'Y': station.append([name, float(tmpAtts[2])])
            elif name == 'ELEV': station.append([name, float(tmpAtts[3])])
            elif name == 'Int': station.append([name, int(tmpAtts[4])])
            elif name == 'Sensors': station.append(tmpAtts[5:])
            else: assert(False), 'Unknown sensor name ' + name
        return station


    def getSReading(self):
        '''
        Read sensor readings from weather station
        @return: List of sensor readings. [SID, time, [att name, value], ..., 
        [att name, value]]. [] if no data
        '''
        tmpLine = self.fdInSen.readline().split()
        if len(tmpLine) == 0: return []
        sensors = [int(tmpLine[0]), float(tmpLine[1])]
        tmpAttrib = []
        for i in range(2, len(tmpLine)): #read attribute name, value
            if (i % 2) != 0: continue#Read starting from 2nd entry

            if tmpLine[i] == 'X' or tmpLine[i] == 'Y' or tmpLine[i] == 'ELEV':
                v = float(tmpLine[i + 1])
                if tmpLine[i] == 'X':
                    assert(v >= 0), 'X < 0' 
                    assert(v <= Config.SIZE_TORUS[0]), 'X > torus[x]'
                elif tmpLine[i] == 'Y':
                    assert(v >= 0), 'Y < 0' 
                    assert(v <= Config.SIZE_TORUS[1]), 'Y > torus[Y]'
                else:
                    assert(v >= Config.MIN_ELEV), 'ELEV < Min' 
                    assert(v <= Config.MAX_ELEV), 'ELEV > Max'
                tmpAttrib = [tmpLine[i], v]
            elif tmpLine[i] == 'DD' or tmpLine[i] == 'FF' or \
                                                        tmpLine[i] == 'FFGUST':
                v = float(tmpLine[i + 1])
                if tmpLine[i] == 'DD':
                    assert(v >= Config.MIN_DD), 'DD < Min'
                    assert(v <= Config.MAX_DD), 'DD > Max'
                elif tmpLine[i] == 'FF':
                    assert(v >= Config.MIN_FF), 'FF < Min'
                    assert(v <= Config.MAX_FF), 'FF > Max'
                else:
                    assert(v >= Config.MIN_FFGUST), 'FFGUST < Min'
                    assert(v <= Config.MAX_FFGUST), 'FFGUST > Max'
                tmpAttrib = [tmpLine[i], v]
            elif tmpLine[i] == 'P' or tmpLine[i] == 'RH' or tmpLine[i] == 'T':
                v = float(tmpLine[i + 1])
                if tmpLine[i] == 'P':
                    assert(v >= Config.MIN_P), 'P < Min'
                    assert(v <= Config.MAX_P), 'P > Max'
                elif tmpLine[i] == 'RH':
                    assert(v >= Config.MIN_RH), 'RH < Min'
                    assert(v <= Config.MAX_RH), 'RH > Max'
                else:
                    assert(v >= Config.MIN_T), 'T < Min'
                    assert(v <= Config.MAX_T), 'T > Max'
                tmpAttrib = [tmpLine[i], v]
            elif tmpLine[i] == 'PCP1H' or tmpLine[i] == 'PCP5M'\
                        or tmpLine[i] == 'PCP15M' or tmpLine[i] == 'PCPRATE':
                v = float(tmpLine[i + 1])
                if tmpLine[i] == 'PCP1H':
                    assert(v >= Config.MIN_PCP1H), 'PCP1H < Min'
                    assert(v <= Config.MAX_PCP1H), 'PCP1H > Max'
                elif tmpLine[i] == 'PCP5M':
                    assert(v >= Config.MIN_PCP1H), 'PCP5M < Min'
                    assert(v <= Config.MAX_PCP1H), 'PCP5M > Max'
                elif tmpLine[i] == 'PCP15M':
                    assert(v >= Config.MIN_PCP15M), 'PCP15M < Min'
                    assert(v <= Config.MAX_PCP15M), 'PCP15M > Max'
                else:
                    assert(v >= Config.MIN_PCPRATE), 'PCPRATE < Min'
                    assert(v <= Config.MAX_PCPRATE), 'PCPRATE > Max'
                tmpAttrib = [tmpLine[i], v]
            elif tmpLine[i] == 'PCPINT' or tmpLine[i] == 'PCPTYPE':
                v = int(tmpLine[i + 1])
                if tmpLine[i] == 'PCPINT':
                    assert(v >= Config.MIN_PCPINT), 'PCPINT < Min'
                    assert(v <= Config.MAX_PCPINT), 'PCPINT > Max'
                else:
                    assert(v >= Config.MIN_PCPTYPE), 'PCPTYPE < Min'
                    assert(v <= Config.MAX_PCPTYPE), 'PCPTYPE > Max'
                tmpAttrib = [tmpLine[i], v]
            else: assert(False), 'Unknown sensor type in queries '+ tmpLine[i]
            sensors.append(tmpAttrib)
            tmpAttrib = []
        return sensors


    def getQuery(self):
        '''
        Read next query
        @return: Query as a list. [userID, time, validTime, [att name 
         min val, max val], ..., [att name, min val, max val]], [] if no data
        '''
        tmpLine = self.fdInQue.readline().split()
        if len(tmpLine) == 0: return []
        query = [int(tmpLine[0]), float(tmpLine[1]), float(tmpLine[2])] 
        tmpAttrib = []
        for i in range(3, len(tmpLine)): #read attribute name, min, max
            if (i % 3) == 0: #Read starting from 3rd entry
                if tmpLine[i] == 'X' or tmpLine[i] == 'Y' or \
                                                        tmpLine[i] == 'ELEV':
                    tmpAttrib = [tmpLine[i], float(tmpLine[i + 1]), \
                                  float(tmpLine[i + 2])]
                elif tmpLine[i] == 'DD' or tmpLine[i] == 'FF' or \
                                                        tmpLine[i] == 'FFGUST':
                    tmpAttrib = [tmpLine[i], float(tmpLine[i + 1]), \
                                  float(tmpLine[i + 2])]
                elif tmpLine[i] == 'P':
                    tmpAttrib = [tmpLine[i], float(tmpLine[i + 1]), \
                                  float(tmpLine[i + 2])]
                elif tmpLine[i] == 'PCP1H' or tmpLine[i] == 'PCP5M'\
                        or tmpLine[i] == 'PCP15M' or tmpLine[i] == 'PCPRATE':
                    tmpAttrib = [tmpLine[i], float(tmpLine[i + 1]), \
                                      float(tmpLine[i + 2])]
                elif tmpLine[i] == 'PCPINT' or tmpLine[i] == 'PCPTYPE':
                    tmpAttrib = [tmpLine[i], int(tmpLine[i + 1]), \
                                  int(tmpLine[i + 2])]
                elif tmpLine[i] == 'T':
                    tmpAttrib = [tmpLine[i], float(tmpLine[i + 1]), \
                                  float(tmpLine[i + 2])]
                elif tmpLine[i] == 'RH':
                    tmpAttrib = [tmpLine[i], float(tmpLine[i + 1]), \
                                  float(tmpLine[i + 2])]
                else:
                    assert(False), 'Unknown sensor type in queries '+ tmpLine[i]
                query.append(tmpAttrib)
                tmpAttrib = []
        return query