module Waldo.Story (
selectStory
, knapsackSizer
, Story(..)
, StoryGuard, StoryOption
, isIn, browserIs, osIs, netSpeedIs, orgIs, orgMatch, ispIs
, refererDomainIs
, pdTestJustIs
, giveThem, allocate
) where
import Data.Maybe
import Data.List
import Control.Monad.Reader
import Data.ByteString.Char8 (ByteString)
import qualified Data.Text as T
import Network.URI
import Text.Regex.TDFA ((=~))
import Waldo.Stalk
import Waldo.Script
type StoryGuard = ReaderT PersonalData Maybe ()
type StoryOption = ReaderT PersonalData Maybe Story
data Story =
StoryGoto {
storyGoto :: T.Text
}
| Story {
storyAltText :: T.Text
, storyPanelSets :: [PanelSizes]
, storyPadX :: Int
, storyPadY :: Int
, storyName :: T.Text
}
deriving (Show)
selectStory :: ((Int, Int) -> Story -> Maybe Script) -> Script -> [StoryOption] -> PersonalData -> IO Script
selectStory sizer d storyGens pd = do
let stories = catMaybes $ map (flip runReaderT pd) storyGens
let scripts = mapMaybe doSize stories
return $ fromMaybe d $ listToMaybe scripts
where
doSize (s@Story {}) = sizer (pdScreen pd) s
doSize (StoryGoto t) = Just (ScriptTo t)
knapsackSizer :: Int -> (Int, Int) -> Story -> Maybe Script
knapsackSizer sitePad (w, h) s =
listToMaybe $ (sortCorrectDir sizeLimited) ++ (take 1 areaSortedSized)
where
sortCorrectDir =
if (h > 0) && (w > 0)
then reverse
else id
sizeLimited = fitWidth $ fitHeight $ areaSortedSized
areaSortedSized = areaSort allScripts
allScripts = do
combo <- mapM id $ storyPanelSets s
return $ mkScript (storyName s) (storyAltText s) combo
areaSort = sortBy (\a b -> compare (scriptArea a) (scriptArea b))
scriptArea scr = (sHeight scr) * (sWidth scr)
fitHeight scripts =
if h > 0
then filter (\scr -> h > (sHeight scr+storyPadY s+sitePad)) scripts
else scripts
fitWidth scripts =
if w > 0
then filter (\scr -> w > (sWidth scr+storyPadX s+sitePad)) scripts
else scripts
refererDomainIs :: String -> StoryGuard
refererDomainIs d =
asks pdRefURI >>= guard . fromMaybe False . fmap ((isSuffixOf d) . uriRegName) . join . fmap uriAuthority
pdTestJustIs :: Eq a => (PersonalData -> Maybe a) -> a -> StoryGuard
pdTestJustIs g v = asks g >>= guard . maybe False (v==)
isIn :: ByteString -> StoryGuard
isIn locName = asks pdLocal >>= guard . (not . null . (filter (locName==)))
browserIs :: Browser -> StoryGuard
browserIs b = asks pdBrowser >>= guard . (maybe False (b==))
osIs :: OS -> StoryGuard
osIs os = asks pdOS >>= guard . (maybe False (os==))
netSpeedIs :: NetSpeed -> StoryGuard
netSpeedIs ns = asks pdNetSpeed >>= guard . (maybe False (ns==))
orgIs :: ByteString -> StoryGuard
orgIs o = asks pdOrg >>= guard . (maybe False (o==))
orgMatch :: ByteString -> StoryGuard
orgMatch o = asks pdOrg >>= guard . (maybe False (flip (=~) o))
ispIs :: ByteString -> StoryGuard
ispIs i = asks pdISP >>= guard . (maybe False (i==))
allocate :: MonadPlus m => m () -> a -> m a
allocate cnd r = cnd >> return r
giveThem :: MonadPlus m => m () -> m a -> m a
giveThem = (>>)