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

module Data.Aviation.Stratux.Types.Settings (
  Settings(..)
, HasSettings(..)
, SettingsSet(..)
, HasSettingsSet(..)
, AsSettings(..)
, emptySettingsSet
) where

import Control.Applicative((<*>))
import Control.Category((.), id)
import Control.Lens(makeClassy, Prism', prism')
import Data.Aeson(FromJSON(parseJSON), ToJSON(toJSON), (.:), (.:?), (.=), object, withObject)
import Data.Aeson.Types(KeyValue)
import Data.Aviation.Stratux.Types.NetworkConnection
import Data.Bool(Bool)
import Data.Eq(Eq)
import Data.Functor((<$>))
import Data.Function(($))
import Data.Int(Int)
import Data.Maybe(Maybe(Nothing, Just), catMaybes)
import Data.Ord(Ord)
import Data.String(String)
import Data.Text(Text)
import Prelude(Show)

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

data Settings =
  Settings {
    _uatEnabled :: Bool
  , _esEnabled :: Bool
  , _gpsEnabled :: Bool
  , _networkOutputs :: [NetworkConnection]
  , _ahrsEnabled :: Bool
  , _debug :: Bool
  , _replayLog :: Bool
  , _ppm :: Int
  , _ownshipModeS :: String
  , _watchList :: String
  } deriving (Eq, Ord, Show)

makeClassy ''Settings

-- |
--
-- >>> decode "{\"UAT_Enabled\":true,\"ES_Enabled\":true,\"GPS_Enabled\":true,\"NetworkOutputs\":[{\"Conn\":null,\"Ip\":\"\",\"Port\":4000,\"Capability\":5,\"LastUnreachable\":\"0001-01-01T00:00:00Z\",\"SleepFlag\":false}],\"AHRS_Enabled\":false,\"DEBUG\":false,\"ReplayLog\":true,\"PPM\":0,\"OwnshipModeS\":\"F00000\",\"WatchList\":\"\"}" :: Maybe Settings
-- Just (Settings {_uatEnabled = True, _esEnabled = True, _gpsEnabled = True, _networkOutputs = [NetworkConnection {_conn = Nothing, _ip = "", _port = 4000, _capability = 5, _lastUnreachable = 0001-01-01 00:00:00 UTC, _sleepFlag = False}], _ahrsEnabled = False, _debug = False, _replayLog = True, _ppm = 0, _ownshipModeS = "F00000", _watchList = ""})
instance FromJSON Settings where
  parseJSON =
    withObject "Settings" (\x ->
      Settings <$>
        x .: "UAT_Enabled" <*>
        x .: "ES_Enabled" <*>
        x .: "GPS_Enabled" <*>
        x .: "NetworkOutputs" <*>
        x .: "AHRS_Enabled" <*>
        x .: "DEBUG" <*>
        x .: "ReplayLog" <*>
        x .: "PPM" <*>
        x .: "OwnshipModeS" <*>
        x .: "WatchList"
        )

-- |
--
-- >>> encode (Settings True True True [NetworkConnection Nothing "" 4000 5 (UTCTime (fromGregorian 1 1 1) 597) False] False False True 0 "F00000" "")
-- "{\"OwnshipModeS\":\"F00000\",\"AHRS_Enabled\":false,\"NetworkOutputs\":[{\"Ip\":\"\",\"Conn\":null,\"Capability\":5,\"SleepFlag\":false,\"LastUnreachable\":\"0001-01-01T00:09:57Z\",\"Port\":4000}],\"PPM\":0,\"GPS_Enabled\":true,\"DEBUG\":false,\"ES_Enabled\":true,\"ReplayLog\":true,\"UAT_Enabled\":true,\"WatchList\":\"\"}"
instance ToJSON Settings where
  toJSON (Settings uatEnabled_ esEnabled_ gpsEnabled_ networkOutputs_ ahrsEnabled_ debug_ replayLog_ ppm_ ownshipModeS_ watchList_) =
    object [
      "UAT_Enabled" .= uatEnabled_
    , "ES_Enabled" .= esEnabled_
    , "GPS_Enabled" .= gpsEnabled_
    , "NetworkOutputs" .= networkOutputs_
    , "AHRS_Enabled" .= ahrsEnabled_
    , "DEBUG" .= debug_
    , "ReplayLog" .= replayLog_
    , "PPM" .= ppm_
    , "OwnshipModeS" .= ownshipModeS_
    , "WatchList" .= watchList_
    ]

data SettingsSet =
  SettingsSet {
    _uatEnabled_ :: Maybe Bool
  , _esEnabled_ :: Maybe Bool
  , _gpsEnabled_ :: Maybe Bool
  , _networkOutputs_ :: Maybe [NetworkConnection]
  , _ahrsEnabled_ :: Maybe Bool
  , _debug_ :: Maybe Bool
  , _replayLog_ :: Maybe Bool
  , _ppm_ :: Maybe Int
  , _ownshipModeS_ :: Maybe String
  , _watchList_ :: Maybe String
  } deriving (Eq, Ord, Show)

makeClassy ''SettingsSet

class AsSettings a where
  _Settings ::
    Prism'
      a
      Settings

instance AsSettings Settings where
  _Settings =
    id

instance AsSettings SettingsSet where
  _Settings =
    prism'
      (\(Settings _uatEnabled_ _esEnabled_ _gpsEnabled_ _networkOutputs_ _ahrsEnabled_ _debug_ _replayLog_ _ppm_ _ownshipModeS_ _watchList_) ->
        SettingsSet
          (Just _uatEnabled_)
          (Just _esEnabled_)
          (Just _gpsEnabled_)
          (Just _networkOutputs_)
          (Just _ahrsEnabled_)
          (Just _debug_)
          (Just _replayLog_)
          (Just _ppm_)
          (Just _ownshipModeS_)
          (Just _watchList_)
      )
      (\(SettingsSet _uatEnabled_ _esEnabled_ _gpsEnabled_ _networkOutputs_ _ahrsEnabled_ _debug_ _replayLog_ _ppm_ _ownshipModeS_ _watchList_) ->
        Settings <$>
          _uatEnabled_ <*>
          _esEnabled_ <*>
          _gpsEnabled_ <*>
          _networkOutputs_ <*>
          _ahrsEnabled_ <*>
          _debug_ <*>
          _replayLog_ <*>
          _ppm_ <*>
          _ownshipModeS_ <*>
          _watchList_
      )

emptySettingsSet ::
  SettingsSet
emptySettingsSet =
  SettingsSet
    Nothing
    Nothing
    Nothing
    Nothing
    Nothing
    Nothing
    Nothing
    Nothing
    Nothing
    Nothing

-- |
--
-- >>> decode "{\"UAT_Enabled\":true,\"ES_Enabled\":true,\"GPS_Enabled\":true,\"NetworkOutputs\":[{\"Conn\":null,\"Ip\":\"\",\"Port\":4000,\"Capability\":5,\"LastUnreachable\":\"0001-01-01T00:00:00Z\",\"SleepFlag\":false}],\"AHRS_Enabled\":false,\"DEBUG\":false,\"ReplayLog\":true,\"PPM\":0,\"OwnshipModeS\":\"F00000\",\"WatchList\":\"\"}" :: Maybe SettingsSet
-- Just (SettingsSet {_uatEnabled_ = Just True, _esEnabled_ = Just True, _gpsEnabled_ = Just True, _networkOutputs_ = Just [NetworkConnection {_conn = Nothing, _ip = "", _port = 4000, _capability = 5, _lastUnreachable = 0001-01-01 00:00:00 UTC, _sleepFlag = False}], _ahrsEnabled_ = Just False, _debug_ = Just False, _replayLog_ = Just True, _ppm_ = Just 0, _ownshipModeS_ = Just "F00000", _watchList_ = Just ""})
--
-- >>> decode "{\"ES_Enabled\":true,\"GPS_Enabled\":true,\"NetworkOutputs\":[{\"Conn\":null,\"Ip\":\"\",\"Port\":4000,\"Capability\":5,\"LastUnreachable\":\"0001-01-01T00:00:00Z\",\"SleepFlag\":false}],\"AHRS_Enabled\":false,\"DEBUG\":false,\"ReplayLog\":true,\"PPM\":0,\"OwnshipModeS\":\"F00000\",\"WatchList\":\"\"}" :: Maybe SettingsSet
-- Just (SettingsSet {_uatEnabled_ = Nothing, _esEnabled_ = Just True, _gpsEnabled_ = Just True, _networkOutputs_ = Just [NetworkConnection {_conn = Nothing, _ip = "", _port = 4000, _capability = 5, _lastUnreachable = 0001-01-01 00:00:00 UTC, _sleepFlag = False}], _ahrsEnabled_ = Just False, _debug_ = Just False, _replayLog_ = Just True, _ppm_ = Just 0, _ownshipModeS_ = Just "F00000", _watchList_ = Just ""})
--
-- >>> decode "{\"ES_Enabled\":true,\"NetworkOutputs\":[{\"Conn\":null,\"Ip\":\"\",\"Port\":4000,\"Capability\":5,\"LastUnreachable\":\"0001-01-01T00:00:00Z\",\"SleepFlag\":false}],\"AHRS_Enabled\":false,\"DEBUG\":false,\"OwnshipModeS\":\"F00000\",\"WatchList\":\"\"}" :: Maybe SettingsSet
-- Just (SettingsSet {_uatEnabled_ = Nothing, _esEnabled_ = Just True, _gpsEnabled_ = Nothing, _networkOutputs_ = Just [NetworkConnection {_conn = Nothing, _ip = "", _port = 4000, _capability = 5, _lastUnreachable = 0001-01-01 00:00:00 UTC, _sleepFlag = False}], _ahrsEnabled_ = Just False, _debug_ = Just False, _replayLog_ = Nothing, _ppm_ = Nothing, _ownshipModeS_ = Just "F00000", _watchList_ = Just ""})
instance FromJSON SettingsSet where
  parseJSON =
    withObject "SettingsSet" (\x ->
      SettingsSet <$>
        x .:? "UAT_Enabled" <*>
        x .:? "ES_Enabled" <*>
        x .:? "GPS_Enabled" <*>
        x .:? "NetworkOutputs" <*>
        x .:? "AHRS_Enabled" <*>
        x .:? "DEBUG" <*>
        x .:? "ReplayLog" <*>
        x .:? "PPM" <*>
        x .:? "OwnshipModeS" <*>
        x .:? "WatchList"
        )

-- |
--
-- >>> encode (SettingsSet (Just True) (Just True) (Just True) (Just [(NetworkConnection Nothing "" 4000 5 (UTCTime (fromGregorian 1 1 1) 597) False)]) (Just False) (Just False) (Just True) (Just 0) (Just "F00000") (Just ""))
-- "{\"OwnshipModeS\":\"F00000\",\"AHRS_Enabled\":false,\"NetworkOutputs\":[{\"Ip\":\"\",\"Conn\":null,\"Capability\":5,\"SleepFlag\":false,\"LastUnreachable\":\"0001-01-01T00:09:57Z\",\"Port\":4000}],\"PPM\":0,\"GPS_Enabled\":true,\"DEBUG\":false,\"ES_Enabled\":true,\"ReplayLog\":true,\"UAT_Enabled\":true,\"WatchList\":\"\"}"
--
-- >>> encode (SettingsSet Nothing (Just True) (Just True) (Just [(NetworkConnection Nothing "" 4000 5 (UTCTime (fromGregorian 1 1 1) 597) False)]) (Just False) (Just False) (Just True) (Just 0) (Just "F00000") (Just ""))
-- "{\"OwnshipModeS\":\"F00000\",\"AHRS_Enabled\":false,\"NetworkOutputs\":[{\"Ip\":\"\",\"Conn\":null,\"Capability\":5,\"SleepFlag\":false,\"LastUnreachable\":\"0001-01-01T00:09:57Z\",\"Port\":4000}],\"PPM\":0,\"GPS_Enabled\":true,\"DEBUG\":false,\"ES_Enabled\":true,\"ReplayLog\":true,\"WatchList\":\"\"}"
--
-- >>> encode (SettingsSet Nothing (Just True) Nothing (Just [(NetworkConnection Nothing "" 4000 5 (UTCTime (fromGregorian 1 1 1) 597) False)]) (Just False) (Just False) Nothing Nothing (Just "F00000") (Just ""))
-- "{\"OwnshipModeS\":\"F00000\",\"AHRS_Enabled\":false,\"NetworkOutputs\":[{\"Ip\":\"\",\"Conn\":null,\"Capability\":5,\"SleepFlag\":false,\"LastUnreachable\":\"0001-01-01T00:09:57Z\",\"Port\":4000}],\"DEBUG\":false,\"ES_Enabled\":true,\"WatchList\":\"\"}"
instance ToJSON SettingsSet where
  toJSON (SettingsSet uatEnabled__ esEnabled__ gpsEnabled__ networkOutputs__ ahrsEnabled__ debug__ replayLog__ ppm__ ownshipModeS__ watchList__) =
      let (.=?) ::
            (ToJSON v, KeyValue kv) =>
            Text
            -> Maybe v
            -> Maybe kv
          (.=?) =
            (<$>) . (.=)
      in  object . catMaybes $
            [
              "UAT_Enabled" .=? uatEnabled__
            , "ES_Enabled" .=? esEnabled__
            , "GPS_Enabled" .=? gpsEnabled__
            , "NetworkOutputs" .=? networkOutputs__
            , "AHRS_Enabled" .=? ahrsEnabled__
            , "DEBUG" .=? debug__
            , "ReplayLog" .=? replayLog__
            , "PPM" .=? ppm__
            , "OwnshipModeS" .=? ownshipModeS__
            , "WatchList" .=? watchList__
            ]