{-
	Copyright (C) 2018 Dr. Alistair Ward

	This file is part of BishBosh.

	BishBosh is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	BishBosh is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with BishBosh.  If not, see <http://www.gnu.org/licenses/>.
-}
{- |
 [@AUTHOR@]	Dr. Alistair Ward

 [@DESCRIPTION@]	Defines the result of a /game/.
-}

module BishBosh.Model.Result(
-- * Types
-- ** Data-types
	Result(
--		VictoryBy,
--		Draw
	),
-- * Constants
	range,
-- * Function
	findMaybeVictor,
-- ** Constructor
	mkResult,
-- ** Predicates
	isDraw
) where

import qualified	BishBosh.Attribute.LogicalColour	as Attribute.LogicalColour
import qualified	BishBosh.Property.Opposable		as Property.Opposable
import qualified	Control.DeepSeq
import qualified	Data.List.Extra

-- | The ways in which a game can legally be terminated.
data Result
	= VictoryBy Attribute.LogicalColour.LogicalColour	-- ^ The /logical colour/ of the victor.
	| Draw
	deriving Eq

instance Control.DeepSeq.NFData Result where
	rnf (VictoryBy logicalColour)		= Control.DeepSeq.rnf logicalColour
	rnf Draw				= ()

-- | Convert a game-termination reason into PGN's @Result@ field; <https://www.chessclub.com/user/help/pgn-spec>.
instance Show Result where
	showsPrec _ result	= (
		\(showsWhiteResult, showsBlackResult) -> showsWhiteResult . showChar '-' . showsBlackResult
	 ) $ case result of
		VictoryBy Attribute.LogicalColour.Black -> (lose, win)
		VictoryBy _				-> (win, lose)
		_					-> (draw, draw)
		where
			lose	= showChar '0'
			win	= showChar '1'
			draw	= showString "1/2"

instance Read Result where
	readsPrec _ s	= case Data.List.Extra.trimStart s of
		'0' : '-' : '1' : remainder				-> [(VictoryBy Attribute.LogicalColour.Black, remainder)]
		'1' : '-' : '0' : remainder				-> [(VictoryBy Attribute.LogicalColour.White, remainder)]
		'1' : '/' : '2' : '-' : '1' : '/' : '2' : remainder	-> [(Draw, remainder)]
		_							-> []	-- No Parse.

instance Property.Opposable.Opposable Result where
	getOpposite (VictoryBy logicalColour)	= VictoryBy $ Property.Opposable.getOpposite logicalColour
	getOpposite _				= Draw

-- | The constant range of values.
range :: [Result]
range	= Draw : map VictoryBy Attribute.LogicalColour.range

-- | Constructor.
mkResult :: Maybe Attribute.LogicalColour.LogicalColour -> Result
mkResult (Just logicalColour)	= VictoryBy logicalColour
mkResult _			= Draw

-- | Whether the game was drawn.
isDraw :: Result -> Bool
isDraw Draw	= True
isDraw _	= False

-- | Find any winner.
findMaybeVictor :: Result -> Maybe Attribute.LogicalColour.LogicalColour
findMaybeVictor (VictoryBy logicalColour)	= Just logicalColour
findMaybeVictor _				= Nothing