{-# LANGUAGE UnicodeSyntax, TypeSynonymInstances, ExistentialQuantification #-}
{-| This module defines the Soccer-Fun API that is concerned with teams.
	All available teams are collected in this module (allAvailableTeams).
-}
module SoccerFun.Team where

import SoccerFun.Player
import SoccerFun.Types
import SoccerFun.Geometry
import SoccerFun.Prelude
import Data.List ((\\), nub, sort)
import SoccerFun.Field

type Team = [Player] -- ^ the fielders are supposed to have different numbers, and all not equal to 1

validateTeam  Team  Team
validateTeam team = map validatePlayer team
	where
--	validatePlayer ∷ Player → Player
	validatePlayer (fb@Player{height=height})
		= fb {height = height `boundedBy` (minHeight,maxHeight)
			  , stamina = maxStamina
			  , health = maxHealth
		  }
replaceInTeam  [Player]  Team  Team
replaceInTeam fbs team = (team \\ fbs) ++ fbs

getTeam  ClubName  [Team]  Team
getTeam cn teams = case [team | team<-teams, nameOf team==cn] of
	(team:_)  team
	_  error ("Team " ++ show cn ++ " does not seem to exist.\n")

class Mirror a where mirror  Field  a  a

instance NameOf Team where
	nameOf players
		= case players of
			(fb:_)  nameOf (playerID fb)
			none  error "nameOf[Team]: applied to empty team.\n"

isValidTeam  Team  Bool
isValidTeam team = length clubNames == 1
							&&
						  (null keepers || isValidKeeper (head keepers))
							&&
						  all isValidPlayer players
							&&
						  sort (map nrOf players) == sort (nub (map nrOf players))
							&&
						  not (elem 1 (map nrOf fielders))
	where
	(keepers,fielders) = spanfilter isKeeper team
	clubNames = nub (map clubOf players)
	clubName' = head clubNames  String
	players = keepers ++ fielders
	clubOf fb = clubName (playerID fb)
	nrOf fb = playerNo (playerID fb)
	isValidKeeper fb = (playerID fb) == PlayerID {clubName=clubName',playerNo=1}
	isValidPlayer fb = clubOf fb == clubName'

instance Other ATeam where
	other Team1 = Team2
	other Team2 = Team1

instance Mirror a  Mirror [a] where mirror field as = map (mirror field) as
instance Mirror Player where mirror field fb = fb {pos = mirror field (pos fb)
                                                              , nose = mirror field (nose fb)
                                                              , speed = mirror field (speed fb)
                                                          }
instance Mirror Position where mirror field pos = Position {px = (flength field) - (px pos)
                                                          ,py = (fwidth field) - (py pos)
                                                          }
instance Mirror Speed where mirror field speed = speed {direction = mirror field (direction speed)}
instance Mirror Angle where mirror field angle = if (angle >= pi) then (3.0*pi - angle) else (pi - angle)