packages feed

apelsin-1.2: src/OnlineClans.hs

module OnlineClans (newOnlineClans) where
import Graphics.UI.Gtk

import Data.Monoid
import Data.Ord
import Data.Tree
import Data.List (sortBy)
import Control.Concurrent
import Network.Tremulous.NameInsensitive
import qualified Network.Tremulous.Protocol as P
import Network.Tremulous.Util
import qualified Data.ByteString.Char8 as B

import ClanFetcher
import Types
import Config
import GtkUtils
import GtkExts
import TremFormatting

newOnlineClans :: Bundle-> SetCurrent -> IO (ScrolledWindow, ClanPolledHook)
newOnlineClans Bundle{..} setServer = do
	Config {colors} <- readMVar mconfig

	gen@(GenSimple raw view) <- newGenSimple =<< treeStoreNew []

	addColumn gen "Name" True [cellTextEllipsize := EllipsizeEnd] $ \rend ->
		cellSetMarkup rend . showName colors
	addColumn gen "Server" True [cellTextEllipsize := EllipsizeEnd] $ \rend ->
		cellSetMarkup rend . showServer colors

	let updateF clans P.PollResult{..} = do
		let players = buildTree $ sortByPlayers $
			associatePlayerToClans (makePlayerNameList polled) clans
		treeStoreClear raw
		treeViewColumnsAutosize view
		mapM_ (treeStoreInsertTree raw [] 0) players
		treeViewExpandAll view

	on view cursorChanged $ do
		(path, _)	<- treeViewGetCursor view
		item		<- getElementPath gen path
		case item of
			Left _ -> return ()
			Right (_, gs) -> setServer False gs

	on view rowActivated $ \path _ -> do
		item		<- getElementPath gen path
		case item of
			Left _ -> return ()
			Right (_, gs) -> setServer True gs

	scroll <- scrollIt view PolicyAutomatic PolicyAutomatic

	return (scroll, updateF)
	where
	showName colors c =  case c of
		Left Clan{..}		-> B.concat ["<b>", htmlEscapeBS $ original name, "</b>"]
		Right (name, _)		-> pangoPrettyBS colors name

	showServer colors c =  case c of
		Left _ -> ""
		Right (_, P.GameServer{hostname}) -> pangoPrettyBS colors hostname


type PlayerList = [(TI, P.GameServer)]
type OnlineView = Forest (Either Clan (TI, P.GameServer))

associatePlayerToClans :: PlayerList -> [Clan] -> [(Clan, PlayerList)]
associatePlayerToClans players clans = map f clans
	where
	f c@Clan{tagexpr} = (c, filter (cmp tagexpr) players)
	cmp e = matchTagExpr e . fst

buildTree :: [(Clan, PlayerList)] -> OnlineView
buildTree = filter notEmpty . foldr f [] where
	f (clan, pls) xs = Node (Left clan) (map rightNode pls) : xs
	rightNode x = Node (Right x) []
	notEmpty (Node _ [])	= False
	notEmpty _		= True

sortByPlayers :: [(Clan, [b])] -> [(Clan, [b])]
sortByPlayers = sortBy $ comparing (length . snd) `mappend` flip (comparing (name . fst))