from LogAnalyzer import Test, TestResult


class TestGPSGlitch(Test):
    '''test for GPS glitch reporting or bad GPS data (satellite count, hdop)'''

    def __init__(self):
        Test.__init__(self)
        self.name = "GPS"

    def findSatsChan(self, channels):
        for chan in "NSats", "NSat", "numSV":
            if chan in channels:
                return channels[chan]

    def findHDopChan(self, channels):
        for chan in "HDop", "HDp", "EPH":
            if chan in channels:
                return channels[chan]

    def run(self, logdata, verbose):
        self.result = TestResult()
        self.result.status = TestResult.StatusType.GOOD

        if "GPS" not in logdata.channels:
            self.result.status = TestResult.StatusType.UNKNOWN
            self.result.statusMessage = "No GPS log data"
            return

        # glitch protection is currently copter-only, but might be
        # added to other vehicle types later and there's no harm in
        # leaving the test in for all
        gpsGlitchCount = 0
        if "ERR" in logdata.channels:
            assert(len(logdata.channels["ERR"]["Subsys"].listData) ==
                   len(logdata.channels["ERR"]["ECode"].listData))
            for i in range(len(logdata.channels["ERR"]["Subsys"].listData)):
                subSys = logdata.channels["ERR"]["Subsys"].listData[i][1]
                eCode = logdata.channels["ERR"]["ECode"].listData[i][1]
                if subSys == 11 and (eCode == 2):
                    gpsGlitchCount += 1
        if gpsGlitchCount:
            self.result.status = TestResult.StatusType.FAIL
            self.result.statusMessage = ("GPS glitch errors found (%d)" %
                                         gpsGlitchCount)

        # define and check different thresholds for WARN level and
        # FAIL level
        # TODO: for plane, only check after first instance of throttle
        # > 0, or after takeoff if we can reliably detect it
        minSatsWARN = 6
        minSatsFAIL = 5
        maxHDopWARN = 3.0
        maxHDopFAIL = 10.0
        satsChan = self.findSatsChan(logdata.channels["GPS"])
        hdopChan = self.findHDopChan(logdata.channels["GPS"])
        foundBadSatsWarn = satsChan.min() < minSatsWARN
        foundBadHDopWarn = hdopChan.max() > maxHDopWARN
        foundBadSatsFail = satsChan.min() < minSatsFAIL
        foundBadHDopFail = hdopChan.max() > maxHDopFAIL
        satsMsg = ("Min satellites: %s, Max HDop: %s" %
                   (satsChan.min(), hdopChan.max()))
        if gpsGlitchCount:
            self.result.statusMessage = "\n".join([self.result.statusMessage,
                                                   satsMsg])
        if foundBadSatsFail or foundBadHDopFail:
            if not gpsGlitchCount:
                self.result.status = TestResult.StatusType.FAIL
                self.result.statusMessage = satsMsg
        elif foundBadSatsWarn or foundBadHDopWarn:
            if not gpsGlitchCount:
                self.result.status = TestResult.StatusType.WARN
                self.result.statusMessage = satsMsg
