module WeatherData
 where

import ListUtils

--Data for storing the actual statistics

data Actual = Actual Date Temp Percip SkyCover Wind
data Date = Date Int String Int  -- Date( Day, Month, Year) 
data Temp = Temp Int Int Int -- Temp( Avg Min Max)
data Percip = NoData | Trace | Amount Float
data SkyCover = SkyCover Float
data Wind = Wind Float

--To take a list of string and append them with separating spaces
formatShow :: [String] -> String 
formatShow = foldr (\x b -> (x ++ " ") ++ b) ""
--formatShow ["hi","world"] => "hi world "

--Means of having the interactive environment nicely print statistics
instance Show Wind where
 show (Wind n) = formatShow ["Wind",(show n)]
instance Show SkyCover where
 show (SkyCover n) = formatShow ["SkyCover",(show n)]
instance Show Percip where
 show NoData = "NoData"
 show Trace = "Trace"
 show (Amount n) = formatShow ["Amount",(show n)]
instance Show Temp where
 show (Temp avg min max) = formatShow["Temp",(show avg),(show min),(show max)]
instance Show Date where
 show (Date day month year) = formatShow ["Date",(show day),month,(show year)]
instance Show Actual where
 show (Actual d t p s w) = formatShow ["Actual",(show d),(show t),(show p),(show s),(show w)]


--Functions for building dates

-- To build a date based on the format of either the actual or predicted pages
getDate :: [String] -> Date
getDate n | ((length n) == 5) =
  case n of
   (_:day:date:month:year:[]) ->  Date (read date) month (read year)
getDate (_:month:day:year:rest) = Date (read day) month (read year)
-- getDate ["FCST","MON","26","JAN","2004"] => Date 26 "JAN" 2004
-- getDate ["SUN","JAN","25","2004","SALT"] => Date 25 "JAN" 2004

-- Builds a date from the input stream for the actual and predicted pages
dataForDate :: [String] -> Date
dataForDate ls =
 let lsDate = stripTo "MST" ls in
  getDate lsDate
-- dataForDate ["6:55","MST","SUN","JAN","25","2004","SALT"] => Date 25 "JAN" 2004


--Deconstructors for printing Actuals to file 
actualToTuple:: Actual -> ((Int, String, Int), (Int, Int, Int), Float, Float, Float)
actualToTuple (Actual d t p s w) = 
  ((dateToTuple d), (tempToTuple t), (percipToFloat p), (skyToFloat s), (windToFloat w))

dateToTuple :: Date -> (Int, String, Int)
dateToTuple (Date d m y ) = (d, m, y)

tempToTuple :: Temp -> (Int, Int, Int)
tempToTuple (Temp a m x ) = (a,m,x)

percipToFloat :: Percip -> Float
percipToFloat NoData = -2.0
percipToFloat Trace = -1.0
percipToFloat (Amount n) = n

skyToFloat (SkyCover n) = n

windToFloat (Wind n) = n


--Constructors for reading tuples from file
toActual :: ((Int, String, Int), (Int, Int, Int), Float, Float, Float) -> Actual
toActual (d, t, p, s, w) = Actual (toDate d) (toTemp t) (toPercip p) (toSky s) (toWind w)

toDate :: (Int, String, Int) -> Date
toDate (d, m, y) = Date d m y

toTemp :: (Int, Int, Int) -> Temp
toTemp (a, m, x) = Temp a m x

toPercip :: Float -> Percip
toPercip n | n == -2.0 = NoData
           | n == -1.0 = Trace
           | otherwise = Amount n

toSky n = SkyCover n

toWind n = Wind n

--Data for storing the predictions
data Prediction = Predict Date Date Outlook Range CoP
data Outlook = Cloudy Amt | Snow | Sunny | Rain | Tstorms | FreezeRain | Showers
data Amt = Full | Mostly | Partly
data Range = Range Int Int
data CoP = Chance Int

--Means of nicely printing predictions in interactions

instance Show CoP where
 show (Chance p) = formatShow ["Chance",(show p)]
instance Show Range where
 show (Range m x) = formatShow ["Range",(show m),(show x)]
instance Show Amt where
 show Full = "Full"
 show Mostly = "Mostly"
 show Partly = "Partly"
instance Show Outlook where
 show (Cloudy a) = formatShow ["Cloudy",(show a)]
 show Snow = "Snow"
 show Sunny = "Sunny"
 show Rain = "Rain"
 show Tstorms = "Tstorms"
 show FreezeRain = "FreezeRain"
 show Showers = "Showers"
instance Show Prediction where
 show (Predict on for o r c) = 
  formatShow ["Predict",(show on),(show for),(show o),(show r),(show c)]


--Deconstructors for printing predictions to file
predicToTuple :: Prediction -> ((Int,String,Int),(Int,String,Int), Int, (Int,Int), Int)
predicToTuple (Predict on d o r c) = 
  ((dateToTuple on), (dateToTuple d), (outlookToTuple o), (rangeToTuple r), (copToTuple c))

outlookToTuple :: Outlook -> Int
outlookToTuple (Cloudy a) = 10 + (amtToTuple a)
outlookToTuple Snow = 20
outlookToTuple Sunny = 30
outlookToTuple Rain = 40
outlookToTuple Tstorms = 50
outlookToTuple FreezeRain = 60
outlookToTuple Showers = 70

amtToTuple :: Amt -> Int
amtToTuple Full = 0
amtToTuple Mostly = 1
amtToTuple Partly = 2

rangeToTuple :: Range -> (Int, Int)
rangeToTuple (Range min max) = (min,max)

copToTuple (Chance n) = n

--Constructors for reading predictions from file
toPredict :: ((Int,String,Int),(Int,String,Int), Int, (Int,Int), Int) -> Prediction
toPredict (on, d, o, r, c) = 
  Predict (toDate on) (toDate d) (toOutlook o) (toRange r) (toCoP c)

toOutlook :: Int -> Outlook
toOutlook n | n < 20 = Cloudy (toAmt (n - 10))
toOutlook 20 = Snow
toOutlook 30 = Sunny
toOutlook 40 = Rain
toOutlook 50 = Tstorms
toOutlook 60 = FreezeRain
toOutlook 70 = Showers

toAmt 0 = Full
toAmt 1 = Mostly
toAmt 2 = Partly

toRange (m,x) = Range m x

toCoP n = Chance n
