{-# LANGUAGE PackageImports, FlexibleContexts #-}
-- | Read and write vectors as ASCII text files.
--
--   The file format is like:
--
--   @
--	VECTOR			-- header
--	100			-- length of vector
--	1.23 1.56 1.23 ...	-- data, separated by whitespace
--	....
--   @
module Data.Array.Repa.IO.Vector
	( readVectorFromTextFile
	, writeVectorToTextFile)
where
import Data.Array.Repa				as A
import Data.Array.Repa.Repr.Unboxed             as A
import Data.Array.Repa.IO.Internals.Text
import Data.List				as L
import Prelude					as P
import System.IO
import Control.Monad
import Data.Char


-- | Read a vector from a text file.
--
--   * WARNING: This is implemented fairly naively, just using `Strings` 
--     under the covers. It will be slow for large data files.
-- 
--   * It also doesn't do graceful error handling.
--     If the file has the wrong format you'll get a confusing `error`.
--
readVectorFromTextFile
	:: (Num e, Read e, Unbox e)
	=> FilePath
	-> IO (Array U DIM1 e)	

readVectorFromTextFile fileName
 = do	handle		<- openFile fileName ReadMode
	
	"VECTOR"	<- hGetLine handle
	[len]		<- liftM (P.map readInt . words) $ hGetLine handle
	str		<- hGetContents handle
	let vals	= readValues str

	let dims	= Z :. len
	return $ fromListUnboxed dims vals


readInt :: String -> Int
readInt str
	| and $ P.map isDigit str
	= read str
	
	| otherwise
	= error "Data.Array.Repa.IO.Vector.readVectorFromTextFile parse error when reading data"
	
	
-- | Write a vector as a text file.
writeVectorToTextFile 
	:: (Show e, Source r e)
	=> Array r DIM1 e
	-> FilePath
	-> IO ()

writeVectorToTextFile arr fileName
 = do	file	<- openFile fileName WriteMode	

	hPutStrLn file "VECTOR"

	let Z :. len
		= extent arr

	hPutStrLn file 	$ show len
	hWriteValues file $ toList arr
	hClose file
	hFlush file