{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}

module Data.Aviation.Stratux.Types.Situation(
  Situation(..)
, HasSituation(..)
) where

import Control.Applicative(Applicative((<*>)))
import Control.Lens(makeClassy)
import Data.Aeson(FromJSON(parseJSON), ToJSON(toJSON), (.:), withObject, (.=), object)
import Data.Aviation.Stratux.Types.UTCTimes(HasUTCTimes(utcTimes))
import Data.Eq(Eq)
import Data.Int(Int)
import Data.Functor((<$>))
import Data.Ord(Ord)
import Data.Time(UTCTime)
import Prelude(Double, Show)

-- $setup
-- >>> :set -XOverloadedStrings
-- >>> import Control.Lens
-- >>> import Data.Aeson(decode, encode)
-- >>> import Data.Maybe(Maybe)
-- >>> import Prelude
-- >>> import Data.Time

data Situation =
  Situation {
    _lat :: Double
  , _lon :: Double
  , _heightAboveEllipsoid :: Double
  , _geoidSep :: Double
  , _satellites :: Int
  , _satellitesTracked :: Int
  , _satellitesSeen :: Int
  , _accuracy :: Double
  , _nacp :: Int
  , _alt :: Double
  , _accuracyVert :: Double
  , _gpsVertVel :: Double
  , _lastFixLocalTime :: UTCTime
  , _trueCourse :: Double
  , _groundSpeed :: Int
  , _lastGroundTrackTime :: UTCTime
  , _lastGPSTimeTime :: UTCTime
  , _lastNMEAMessage :: UTCTime
  , _temp :: Double
  , _pressureAlt :: Double
  , _pitch :: Double
  , _roll :: Double
  , _gyroHeading :: Double
  , _lastAttitudeTime :: UTCTime
  } deriving (Eq, Ord, Show)

makeClassy ''Situation

-- |
--
-- >>> decode "{\"Lat\":-27.39512,\"Lng\":152.87691,\"HeightAboveEllipsoid\":214.26509,\"GeoidSep\":125,\"Satellites\":7,\"SatellitesTracked\":11,\"SatellitesSeen\":8,\"Accuracy\":5.4,\"NACp\":10,\"Alt\":89.26509,\"AccuracyVert\":7.2,\"GPSVertVel\":0.18700787,\"LastFixLocalTime\":\"0001-01-01T00:17:01.25Z\",\"TrueCourse\":353,\"GroundSpeed\":0,\"LastGroundTrackTime\":\"0001-01-01T00:17:01.25Z\",\"LastGPSTimeTime\":\"0001-01-01T00:17:00.55Z\",\"LastNMEAMessage\":\"0001-01-01T00:17:01.25Z\",\"Temp\":0,\"Pressure_alt\":0,\"Pitch\":0,\"Roll\":0,\"Gyro_heading\":0,\"LastAttitudeTime\":\"0001-01-01T00:00:00Z\"}" :: Maybe Situation
-- Just (Situation {_lat = -27.39512, _lon = 152.87691, _heightAboveEllipsoid = 214.26509, _geoidSep = 125.0, _satellites = 7, _satellitesTracked = 11, _satellitesSeen = 8, _accuracy = 5.4, _nacp = 10, _alt = 89.26509, _accuracyVert = 7.2, _gpsVertVel = 0.18700787, _lastFixLocalTime = 0001-01-01 00:17:01.25 UTC, _trueCourse = 353.0, _groundSpeed = 0, _lastGroundTrackTime = 0001-01-01 00:17:01.25 UTC, _lastGPSTimeTime = 0001-01-01 00:17:00.55 UTC, _lastNMEAMessage = 0001-01-01 00:17:01.25 UTC, _temp = 0.0, _pressureAlt = 0.0, _pitch = 0.0, _roll = 0.0, _gyroHeading = 0.0, _lastAttitudeTime = 0001-01-01 00:00:00 UTC})
instance FromJSON Situation where
  parseJSON =
    withObject "Situation" (\x ->
      Situation <$>
        x .: "Lat" <*>
        x .: "Lng" <*>
        x .: "HeightAboveEllipsoid" <*>
        x .: "GeoidSep" <*>
        x .: "Satellites" <*>
        x .: "SatellitesTracked" <*>
        x .: "SatellitesSeen" <*>
        x .: "Accuracy" <*>
        x .: "NACp" <*>
        x .: "Alt" <*>
        x .: "AccuracyVert" <*>
        x .: "GPSVertVel" <*>
        x .: "LastFixLocalTime" <*>
        x .: "TrueCourse" <*>
        x .: "GroundSpeed" <*>
        x .: "LastGroundTrackTime" <*>
        x .: "LastGPSTimeTime" <*>
        x .: "LastNMEAMessage" <*>
        x .: "Temp" <*>
        x .: "Pressure_alt" <*>
        x .: "Pitch" <*>
        x .: "Roll" <*>
        x .: "Gyro_heading" <*>
        x .: "LastAttitudeTime"
        )

-- |
--
-- >>> encode (Situation (-27.39412) 152.59218 214.26509 125.0 7 11 8 5.4 10 89.26509 7.2 0.18700787 (UTCTime (fromGregorian 1 1 1) 597) 353.0 0 (UTCTime (fromGregorian 1 1 1) 597) (UTCTime (fromGregorian 1 1 1) 597) (UTCTime (fromGregorian 1 1 1) 597) 0.0 0.0 0.0 0.0 0.0 (UTCTime (fromGregorian 1 1 1) 597))
-- "{\"Gyro_heading\":0,\"SatellitesSeen\":8,\"Roll\":0,\"Satellites\":7,\"AccuracyVert\":7.2,\"TrueCourse\":353,\"Pressure_alt\":0,\"GPSVertVel\":0.18700787,\"GeoidSep\":125,\"SatellitesTracked\":11,\"Lat\":-27.39412,\"NACp\":10,\"Temp\":0,\"LastAttitudeTime\":\"0001-01-01T00:09:57Z\",\"GroundSpeed\":0,\"Accuracy\":5.4,\"Lng\":152.59218,\"LastFixLocalTime\":\"0001-01-01T00:09:57Z\",\"HeightAboveEllipsoid\":214.26509,\"LastGroundTrackTime\":\"0001-01-01T00:09:57Z\",\"Pitch\":0,\"LastNMEAMessage\":\"0001-01-01T00:09:57Z\",\"LastGPSTimeTime\":\"0001-01-01T00:09:57Z\",\"Alt\":89.26509}"
instance ToJSON Situation where
  toJSON (Situation lat_ lon_ heightAboveEllipsoid_ geoidSep_ satellites_ satellitesTracked_ satellitesSeen_ accuracy_ nacp_ alt_ accuracyVert_ gpsVertVel_ lastFixLocalTime_ trueCourse_ groundSpeed_ lastGroundTrackTime_ lastGPSTimeTime_ lastNMEAMessage_ temp_ pressureAlt_ pitch_ roll_ gyroHeading_ lastAttitudeTime_) =
    object [
      "Lat" .= lat_
    , "Lng" .= lon_
    , "HeightAboveEllipsoid" .= heightAboveEllipsoid_
    , "GeoidSep" .= geoidSep_
    , "Satellites" .= satellites_
    , "SatellitesTracked" .= satellitesTracked_
    , "SatellitesSeen" .= satellitesSeen_
    , "Accuracy" .= accuracy_
    , "NACp" .= nacp_
    , "Alt" .= alt_
    , "AccuracyVert" .= accuracyVert_
    , "GPSVertVel" .= gpsVertVel_
    , "LastFixLocalTime" .= lastFixLocalTime_
    , "TrueCourse" .= trueCourse_
    , "GroundSpeed" .= groundSpeed_
    , "LastGroundTrackTime" .= lastGroundTrackTime_
    , "LastGPSTimeTime" .= lastGPSTimeTime_
    , "LastNMEAMessage" .= lastNMEAMessage_
    , "Temp" .= temp_
    , "Pressure_alt" .= pressureAlt_
    , "Pitch" .= pitch_
    , "Roll" .= roll_
    , "Gyro_heading" .= gyroHeading_
    , "LastAttitudeTime" .= lastAttitudeTime_
    ]

instance HasUTCTimes Situation where
  utcTimes f (Situation lat_ lon_ heightAboveEllipsoid_ geoidSep_ satellites_ satellitesTracked_ satellitesSeen_ accuracy_ nacp_ alt_ accuracyVert_ gpsVertVel_ lastFixLocalTime_ trueCourse_ groundSpeed_ lastGroundTrackTime_ lastGPSTimeTime_ lastNMEAMessage_ temp_ pressureAlt_ pitch_ roll_ gyroHeading_ lastAttitudeTime_) =
      (\lastFixLocalTime__ lastGroundTrackTime__ lastGPSTimeTime__ lastNMEAMessage__ lastAttitudeTime__ ->
        Situation lat_ lon_ heightAboveEllipsoid_ geoidSep_ satellites_ satellitesTracked_ satellitesSeen_ accuracy_ nacp_ alt_ accuracyVert_ gpsVertVel_ lastFixLocalTime__ trueCourse_ groundSpeed_ lastGroundTrackTime__ lastGPSTimeTime__ lastNMEAMessage__ temp_ pressureAlt_ pitch_ roll_ gyroHeading_ lastAttitudeTime__) <$>
        f lastFixLocalTime_ <*>
        f lastGroundTrackTime_ <*>
        f lastGPSTimeTime_ <*>
        f lastNMEAMessage_ <*>
        f lastAttitudeTime_