module Utils where
import Data.Array
import qualified Data.Heap as H
import Data.List
import Data.Maybe

{-
Generic and self-explanatory utility functions
-}

toZeroIndexedArray :: [Float] -> Array Int Float

toZeroIndexedArray x = listArray (0, (length x)-1) x

-- Copied from somewhere in Stackoverflow

arrZipWith :: Ix i => (a -> b -> c) -> Array i a -> Array i b -> Array i c

arrZipWith f a b
    | bounds a == bounds b = listArray (bounds a) (zipWith f (elems a) (elems b))
    | otherwise            = error "array bounds do not agree"

-- Copied from somewhere in Stackoverflow

subArrayList :: Int -> Int -> Array Int a -> [a]

subArrayList i j a = map (a!) [i..j]


rollingWindow ::  Int -> [Float] -> [[Float]]

rollingWindow m = foldr (zipWith (:)) (repeat []) . take m . tails

-- Copied from Control.Parallel.Strategies

chunk :: Int -> [a] -> [[a]]

chunk _ [] = []

chunk n xs = as : chunk n bs where (as,bs) = splitAt n xs


readFloat :: String -> Float

readFloat = read


getFloats :: String -> IO [Float]

getFloats filename = fmap ((map readFloat) . lines) (readFile filename)


modifyBottomKDistances :: Int -> Float -> H.MaxHeap Float -> H.MaxHeap Float

modifyBottomKDistances k dist bottomDistances
    | (H.size bottomDistances < k)                                      = H.insert dist bottomDistances
    | let maxDist = fromJust (H.viewHead bottomDistances) in dist <= maxDist = H.insert dist (H.drop 1 bottomDistances)
    | otherwise = bottomDistances
{-
Selection algorithm - linear for small k
-}

getKPartition :: Int -> [Float] -> Float

getKPartition k m = fromJust (H.viewHead (foldr (modifyBottomKDistances (k)) H.empty m))
