module GIS.Hylo where
import Geometry.Shapefile.MergeShpDbf
import Geometry.Shapefile.ReadShp
import Geometry.Shapefile.Types
import Data.List
import Data.Char
import Data.Maybe
import Data.Monoid
import GIS.Math.Projections
import GIS.Math.Spherical
import GIS.Utils
import Control.Lens.Tuple
import Control.Lens
import Control.Monad
import GIS.Types
import GIS.Graphics.Types
import Data.Default
import System.Directory
districtArea :: [District] -> String
districtArea districts = concat . intercalate (pure "\n") $ map (pure . show . distA) districts
where distA (District _ label _ area _) = (label, sum area)
districtPerimeter :: [District] -> String
districtPerimeter districts = concat . intercalate (pure "\n") $ map (pure . show . distP) districts
where distP (District _ label perimeter _ _) = (label, perimeter)
districtCompactness :: [District] -> String
districtCompactness districts = concat . intercalate (pure "\n") $ map (pure . show . distC) districts
where distC (District _ label _ _ compacticity) = (label, compacticity)
districtToMapP :: Projection -> [District] -> Map
districtToMapP p = projectMap p . districtToMap
districtToMap :: [District] -> Map
districtToMap districts = labelledDistricts .~ dist $ def
where dist = gc $ zip (fmap _shape districts) (fmap _districtLabel districts)
gc = concatMap (\(a,b) -> zip a (replicate (length a) b))
districtToMapFilesP :: Projection -> [District] -> [Map]
districtToMapFilesP p = fmap (projectMap p) . districtToMapFiles
districtToMapFiles :: [District] -> [Map]
districtToMapFiles = map (\(District polygons label _ area _) -> title .~ label ++ "-" ++ (show . sum $ area) $ labelledDistricts .~ (zip polygons (nullLabel polygons)) $ def)
where nullLabel polys = map (const "") [1..(length polys)]
getDistricts :: FilePath -> IO [District]
getDistricts filepath = do
dbfExists <- doesFileExist (stripExt filepath <> ".dbf")
file <- if dbfExists then readShpWithDbf filepath else readShpFile filepath
let districtLabels = fromJust $ (fmap labels) $ mapM (shpRecLabel) . shpRecs $ file
let shapes = (map (getPolygon . fromJust . shpRecContents)) . shpRecs $ file
let perimeters = map (totalPerimeter . getPolygon . fromJust . shpRecContents) . shpRecs $ file
let areas = map (fmap areaPolygon . getPolygon . fromJust . shpRecContents) . shpRecs $ file
let compacticity = map (relativeCompactness . concat . getPolygon . fromJust . shpRecContents) . shpRecs $ file
pure $ zipWith5 (\a b c d e -> District a b c d e) shapes districtLabels perimeters areas compacticity
getPolygon :: RecContents -> [Polygon]
getPolygon (RecPolygon { recPolPoints = pt }) = pt
getPolygon (RecPolygonM { recPolMPoints = pt }) = pt
getPolygon (RecPolygonZ { recPolZPoints = pt }) = pt