{-# LANGUAGE OverloadedStrings #-} module Utils ( generateDictionary , generateStarDict , renderId ) where import Control.Arrow (second) import Data.Monoid ((<>)) import Data.Text.Lazy.Builder as BT import Data.Traversable (mapAccumL) import NLP.Dictionary.StarDict.Common (IfoFile(..), IndexEntry, Renderer, DataEntry(..)) import NLP.Dictionary.StarDict.Common (renderIfoFile, renderIndexFile, putIndexNumber) import System.Directory (getTemporaryDirectory, createDirectoryIfMissing) import System.FilePath ((), (<.>)) import System.Random (getStdRandom, Random(..)) import qualified Data.ByteString.Lazy as BS import qualified Data.Set as Set import qualified Data.Text.Lazy as T import qualified Data.Text.Lazy.IO as T randomString :: Int -> IO String randomString n = mapM (const $ getStdRandom (randomR ('a', 'z'))) (replicate n ()) randomWord :: (Int, Int) -> IO T.Text randomWord wordSize = (getStdRandom $ randomR wordSize) >>= (fmap T.pack . randomString) randomText :: (Int, Int) -> (Int, Int) -> IO T.Text randomText textSize wordSize = fmap (("<<" <>) . (<> ">>")) $ (getStdRandom $ randomR textSize) >>= fmap (T.intercalate " ") . sequence . flip replicate (randomWord wordSize) generateDictionary :: Int -> (Int, Int) -> (Int, Int) -> IO [(T.Text, T.Text)] generateDictionary dictionarySize textSize wordSize = do ws <- fmap (Set.toList . Set.fromList) $ sequence $ replicate dictionarySize (randomWord wordSize) zip ws <$> (sequence $ replicate (length ws) (randomText textSize wordSize)) generateIndex :: [(T.Text, T.Text)] -> [IndexEntry] generateIndex = snd . mapAccumL generateIndexEntry 0 . map (second (fromIntegral . T.length)) where generateIndexEntry :: Int -> (T.Text, Int) -> (Int, IndexEntry) generateIndexEntry offset (name, size) = let offset' = offset + (fromIntegral . T.length $ name) in (offset' + size, (name, (offset', size))) generateStarDict :: [(T.Text, T.Text)] -> IO FilePath generateStarDict dictionary = do dictionaryName <- randomString 16 basePath <- () <$> getTemporaryDirectory <*> (pure dictionaryName) createDirectoryIfMissing True basePath let dictionaryPath = basePath dictionaryName <.> "dict" let dictionaryContents = BT.toLazyText . foldr1 (<>) . ((BT.fromLazyText ""):) . map (\(name, entry) -> BT.fromLazyText name <> BT.fromLazyText entry) $ dictionary T.writeFile dictionaryPath dictionaryContents let indexPath = basePath dictionaryName <.> "idx" let indexContents = renderIndexFile (generateIndex dictionary) (putIndexNumber Nothing) BS.writeFile indexPath indexContents let ifoPath = basePath dictionaryName <.> "ifo" let ifoFile = IfoFile { ifoMagicData = "StarDict's dict ifo file" , ifoVersion = "3.0.0" , ifoBookName = "Random Dictionary" , ifoWordCount = length dictionary , ifoIdxFileSize = fromIntegral . BS.length $ indexContents , ifoIdxOffsetBits = Nothing , ifoSynWordCount = Nothing , ifoAuthor = Nothing , ifoEmail = Nothing , ifoWebsite = Nothing , ifoDescription = Nothing , ifoDate = Nothing , ifoSameTypeSequence = Just "m" , ifoDictType = Nothing } T.writeFile ifoPath ((renderIfoFile ifoFile) <> "\n") return ifoPath renderId :: Renderer renderId (UTF8Text s) = s renderId _ = error "not implemented"