{-
	Copyright (C) 2021 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@]

	* Describes the directional components of a diagonal line.
-}

module BishBosh.Direction.Diagonal(
-- * Types
-- ** Data-types
	Diagonal()
) where

import			Control.Arrow((***))
import qualified	BishBosh.Direction.Horizontal		as Direction.Horizontal
import qualified	BishBosh.Direction.Vertical		as Direction.Vertical
import qualified	BishBosh.Property.FixedMembership	as Property.FixedMembership
import qualified	BishBosh.Property.Opposable		as Property.Opposable
import qualified	BishBosh.Property.Orientated		as Property.Orientated
import qualified	BishBosh.Property.Reflectable		as Property.Reflectable
import qualified	Control.DeepSeq
import qualified	Data.List.Extra

-- | Directions at 45 degress to all edges of the board; those in which a Bishop can move.
data Diagonal	= MkDiagonal {
	Diagonal -> Vertical
getVertical	:: Direction.Vertical.Vertical,		-- ^ The vertical component of the diagonal.
	Diagonal -> Horizontal
getHorizontal	:: Direction.Horizontal.Horizontal	-- ^ The horizontal component of the diagonal.
} deriving (Diagonal -> Diagonal -> Bool
(Diagonal -> Diagonal -> Bool)
-> (Diagonal -> Diagonal -> Bool) -> Eq Diagonal
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Diagonal -> Diagonal -> Bool
$c/= :: Diagonal -> Diagonal -> Bool
== :: Diagonal -> Diagonal -> Bool
$c== :: Diagonal -> Diagonal -> Bool
Eq, Eq Diagonal
Eq Diagonal
-> (Diagonal -> Diagonal -> Ordering)
-> (Diagonal -> Diagonal -> Bool)
-> (Diagonal -> Diagonal -> Bool)
-> (Diagonal -> Diagonal -> Bool)
-> (Diagonal -> Diagonal -> Bool)
-> (Diagonal -> Diagonal -> Diagonal)
-> (Diagonal -> Diagonal -> Diagonal)
-> Ord Diagonal
Diagonal -> Diagonal -> Bool
Diagonal -> Diagonal -> Ordering
Diagonal -> Diagonal -> Diagonal
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Diagonal -> Diagonal -> Diagonal
$cmin :: Diagonal -> Diagonal -> Diagonal
max :: Diagonal -> Diagonal -> Diagonal
$cmax :: Diagonal -> Diagonal -> Diagonal
>= :: Diagonal -> Diagonal -> Bool
$c>= :: Diagonal -> Diagonal -> Bool
> :: Diagonal -> Diagonal -> Bool
$c> :: Diagonal -> Diagonal -> Bool
<= :: Diagonal -> Diagonal -> Bool
$c<= :: Diagonal -> Diagonal -> Bool
< :: Diagonal -> Diagonal -> Bool
$c< :: Diagonal -> Diagonal -> Bool
compare :: Diagonal -> Diagonal -> Ordering
$ccompare :: Diagonal -> Diagonal -> Ordering
$cp1Ord :: Eq Diagonal
Ord)

instance Control.DeepSeq.NFData Diagonal where
	rnf :: Diagonal -> ()
rnf MkDiagonal {
		getVertical :: Diagonal -> Vertical
getVertical	= Vertical
_,
		getHorizontal :: Diagonal -> Horizontal
getHorizontal	= Horizontal
_
	} = ()

instance Enum Diagonal where
	fromEnum :: Diagonal -> Int
fromEnum MkDiagonal {
		getVertical :: Diagonal -> Vertical
getVertical	= Vertical
v,
		getHorizontal :: Diagonal -> Horizontal
getHorizontal	= Horizontal
h
	} = Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
Direction.Vertical.nVerticals Int -> Int -> Int
forall a. Num a => a -> a -> a
* Vertical -> Int
forall a. Enum a => a -> Int
fromEnum Vertical
v Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Horizontal -> Int
forall a. Enum a => a -> Int
fromEnum Horizontal
h

	toEnum :: Int -> Diagonal
toEnum Int
i	= (Vertical -> Horizontal -> Diagonal)
-> (Vertical, Horizontal) -> Diagonal
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Vertical -> Horizontal -> Diagonal
MkDiagonal ((Vertical, Horizontal) -> Diagonal)
-> ((Int, Int) -> (Vertical, Horizontal)) -> (Int, Int) -> Diagonal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Vertical
forall a. Enum a => Int -> a
toEnum (Int -> Vertical)
-> (Int -> Horizontal) -> (Int, Int) -> (Vertical, Horizontal)
forall (a :: * -> * -> *) b c b' c'.
Arrow a =>
a b c -> a b' c' -> a (b, b') (c, c')
*** Int -> Horizontal
forall a. Enum a => Int -> a
toEnum) ((Int, Int) -> Diagonal) -> (Int, Int) -> Diagonal
forall a b. (a -> b) -> a -> b
$! Int
i Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`divMod` Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
Direction.Vertical.nVerticals

instance Show Diagonal where
	showsPrec :: Int -> Diagonal -> ShowS
showsPrec Int
precedence MkDiagonal {
		getVertical :: Diagonal -> Vertical
getVertical	= Vertical
v,
		getHorizontal :: Diagonal -> Horizontal
getHorizontal	= Horizontal
h
	} = Int -> Vertical -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
precedence Vertical
v ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Horizontal -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
precedence Horizontal
h

instance Read Diagonal where
	readsPrec :: Int -> ReadS Diagonal
readsPrec Int
precedence String
s	= case Int -> ReadS Vertical
forall a. Read a => Int -> ReadS a
readsPrec Int
precedence ReadS Vertical -> ReadS Vertical
forall a b. (a -> b) -> a -> b
$ ShowS
Data.List.Extra.trimStart String
s of
		[(Vertical
vertical, String
s')]	-> case Int -> ReadS Horizontal
forall a. Read a => Int -> ReadS a
readsPrec Int
precedence String
s' of
			[(Horizontal
horizontal, String
s'')]	-> [
				(
					MkDiagonal :: Vertical -> Horizontal -> Diagonal
MkDiagonal {
						getVertical :: Vertical
getVertical	= Vertical
vertical,
						getHorizontal :: Horizontal
getHorizontal	= Horizontal
horizontal
					},
					String
s''
				) -- Pair.
			 ] -- Singleton.
			[(Horizontal, String)]
_			-> []	-- No parse.
		[(Vertical, String)]
_			-> []	-- No parse.

instance Property.FixedMembership.FixedMembership Diagonal where
	members :: [Diagonal]
members	= (Vertical -> Horizontal -> Diagonal)
-> [Vertical] -> [Horizontal -> Diagonal]
forall a b. (a -> b) -> [a] -> [b]
map Vertical -> Horizontal -> Diagonal
MkDiagonal [Vertical]
forall a. FixedMembership a => [a]
Property.FixedMembership.members {-vertical-} [Horizontal -> Diagonal] -> [Horizontal] -> [Diagonal]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Horizontal]
forall a. FixedMembership a => [a]
Property.FixedMembership.members {-horizontal-}

instance Property.Opposable.Opposable Diagonal where
	getOpposite :: Diagonal -> Diagonal
getOpposite MkDiagonal {
		getVertical :: Diagonal -> Vertical
getVertical	= Vertical
v,
		getHorizontal :: Diagonal -> Horizontal
getHorizontal	= Horizontal
h
	} = MkDiagonal :: Vertical -> Horizontal -> Diagonal
MkDiagonal {
		getVertical :: Vertical
getVertical	= Vertical -> Vertical
forall a. Opposable a => a -> a
Property.Opposable.getOpposite Vertical
v,
		getHorizontal :: Horizontal
getHorizontal	= Horizontal -> Horizontal
forall a. Opposable a => a -> a
Property.Opposable.getOpposite Horizontal
h
	}

instance Property.Orientated.Orientated Diagonal where
	isParallel :: Diagonal -> Bool
isParallel	= Bool -> Diagonal -> Bool
forall a b. a -> b -> a
const Bool
False
	isDiagonal :: Diagonal -> Bool
isDiagonal	= Bool -> Diagonal -> Bool
forall a b. a -> b -> a
const Bool
True
	isStraight :: Diagonal -> Bool
isStraight	= Bool -> Diagonal -> Bool
forall a b. a -> b -> a
const Bool
True

instance Property.Reflectable.ReflectableOnX Diagonal where
	reflectOnX :: Diagonal -> Diagonal
reflectOnX diagonal :: Diagonal
diagonal@MkDiagonal {
		getVertical :: Diagonal -> Vertical
getVertical	= Vertical
v
	} = Diagonal
diagonal {
		getVertical :: Vertical
getVertical	= Vertical -> Vertical
forall a. ReflectableOnX a => a -> a
Property.Reflectable.reflectOnX Vertical
v
	}

instance Property.Reflectable.ReflectableOnY Diagonal where
	reflectOnY :: Diagonal -> Diagonal
reflectOnY diagonal :: Diagonal
diagonal@MkDiagonal {
		getHorizontal :: Diagonal -> Horizontal
getHorizontal	= Horizontal
h
	} = Diagonal
diagonal {
		getHorizontal :: Horizontal
getHorizontal	= Horizontal -> Horizontal
forall a. ReflectableOnY a => a -> a
Property.Reflectable.reflectOnY Horizontal
h
	}