{-- TerraHS - Interface between TerraLib and Haskell

    (c) Sergio Costa (INPE) - Setembro, 2005

	This program is free software; you can redistribute it 
    and/or modify it under the terms of the GNU General 
    Public License 2.1 as published by the Free Software Foundation
    (http://www.opensource.org/licenses/gpl-license.php)
--}


{- | A module for supporting a TeLine2D TerraLib class

TeLine2D: Supports a simple 2D line,  composed of 2D xy points.

More information - <http://www.terralib.org>-}
module TerraHS.TerraLib.TeLine2D
	(
		-- * The @TeLine2D@ type
		TeLine2D (..),
		
		-- * The @TeLine2DPtr@ type
		TeLine2DPtr,

		-- * The @TeLinearRing@ type
		TeLinearRing,
		
		-- * The @TeLineSet@ type
		TeLineSet (..),
		
		-- * The @TeLineSetPtr@ type
		TeLineSetPtr		
	)
	 where 

import Foreign (Int32)
import Foreign.C.String
import qualified Foreign.Ptr (Ptr)

import TerraHS.TerraLib.TePoint
import TerraHS.TerraLib.TeCoord2D

import TerraHS.Algebras.Base.Object
import TerraHS.Misc.GenericFunctions

import TerraHS.Algebras.Spatial.Lines

-- | The type  @TeLine2D@ represents a simple 2D line,  composed of 2D xy points 
data TeLine2D = TeLine2D [TeCoord2D] deriving (Eq,Show,Ord)

-- | The type @TeLine2DPtr@ is a pointer to @TeLine2D@
type TeLine2DPtr = Foreign.Ptr.Ptr TeLine2D

-- | The type @TeLineSet@ is a set of a simple 2D line
data TeLineSet = TeLineSet [TeLine2D] 

-- | The type @TeLineSetPtr@ is a pointer to @TeLineSet@
type TeLineSetPtr = Foreign.Ptr.Ptr TeLineSet

-- | The type @TeLinearRing @ is a synonymous to @TeLine2D@
type TeLinearRing = TeLine2D

lineId :: TeLine2DPtr -> String -> IO ()
lineId ptr str = newCString str >>= (teline2d_setobid ptr) >>= return

instance Pointer TeLine2D where

	new (TeLine2D coords) = teline2d_new >>= \line  ->  doall (map ( (addPoint line) ) ( points )) >> return line
		where
		points = map TePoint coords
		addPoint l p =  new p >>= \p -> (teline2d_addtepoint l p) >> delete p
	
	delete ptr = (teline2d_destroy ptr)

	fromPointer ptr = teline2d_size ptr >>= \s -> teline2line ptr 0 s >>= \ps -> return (TeLine2D ps)
		where
		teline2line l i size = do
		if i >= size then return [] else (teline2d_gettepoint l i) >>= fromPointer >>= \(TePoint (x,y)) -> (teline2line l (i+1) size) >>= \xs -> return  ((x,y) : xs)

		
instance Pointer TeLineSet where
	new (TeLineSet []) = telineset_new
	new (TeLineSet xs) = do
		ptr <- new (TeLineSet [])
		addLines ptr xs 0
		return ptr
		where
		addLines ptr [] _ = error "there are any lines"
		addLines ptr [x] i = new x >>= \l  -> lineId l (show i) >> (telineset_addteline ptr l)
		addLines ptr (x:xs) i = new x >>= \l  -> lineId l (show i) >> (telineset_addteline ptr l) >> (addLines ptr xs (i+1))


	delete ptr = (telineset_destroy ptr)

instance Element TeLineSet TeLine2D where

	getElement ptr i = telineset_getteline2d ptr i >>= fromPointer >>= return 
	
		
instance Size TeLineSet where

	size ptr = (telineset_size ptr)		
	

instance Lines TeLine2D Double where
	createLine cs = (TeLine2D cs )
	decompToCoords (TeLine2D cs) = cs
	
	
-- TeLine, TeLineSet----------------------------------------------------------------------------
foreign import stdcall unsafe "c_teline2d_new" teline2d_new :: Prelude.IO TeLine2DPtr
foreign import stdcall unsafe "c_teline2d_destroy" teline2d_destroy :: TeLine2DPtr -> Prelude.IO ()
foreign import stdcall unsafe "c_teline2d_addtepoint" teline2d_addtepoint :: TeLine2DPtr -> TePointPtr ->  Prelude.IO ()
foreign import stdcall unsafe "c_teline2d_size" teline2d_size :: TeLine2DPtr -> Prelude.IO Int32
foreign import stdcall unsafe "c_teline2d_gettepoint" teline2d_gettepoint :: TeLine2DPtr -> Int32 -> Prelude.IO TePointPtr
foreign import stdcall unsafe "c_telineset_new" telineset_new :: Prelude.IO TeLineSetPtr
foreign import stdcall unsafe "c_telineset_destroy" telineset_destroy :: TeLineSetPtr -> Prelude.IO ()
foreign import stdcall unsafe "c_telineset_size" telineset_size ::  TeLineSetPtr -> Prelude.IO Int32
foreign import stdcall unsafe "c_telineset_getteline2d" telineset_getteline2d :: TeLineSetPtr -> Int32 -> Prelude.IO TeLine2DPtr
foreign import stdcall unsafe "c_telineset_addteline" telineset_addteline :: TeLineSetPtr -> TeLine2DPtr -> Prelude.IO ()
foreign import stdcall unsafe "c_teline2d_setobid" teline2d_setobid :: TeLine2DPtr -> CString -> Prelude.IO ()