{-# LANGUAGE OverloadedStrings, TemplateHaskell #-}

module Ham.Internal.Data where

import Data.Aeson
import Data.Aeson.TH
import Data.List
import Data.Char (isDigit, digitToInt)

-- | Frequency in MHz.
newtype Frequency = MHz Float
                  deriving (Show, Read, Eq, Ord)


-- | Wavelength in metres.
wavelength :: Frequency -> Float
wavelength (MHz f) = c / (f * 1e6)
  where c = 299792458 -- m / s

-- | Commmon bands in meters.
bands = [160, 80, 60, 40, 30, 20, 17, 15, 12, 10, 6, 2, 1.25, 0.7, 0.33, 0.23]

band_name :: Float -> String
band_name a | (fromIntegral $ round a) == a = show (round a) <> "m"
            | a > 1.0 = show a <> "m"
            | otherwise = show (round $ a * 100) <> "cm"

data Band = M Float     -- ^ Band in metres
          | Microwave   -- ^ Anything 15% shorter than about 23cm.
          deriving Eq

instance Show Band where
  show (M b) = band_name b
  show Microwave = "Microwave"


-- | Find canonical band name for frequency.
band :: Frequency -> Band
band f = case m of
           (0.23, d) -> if (d / 0.23) > 0.15 then Microwave else M 0.23
           (a, _) -> M a
  where l = wavelength f
        diffs = map (\a -> (a, abs (l - a))) bands
        m = minimumBy (\a b -> compare (snd a) (snd b)) diffs



-- | Modes for a QSO.
-- TODO: This is following Cabrillo; this should go into the Cabrillo module and this type here should have many more entries.
data QsoMode = CW  -- ^ Morse code.
             | PH  -- ^ Voice.
             | FM  -- ^ FM voice.
             | RY  -- ^ RTTY or other teletype mode.
             | DATA
             deriving (Show, Read, Eq)


-- | RST report.
data RST = RST Int Int Int  -- ^ Readability, signal strength, tone.
         | RS Int Int       -- ^ Readability, signal strength
         | NoRST deriving (Eq, Ord)



rstReadability :: RST -> Int
rstReadability (RST r _ _) = r
rstReadability (RS r _)    = r
rstReadability _           = 0

rstStrength :: RST -> Int
rstStrength (RST _ s _) = s
rstStrength (RS _ s)    = s
rstStrength _           = 0

rstTone :: RST -> Int
rstTone (RST _ _ t) = t
rstTone (RS _ _)    = 0
rstTone _           = 0


instance Show RST where
    show (RST r s t) = show r ++ show s ++ show t
    show (RS r s)    = show r ++ show s
    show _           = ""

instance Read RST where
    readsPrec _ ss@(r:s:t:rest) = if Data.List.all isDigit (r:s:t:[]) then
                                    [(RST (digitToInt r) (digitToInt s) (digitToInt t), rest)] else
                                    [(NoRST, ss)]
    readsPrec _ ss@(r:s:rest)   = if Data.List.all isDigit (r:s:[]) then
                                    [(RS (digitToInt r) (digitToInt s), rest)] else
                                    [(NoRST, ss)]
    readsPrec _ ss              = [(NoRST, ss)]


$(deriveJSON defaultOptions ''Frequency)
$(deriveJSON defaultOptions ''RST)
$(deriveJSON defaultOptions ''QsoMode)