{-|
Module      : Diplomacy.OrderObject
Description : Definition of OrderObject, which describes what a Subject is to do.
Copyright   : (c) Alexander Vieth, 2015
Licence     : BSD3
Maintainer  : aovieth@gmail.com
Stability   : experimental
Portability : non-portable (GHC only)
-}

{-# LANGUAGE AutoDeriveTypeable #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE StandaloneDeriving #-}

module Diplomacy.OrderObject (

    OrderObject(..)
  , orderObjectEqual

  , SomeOrderObject(..)

  , moveTarget
  , supportedSubject
  , supportTarget
  , convoySubject
  , convoyTarget
  , withdrawTarget

  ) where

import Diplomacy.Phase
import Diplomacy.Subject
import Diplomacy.OrderType
import Diplomacy.Province

-- | The objective of an order. Together with an Subject and a GreatPower,
--   this makes a complete order.
data OrderObject (phase :: Phase) (order :: OrderType) where

    MoveObject :: ProvinceTarget -> OrderObject Typical Move
    SupportObject
        :: Subject
        -> ProvinceTarget
        -> OrderObject Typical Support
    ConvoyObject
        -- TODO later, would be cool if we could use type system extensions
        -- to eliminate bogus convoys like convoys of fleets or convoys from/to
        -- water provinces.
        :: Subject
        -> ProvinceTarget
        -> OrderObject Typical Convoy

    WithdrawObject :: ProvinceTarget -> OrderObject Retreat Withdraw
    SurrenderObject :: OrderObject Retreat Surrender

    DisbandObject :: OrderObject Adjust Disband
    BuildObject :: OrderObject Adjust Build
    ContinueObject :: OrderObject Adjust Continue
    -- This is convenient because with it, every unit always has an
    -- order in every phase.

deriving instance Eq (OrderObject phase order)
deriving instance Show (OrderObject phase order)

instance Ord (OrderObject phase order) where
    x `compare` y = case (x, y) of
        (MoveObject pt, MoveObject pt') -> pt `compare` pt'
        (SupportObject subj pt, SupportObject subj' pt') -> (subj, pt) `compare` (subj, pt')
        (ConvoyObject subj pt, ConvoyObject subj' pt') -> (subj, pt) `compare` (subj', pt')
        (SurrenderObject, SurrenderObject) -> EQ
        (WithdrawObject pt, WithdrawObject pt') -> pt `compare` pt'
        (DisbandObject, DisbandObject) -> EQ
        (BuildObject, BuildObject) -> EQ
        (ContinueObject, ContinueObject) -> EQ

orderObjectEqual :: OrderObject phase order -> OrderObject phase' order' -> Bool
orderObjectEqual object1 object2 = case (object1, object2) of
    (MoveObject pt1, MoveObject pt2) -> pt1 == pt2
    (SupportObject subj1 pt1, SupportObject subj2 pt2) -> (subj1, pt1) == (subj2, pt2)
    (ConvoyObject subj1 pt1, ConvoyObject subj2 pt2) -> (subj1, pt1) == (subj2, pt2)
    (WithdrawObject pt1, WithdrawObject pt2) -> pt1 == pt2
    (SurrenderObject, SurrenderObject) -> True
    (DisbandObject, DisbandObject) -> True
    (BuildObject, BuildObject) -> True
    (ContinueObject, ContinueObject) -> True
    _ -> False

moveTarget :: OrderObject Typical Move -> ProvinceTarget
moveTarget (MoveObject x) = x

supportedSubject :: OrderObject Typical Support -> Subject
supportedSubject (SupportObject x _) = x

supportTarget :: OrderObject Typical Support -> ProvinceTarget
supportTarget (SupportObject _ x) = x

convoySubject :: OrderObject Typical Convoy -> Subject
convoySubject (ConvoyObject x _) = x

convoyTarget :: OrderObject Typical Convoy -> ProvinceTarget
convoyTarget (ConvoyObject _ x) = x

withdrawTarget :: OrderObject Retreat Withdraw -> ProvinceTarget
withdrawTarget (WithdrawObject x) = x

data SomeOrderObject phase where
    SomeOrderObject :: OrderObject phase order -> SomeOrderObject phase

deriving instance Show (SomeOrderObject phase)

{-
instance Eq (SomeOrderObject phase) where
    (SomeOrderObject x) == (SomeOrderObject y) = case (x, y) of
        (MoveObject _, MoveObject _) -> x == y
        (SupportObject _ _, SupportObject _ _) -> x == y
        (ConvoyObject _ _, ConvoyObject _ _) -> x == y
        (SurrenderObject, SurrenderObject) -> x == y
        (WithdrawObject _, WithdrawObject _) -> x == y
        (DisbandObject, DisbandObject) -> x == y
        (BuildObject, BuildObject) -> x == y
        (ContinueObject, ContinueObject) -> x == y
-}