{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances #-} -- | The @osm@ element of a OSM file, which is the root element. module Data.Geo.OSM.OSM ( OSM , osm , readOsmFile , readOsmFiles , interactOSMIO , interactsOSMIO , interactOSMIO' , interactsOSMIO' , interactOSM , interactsOSM , interactOSM' , interactsOSM' ) where import Prelude hiding (mapM, foldr) import Text.XML.HXT.Core import Control.Monad hiding (mapM) import Data.Foldable import Data.Traversable import Data.Geo.OSM.Children import Data.Geo.OSM.Bound import Data.Geo.OSM.Bounds import Data.Geo.OSM.BoundOption import Data.Lens.Common import Control.Comonad.Trans.Store import Data.Geo.OSM.Lens.VersionL import Data.Geo.OSM.Lens.GeneratorL import Data.Geo.OSM.Lens.BoundsL import Data.Geo.OSM.Lens.ChildrenL import Data.Monoid -- | The @osm@ element of a OSM file, which is the root element. data OSM = OSM String (Maybe String) (Maybe (Either Bound Bounds)) Children deriving Eq instance XmlPickler OSM where xpickle = xpElem "osm" (xpWrap (\(version', generator', bound', nwr') -> osm version' generator' bound' nwr', \(OSM version' generator' bound' nwr') -> (version', generator', bound', nwr')) (xp4Tuple (xpAttr "version" xpText) (xpOption (xpAttr "generator" xpText)) (xpOption (xpAlt (either (const 0) (const 1)) [xpWrap (Left, \(Left b) -> b) xpickle, xpWrap (Right, \(Right b) -> b) xpickle])) xpickle)) instance Show OSM where show = showPickled [] instance VersionL OSM String where versionL = Lens $ \(OSM version generator bounds children) -> store (\version -> OSM version generator bounds children) version instance BoundsL OSM where boundsL = Lens $ \(OSM version generator bounds children) -> store (\bounds -> OSM version generator (foldBoundOption (Just . Left) (Just . Right) Nothing bounds) children) $ case bounds of Nothing -> optionEmptyBound Just (Left b) -> optionBound b Just (Right b) -> optionBounds b instance GeneratorL OSM where generatorL = Lens $ \(OSM version generator bounds children) -> store (\generator -> OSM version generator bounds children) generator instance ChildrenL OSM where childrenL = Lens $ \(OSM version generator bounds children) -> store (\children -> OSM version generator bounds children) children -- | Constructs a osm with a version, bound or bounds, and node attributes and way or relation elements. osm :: String -- ^ The @version@ attribute. -> Maybe String -- ^ The @generator@ attribute. -> Maybe (Either Bound Bounds) -- ^ The @bound@ or @bounds@ elements. -> Children -- ^ The child elements. -> OSM osm = OSM -- | Reads an OSM file into a list of @OSM@ values removing whitespace. readOsmFile :: FilePath -> IO [OSM] readOsmFile = runX . xunpickleDocument (xpickle :: PU OSM) ([withRemoveWS yes, withFileMimeType v_1]) -- FIXME v_1? -- | Reads 0 or more OSM files into a list of @OSM@ values removing whitespace. readOsmFiles :: [FilePath] -> IO [OSM] readOsmFiles = fmap join . mapM readOsmFile -- | Reads a OSM file, executes the given function on the XML, then writes the given file. interactOSMIO' :: (OSM -> IO OSM) -- ^ The function to execute on the XML that is read. -> SysConfigList -- ^ The options for reading the OSM file. -> FilePath -- ^ The OSM file to read. -> SysConfigList -- ^ The options for writing the OSM file. -> FilePath -- ^ The OSM file to write. -> IO () interactOSMIO' f froma from toa to = runX (xunpickleDocument (xpickle :: PU OSM) froma from >>> arrIO f >>> xpickleDocument (xpickle :: PU OSM) toa to) >> return () -- | Reads a OSM file, executes the given functions on the XML, then writes the given file. interactsOSMIO' :: Foldable t => t (OSM -> IO OSM) -- ^ The function to execute on the XML that is read. -> SysConfigList -- ^ The options for reading the OSM file. -> FilePath -- ^ The OSM file to read. -> SysConfigList -- ^ The options for writing the OSM file. -> FilePath -- ^ The OSM file to write. -> IO () interactsOSMIO' = interactOSMIO' . sumM -- | Reads a OSM file removing whitespace, executes the given function on the XML, then writes the given file with indentation. interactOSMIO :: (OSM -> IO OSM) -- ^ The function to execute on the XML that is read. -> FilePath -- ^ The OSM file to read. -> FilePath -- ^ The OSM file to write. -> IO () interactOSMIO f from = interactOSMIO' f [withRemoveWS yes, withFileMimeType v_1] from [withIndent yes, withFileMimeType v_1] -- | Reads a OSM file removing whitespace, executes the given functions on the XML, then writes the given file with indentation. interactsOSMIO :: Foldable t => t (OSM -> IO OSM) -- ^ The function to execute on the XML that is read. -> FilePath -- ^ The OSM file to read. -> FilePath -- ^ The OSM file to write. -> IO () interactsOSMIO = interactOSMIO . sumM -- | Reads a OSM file, executes the given function on the XML, then writes the given file. interactOSM' :: (OSM -> OSM) -- ^ The function to execute on the XML that is read. -> SysConfigList -- ^ The options for reading the OSM file. -> FilePath -- ^ The OSM file to read. -> SysConfigList -- ^ The options for writing the OSM file. -> FilePath -- ^ The OSM file to write. -> IO () interactOSM' f = interactOSMIO' (return . f) -- | Reads a OSM file, executes the given functions on the XML, then writes the given file. interactsOSM' :: Foldable t => t (OSM -> OSM) -- ^ The functions to execute on the XML that is read. -> SysConfigList -- ^ The options for reading the OSM file. -> FilePath -- ^ The OSM file to read. -> SysConfigList -- ^ The options for writing the OSM file. -> FilePath -- ^ The OSM file to write. -> IO () interactsOSM' = interactOSM' . sum' -- | Reads a OSM file removing whitespace, executes the given function on the XML, then writes the given file with indentation. interactOSM :: (OSM -> OSM) -- ^ The function to execute on the XML that is read. -> FilePath -- ^ The OSM file to read. -> FilePath -- ^ The OSM file to write. -> IO () interactOSM f = interactOSMIO (return . f) -- | Reads a OSM file removing whitespace, executes the given functions on the XML, then writes the given file with indentation. interactsOSM :: Foldable t => t (OSM -> OSM) -- ^ The function to execute on the XML that is read. -> FilePath -- ^ The OSM file to read. -> FilePath -- ^ The OSM file to write. -> IO () interactsOSM = interactOSM . sum' -- not exported sum' :: Foldable t => t (a -> a) -> a -> a sum' = appEndo . foldMap Endo sumM :: (Monad m, Foldable t) => t (a -> m a) -> a -> m a sumM = foldr (>=>) return