{-# LANGUAGE OverloadedStrings, GeneralizedNewtypeDeriving #-}
{-# OPTIONS_HADDOCK hide #-}
module SecondTransfer.Utils (
    strToInt
    ,Word24
    ,word24ToInt
    ,putWord24be
    ,getWord24be
    -- ,getTimeDiff
    -- ,timeAsDouble 
    -- ,reportTimedEvent
    ,lowercaseText
    ,unfoldChannelAndSource
    ,stripString
    -- ,neutralizeUrl
    ,domainFromUrl
    -- ,hashFromUrl
    -- ,hashSafeFromUrl
    -- ,unSafeUrl

    -- ,SafeUrl
    ) where 


import           Control.Concurrent.Chan
import           Control.Monad.Trans.Class (lift)
-- import qualified Crypto.Hash.MD5           as MD5
import           Data.Binary               (Binary, get, put, putWord8)
import           Data.Binary.Get           (Get, getWord16be, getWord8)
import           Data.Binary.Put           (Put, putWord16be)
import           Data.Bits
import qualified Data.ByteString           as B
-- import qualified Data.ByteString.Base16    as B16
import           Data.ByteString.Char8     (pack, unpack)
-- import           Data.Hashable             (Hashable)
import           Data.Conduit
import qualified Data.Text                 as T
import           Data.Text.Encoding
import qualified Network.URI               as U
-- import qualified System.Clock              as SC
-- import           Text.Printf               (printf)
-- import qualified Text.Show.ByteString      as S(Show(..))



strToInt::String -> Int 
strToInt = fromIntegral . toInteger . (read::String->Integer)


newtype Word24 = Word24 Int
    deriving (Show)


-- Newtype to protect url usage
-- newtype SafeUrl = SafeUrl { unSafeUrl :: B.ByteString } deriving (Eq, Show, Hashable)



word24ToInt :: Word24 -> Int 
word24ToInt (Word24 w24) = w24


instance Binary Word24 where

    put (Word24 w24) = 
        do 
          let 
            high_stuff   = w24 `shiftR` 24 
            low_stuff    = w24 `mod`  (1 `shiftL` 24) 
          putWord8 $ fromIntegral high_stuff
          putWord16be $ fromIntegral low_stuff 

    get = do
      high_stuff <- getWord8 
      low_stuff  <- getWord16be
      let 
        value = (fromIntegral low_stuff) + ( (fromIntegral high_stuff) `shiftL` 24 ) 
      return $ Word24 value


getWord24be :: Get Int
getWord24be = do 
    w24 <- get
    return $ word24ToInt w24


putWord24be :: Int -> Put 
putWord24be x = put (Word24 x)


lowercaseText :: B.ByteString -> B.ByteString
lowercaseText bs0 = 
    encodeUtf8 ts1 
  where 
    ts1 = T.toLower ts0 
    ts0 = decodeUtf8 bs0


unfoldChannelAndSource :: IO (Chan (Maybe a), Source IO a)
unfoldChannelAndSource = do 
  chan <- newChan 
  let 
    source = do 
      e <- lift $ readChan chan
      case e of 
          Just ee -> do
              yield ee
              source 

          Nothing -> 
              return ()

  return (chan, source)


stripString :: String -> String 
stripString  = filter $ \ ch -> (ch /= '\n') && ( ch /= ' ')


-- neutralizeUrl :: B.ByteString -> B.ByteString
-- neutralizeUrl url = let 
--     Just (U.URI {- scheme -} _ authority u_path u_query u_frag) = U.parseURI $ unpack url
--     Just (U.URIAuth _ use_host _) = authority
--     complete_url  = U.URI {
--         U.uriScheme     = "snu:"
--         ,U.uriAuthority = Just $ U.URIAuth {
--             U.uriUserInfo = ""
--             ,U.uriRegName = use_host 
--             ,U.uriPort    = ""
--             }
--         ,U.uriPath      = u_path
--         ,U.uriQuery     = u_query 
--         ,U.uriFragment  = u_frag 
--       }
--   in 
--     pack $ show complete_url


domainFromUrl :: B.ByteString -> B.ByteString
domainFromUrl url = let 
    Just (U.URI {- scheme -} _ authority _ _ _) = U.parseURI $ unpack url
    Just (U.URIAuth _ use_host _) = authority
  in 
    pack use_host


-- hashFromUrl :: B.ByteString -> B.ByteString 
-- hashFromUrl url = 
--     B.take 10 . B16.encode . MD5.finalize $ foldl MD5.update MD5.init $  [urlHashSalt, neutralizeUrl url]


-- hashSafeFromUrl :: B.ByteString -> SafeUrl 
-- hashSafeFromUrl = SafeUrl . hashFromUrl