-- |
-- Module    : G500.Read
-- Copyright : (C) 2013 Parallel Scientific Labs, LLC.
-- License   : GPLv2
--
-- A module that reads files generated by Gen (graph500gen) program
-- one directory level above.
--
module G500.Read
    ( Graph500Reader
    , mkGraph500Reader
    ) where

import Control.Monad
import Data.Array.IO
import Data.Array.Unboxed
import Data.Word
import System.IO

import G500

-- |A synonym for IO action that performs a read.
type Graph500Reader = IO (Maybe (UArray Int Index))

-- |Create a graph reader structure.
-- The @handle@ should be opened to read as a binary file.
-- Also the handle gets captured in result of the function and will
-- be closed at the end of operation.
mkGraph500Reader :: Handle              -- ^ File handle.
                 -> Int                 -- ^ Size of a read.
                 -> IO Graph500Reader
mkGraph500Reader handle portionSize = do
	buf <- newArray (0,bytesCount-1) 0
	return $ graph500Reader handle buf
	where
		vertexSize = 8
		edgeSize = 2*vertexSize
		bytesCount = edgeSize*portionSize
		graph500Reader h buf = do
			eof <- hIsEOF h
			if eof then do
					hClose h
					return Nothing
				else readBatchPortion h buf
		readVertexIndex :: IOUArray Int Word8 -> Int -> IO Index
		readVertexIndex a i = do
			bytes <- forM [i*vertexSize..(i+1)*vertexSize-1] $ readArray a
			return $ foldr (\x j -> j*256 + fromIntegral x) 0 $ bytes
		readBatchPortion :: Handle -> IOUArray Int Word8 -> IO (Maybe (UArray Int Index))
		readBatchPortion h buf = do
			n <- hGetArray h buf bytesCount
			let edgesCount = n `div` edgeSize
			let indicesCount = edgesCount*2
			let maxIndex = indicesCount-1
			result <- (newArray (0,maxIndex) (0 :: Index)) :: IO (IOUArray Int Index)
			forM_ [0..indicesCount-1] $ \i -> do
				idx <- readVertexIndex buf i
				writeArray result i idx
			pairs <- freeze result
			return $ Just pairs