```module Data.Geometry.Polygon where

import Data.Geometry.BoundingBox
import Data.Geometry.Point
import Data.Geometry.Geometry

---------------------------------------------------------------------
-- | Polygons

-- | Class that defines what a polygon is. Note that it is assumed that the
-- first and the last point are *NOT* the same point.
--
class (HasPoints p, IsTransformable p) => IsPolygon p where
vertices :: p a -> [Point2' a]
vertices = points

-- | default implementation assumes points are in order
edges   :: p a -> [(Point2' a, Point2' a)]
edges p = let pts = points p in
zip pts (tail pts ++ [head pts])

isSimple      :: p a -> Bool
containsHoles :: p a -> Bool

---------------------------------------------------------------------
-- | Simple polygons, i.e. polygons consisting of a sequence of points (vertices)
-- | such that the edges do not intersect. Simple polygons do not contain holes
data SimplePolygon' a = SimplePolygon [Point2' a]
deriving (Show,Eq)

instance HasPoints SimplePolygon' where
points (SimplePolygon pts) = pts

instance IsPolygon SimplePolygon' where
isSimple      = const  True
containsHoles = const False

instance IsPoint2Functor SimplePolygon' where
p2fmap f (SimplePolygon pts) = SimplePolygon (map f pts)

---------------------------------------------------------------------
-- | A multipolygon consists of several simple polygons
data MultiPolygon' a = MultiPolygon [SimplePolygon' a]
deriving (Show,Eq)

instance HasPoints MultiPolygon' where
points (MultiPolygon pls) = concatMap points pls

instance IsPolygon MultiPolygon' where
isSimple                    = const False
containsHoles               = const False

instance IsPoint2Functor MultiPolygon' where
p2fmap f (MultiPolygon polys) = MultiPolygon (map (p2fmap f) polys)

---------------------------------------------------------------------
-- | Bounding boxes can be used as polygons
instance IsPolygon BoundingBox2' where
isSimple      = const True
containsHoles = const False
```