{-# OPTIONS_GHC -fwarn-incomplete-patterns  #-}
{-# OPTIONS_GHC -fwarn-missing-methods      #-}     
{-# LANGUAGE DeriveDataTypeable             #-}
{-# LANGUAGE DeriveFunctor                  #-}
{-# LANGUAGE GeneralizedNewtypeDeriving     #-}
{-# LANGUAGE PatternGuards                  #-}
{-# LANGUAGE TemplateHaskell                #-} 

module Facts.Geography.Location ( DMS       (..)
                                , Elevation (..)
                                , Location  (..)
                                , Latitude  (..)
                                , Longitude (..)
                                ) where

import Data.Angle
import Data.Data
import Data.Typeable

import Facts.Utility.OrphanInstances


data DMS = DMS { degrees  ::  Double
               , minutes  ::  Double
               , seconds  ::  Double
               } deriving (Data, Eq, Ord, Show, Typeable)


data Length = Meters Double
            | Feet   Double
            deriving (Data, Eq, Ord, Show, Typeable)


newtype Latitude  = Latitude  (Degrees Double) deriving (Data, Eq, Ord, Show, Typeable)
newtype Longitude = Longitude (Degrees Double) deriving (Data, Eq, Ord, Show, Typeable)


-- | Elevation from sea level.
type Elevation = Length


data Location = Location { latitude  :: Latitude
                         , longitude :: Longitude
                         , elevation :: Maybe Elevation
                         } deriving (Data, Eq, Ord, Show, Typeable)



dms_to_degrees :: DMS -> Degrees Double
dms_to_degrees (DMS d m s) = Degrees (d + m / 60 + s / 3600)

dms_to_latitude  :: DMS -> Latitude
dms_to_longitude :: DMS -> Longitude
dms_to_latitude  = Latitude  . dms_to_degrees
dms_to_longitude = Longitude . dms_to_degrees

dms_lat_long_to_location_at_sea_level :: (DMS, DMS) -> Location
dms_lat_long_to_location_at_sea_level (lat, lon) = Location { latitude  = dms_to_latitude  $ lat
                                                            , longitude = dms_to_longitude $ lon
                                                            , elevation = Nothing
                                                            }