#-------------------------------------------------------------------------
# Description: This produces a Fire Weather Table. The table produces data
#  needed for the FWF.  The FWF is run seperately and the data are merged
#  by code in SLC_FWF_TextRules and .pl programs in /home/ifps/release
#-------------------------------------------------------------------------
# Copying:
# This software is in the public domain, furnished "as is", without technical
# support, and with no warranty, express or implied, as to its usefulness for
# any purpose.
#-------------------------------------------------------------------------
#   RPP version 20.2
#-------------------------------------------------------------------------

import SLC_FWF_TextRules, TextRules
import SampleAnalysis
import ForecastSeries
import time, string

class TextProduct(TextRules.TextRules, SampleAnalysis.SampleAnalysis):
    Definition =  {
        "type": "smart",
        #"displayName": "FWFWindTable",
        "displayName": "None",
        
        ## Edit Areas: Create Combinations file with edit area combinations.
        "defaultEditAreas": [("Fire1Above8000","Fire Area 1 above 8000"),
        ("Fire2Above8000","Fire Area 2 above 8000"),
        ("Fire3Above8000","Fire Area 3 above 8000"),
        ],
        
        # product identifiers
        "productName": "FIRE SLC stuff", # product name
        "outputFile": "/home/ifps/slcpractice/products/TEXT/FWFWindTable",
        "fullStationID": "Kxxx",    # full station identifier (4letter)
        "wmoID": "FNUS5x",          # WMO ID
        "pil": "FWFxxx",            # Product pil
        "areaName": "",             # Name of state, such as "GEORGIA" -- optional
        "wfoCity": "WfoCity",       # Location of WFO - city name
        "wfoState": "WfoState",     # Location of WFO - state name
        
        # Product-specific variables:
        # To include a TempPopTable for each area in the current Combination:
        #   Set "includeTempPopTable" to 1
        #   Make sure you are using a Combinations file
        #   in your AreaFcst_Local file.g.
        #       "defaultEditAreas": "Combinations",
        #   Create a CityDictionary TextUtility file and specify
        #   in your AreaFcst_Local file (see examples/textProducts directory)
        #   Create the TempPopTable_for_AreaFcst_Local product from the
        #       examples/textProducts directory
        "includeTempPopTable": 0,
##        "cityDictionary": "CityDictionary",
        # Area Dictionary -- Descriptive information about zones
##        "areaDictionary": "AreaDictionary", 
        # Language
        "language": "english",

        # If summaryExtended == 1, then a summary extended forecast will
        # be generated for the given summaryArea
        "summaryExtended": 0,
##        "summaryArea":"FireArea",
        # If individualExtended == 1, an extended forecast will be
        # generated for each individual area
        # If extendedLabel == 1, a label will be included for each
        #  individual extended
        "individualExtended": 0,
##        "extendedLabel": 0,
        }

    def __init__(self):
        TextRules.TextRules.__init__(self)
        SampleAnalysis.SampleAnalysis.__init__(self)

    ########################################################################
    # OVERRIDING THRESHOLDS AND VARIABLES
    ########################################################################
    
    def phrase_descriptor_dict(self, statDict, argDict):
        dict = TextRules.TextRules().phrase_descriptor_dict(statDict, argDict)
        dict["highs"] = self.checkProduct,
        dict["lows"] = self.checkProduct,
        return dict

    def checkProduct(self, statDict, argDict, key, element):
        component = argDict["subType"]
        if component == "FirePeriod":
            return ""
        else:
            return key
        
    # Uncomment any combinations you wish to collapse.
    # For example, if the first entry is uncommented,
    #  the phrase: scattered rain showers and widespread rain
    #  will collapse to: scattered rain showers.
    def wxCombinations(self):
        return [
            ("RW", "R"),
            ("SW", "S"),
            ## ("T","RW"),
            ]

    def minmax_std_deviation(self, parmHisto, timeRange, componentName):
        # Replaces MINMAX_STD_DEVIATION
        # Number of standard deviations to compute around the weighted
        # average for a stdDev_Minmax
        return 1.4

    ########################################################################
    # COMPONENT PRODUCT DEFINITIONS
    ########################################################################

    def FirePeriod(self):
        return {
            "type": "component",
            "analysisList": [
                ("Wind", self.vectorTextMedianRange),
##                      ("Wind", self.vectorTextAvg),
                      ],
            "textRules":[
                (self._fireWind_Ridgephrase),
                ],
            "autoUpperCase":1,
            "autoSentence": 0,
            "combineSentences": 0,
            "postProcessPhrase": self.postProcessPhrase,
            "localEffects": {
                   "MinT": [{
                       "area1": "BelowElev",
                       "area2": "AboveElev",
                       "threshold": 8,
                       "rangeReportingMethod": self.getScalarRange,
                       "simpleValueReportingMethod": self.getTempPhrase,
                       "introWords": "",
                       "area1Words": "",
                       "exceptionWords": "...except ",
                       "area2Words": " above timberline",
                       }],
                   "MaxT": [{
                       "area1": "BelowElev",
                       "area2": "AboveElev",
                       "threshold": 8,
                       "rangeReportingMethod": self.getScalarRange,
                       "simpleValueReportingMethod": self.getTempPhrase,
                       "introWords": "",
                       "area1Words": "",
                       "exceptionWords": "...except ",
                       "area2Words": " above timberline",
                       }],
                   "MinRH": [{
                       "area1": "BelowElev",
                       "area2": "AboveElev",
                       "threshold": 8,
                       "rangeReportingMethod": self.getScalarRange,
                       "simpleValueReportingMethod": self.getTempPhrase,
                       "introWords": "",
                       "area1Words": "%",
                       "exceptionWords": "...except ",
                       "area2Words": "% above timberline",
                       }],
                   "MaxRH": [{
                       "area1": "BelowElev",
                       "area2": "AboveElev",
                       "threshold": 8,
                       "rangeReportingMethod": self.getScalarRange,
                       "simpleValueReportingMethod": self.getTempPhrase,
                       "introWords": "",
                       "area1Words": "%",
                       "exceptionWords": "...except ",
                       "area2Words": "% above timberline",
                       }],
                   },
            }

    def generateForecast(self, argDict):
        # Generate Text Phrases for a list of edit areas

        # Get variables
        error = self._getVariables(argDict)
        if error is not None:
            return error

        # Get the areaList -- derived from defaultEditAreas and
        # may be solicited at run-time from user if desired
        self._areaList = self.getAreaList(argDict)

        # Determine time ranges
        error = self._determineTimeRanges(argDict)
        if error is not None:
            return error

        # Sample the data
        error = self._sampleData(argDict)
        if error is not None:
            return error

        # Initialize the output string
        fcst = ""
        fcst = self._preProcessProduct(fcst, argDict)

        # Generate the product for each edit area in the list
        fraction = 0
        fractionOne = 1.0/float(len(self._areaList))
        percent = 50.0
        self.setProgressPercentage(percent)
        for editArea, areaLabel in self._areaList:
            self.progressMessage(fraction, percent, "Making Product for " + areaLabel)
            fcst = self._preProcessArea(fcst, editArea, areaLabel, argDict)
            fcst  = self._makeProduct(fcst, editArea, areaLabel, argDict)
            fcst = self._postProcessArea(fcst, editArea, areaLabel, argDict)
            fraction = fractionOne
##        fcst = self._postProcessProduct(fcst, argDict)
        return fcst

    def _getVariables(self, argDict):
        # Get Definition variables
        self._definition = argDict["forecastDef"]
        for key in self._definition.keys():
            exec "self._" + key + "= self._definition[key]"

        # DO NOT Display the dialog for the user to choose issuance        
##        additionalItems = []
##        status, varDict = self.displayIssuanceDialog(
##            self._definition["displayName"], self._issuance_list(argDict), additionalItems)
##        if status != "Ok": 
##             return "Product Cancelled"
##        argDict["varDict"] = varDict
                ## Figure out if day or mid shift ZFP package.
        time1 = time.gmtime()
        (year, month, day, h, m, s, w, day, dst) = time1
##        print "ZHour: ", h
        ## Adjust hours as needed in Zulu.
        if h > 17 or h < 6: # day shift
            self._productType = "Afternoon"
            self.totalPeriods = 4
        else:
            self._productType = "Morning"
            self.totalPeriods = 3
        
##        self._productType = varDict["Forecast Product"]                    
        self._seriesUtil = self._definition["defaultEditAreas"]
##        print self._productType
        
        return None

    def _determineTimeRanges(self, argDict):
        # Set up the Series Definition and initial Time Range
        self._issuanceInfo = self.getIssuanceInfo(
            self._productType, self._issuance_list(argDict))
        self._timeRange = self._issuanceInfo.timeRange()
        self._expireTime = self._issuanceInfo.expireTime()
        self._definition["SeriesDef"] = self._issuanceInfo.seriesDef()
        self._definition["labelMethod"] = self._createLabel
        self._definition["priorPeriod"] = 24
        # Determine the extended range
        if self._individualExtended == 1:
            self._extendedStart = self._timeRange.endTime() - 24*5*3600
        else:
            self._extendedStart = self._timeRange.endTime()
        self._extendedRange = self.IFP().TimeRange(
            self._extendedStart, self._extendedStart + 3600)

        # Calculate current times
        self._ddhhmmTime = self.getCurrentTime(
            argDict, "%d%H%M", shiftToLocal=0, stripLeading=0)
        self._timeLabel = self.getCurrentTime(
            argDict, "%l%M %p %Z %a %b %e %Y", stripLeading=1)
        return None

    def _sampleData(self, argDict):
        # Sample and analyze the data for the series
        # This data will be available in argDict["seriesData"] for text rules
        self._seriesProcessor = ForecastSeries.ForecastSeries()
        error = self._seriesProcessor.getSeriesData(
            argDict, self._definition, self._timeRange, self._areaList)
        if error is not None:
            return error
        return None

    def _preProcessProduct(self, fcst, argDict):
        # Product header
        fcst = "template:\n"
        return fcst

    def _preProcessArea(self, fcst, editArea, areaLabel, argDict):
        # This is the header for an edit area combination
        fcst = fcst + areaLabel + "\n"
        return fcst

    def _makeProduct(self, fcst, editArea, areaLabel, argDict):
        argDict["language"] = self._language
        # Generate Series Forecast for Edit Area
        fcst = fcst + self._seriesProcessor.generateForecast(
            argDict, editArea, areaLabel)
        if self._includeTempPopTable == 1:
            fcst = fcst + self._makeTempPopTable(areaLabel, argDict)
        return fcst

    def _postProcessArea(self, fcst, editArea, areaLabel, argDict):
        fcst = fcst + "=\n$$\n\n"
        return fcst

    def _postProcessProduct(self, fcst, argDict):
        # Add one extended
        if self._summaryExtended == 1:
            fcst = fcst + "\n.EXTENDED...\n\n"
            extended = self.generateProduct("ExtendedSeries",
                argDict, area=self._summaryArea,
                timeRange=self._extendedRange)
            fcst = fcst + string.upper(extended)
        fcst = fcst + "\n.OUTLOOK\n\n=\n$$"
        self.setProgressPercentage(100)
        self.progressMessage(0, 100, self._displayName + " Complete")
        return fcst

    ########################################################################
    # PRODUCT-SPECIFIC METHODS
    ########################################################################

    def _issuance_list(self, argDict):
        seriesDefAM = [
            ("FirePeriod", "period1"),
            ("FirePeriod", 12), ("FirePeriod", 12),
           ]
        seriesDefPM = [
            ("FirePeriod", "period1"),
            ("FirePeriod", 12), ("FirePeriod", 12), ("FirePeriod", 12)
            ]
        
        return [
            ("Morning", self.DAY(), self.NIGHT(), self.NIGHT(),
             ".TODAY...\n", "early in the morning", "late in the afternoon",
             1, seriesDefAM), 
            ("Morning Update", "issuanceHour", self.NIGHT(), self.NIGHT(),
             ".REST OF TODAY...\n", "early in the morning", "late in the afternoon",
             1, seriesDefAM), 
            ("Afternoon Update", "issuanceHour", self.NIGHT(), self.NIGHT(),
             ".REST OF TODAY...\n", "early in the morning","late in the afternoon",
             1, seriesDefAM), 
            #  End times are tomorrow:
            ("Afternoon", self.NIGHT(), 24 + self.DAY(), 24 + self.DAY(),
             ".TONIGHT...\n", "late in the night", "early in the evening",
             1, seriesDefPM), 
            ("Evening Update", "issuanceHour", 24 + self.DAY(), 24 + self.DAY(),
             ".REST OF TONIGHT...\n", "late in the night","early in the evening",
             1, seriesDefPM),
            # For the early morning update, this produces:
            # REST OF TONIGHT:
            # MONDAY
            # MONDAY NIGHT
            ("Early Morning Update", "issuanceHour", 24 + self.DAY(), 24 + self.DAY(),
             ".REST OF TONIGHT...\n", "early in the morning","late in the afternoon",
             0, seriesDefPM), 
            ]

    def lateDay_descriptor(self, statDict, argDict, timeRange):
        # If time range is in the first period, return period1 descriptor for
        #  late day -- default 3pm-6pm
        if self._issuanceInfo.period1TimeRange().contains_tr(timeRange):
            return self._issuanceInfo.period1LateDayPhrase()
        else:
            return "late in the afternoon"
        
    def lateNight_descriptor(self, statDict, argDict, timeRange):
        # If time range is in the first period, return period1 descriptor for
        #  late night -- default 3am-6am
        if self._issuanceInfo.period1TimeRange().contains_tr(timeRange):
            return self._issuanceInfo.period1LateNightPhrase()
        else:
            return "early in the morning"

    def _createLabel(self, timeRange, currentLocalTime, shift, index):
        # Make a label given the timeRange in GMT and the shift to
        # convert it to local time. currentLocalTime can be used to
        # compare to current day.

        if timeRange.duration() <= 3600:
                return ""
        if index == 0:
            return self._issuanceInfo.period1Label()
        today = self._issuanceInfo.todayFlag()
        label =  self.getWeekday(timeRange, holidays=1, shiftToLocal=1,
                    labelType="CapitalWithPeriod", today=today, tomorrow=0)
        #print label, timeRange.startTime(), self._extendedStart
        if timeRange.startTime() < self._extendedStart:
            return label + "\n"
        else:
            return label

    def _makeTempPopTable(self, areaLabel, argDict):
        # For each area in the areaLabel group of Combinations,
        #   For each city
        #     Generate a TempPopTable
        exec "import " + self._seriesUtil
        exec "combinations = "+ self._seriesUtil + ".Combinations"
        for seriesList, label in combinations:
            if label == areaLabel:
                break
        exec "import " + self._cityDictionary
        exec "cityDict = " + self._cityDictionary + ".CityDictionary"
        table = ""
        # Show title only before first city
        argDict["_showTempPopTitle"]= 1
        for area in seriesList:
            cities = cityDict[area]
            for city, cityLabel in cities:
                table = table + self.generateProduct(
                    "TempPopTable_for_AreaFcst_Local", argDict, city,
                    self._timeRange, areaLabel=cityLabel)
                argDict["_showTempPopTitle"]= 0
        table = "\n" + table + "\n\n"
        return table

    def HighlightPhrase(self):
        return {
          "type": "phrase",
          "displayName": None,
          "lineLength": 69,
          "analysisList":[
                          ("Highlights", self.avg_byTimeRange),
                         ],

          "textRules":[
                       self.highlights_phrase,
                       ],
           "autoSentence": 1,
           "autoUpperCase": 0,
        }