{-# LANGUAGE TypeFamilies, FlexibleContexts, TypeOperators #-}

-- Infamous company datatype

module Company
where

import Data.Generics.IG.Representable

data Company  = C [Dept]                deriving Show
data Dept     = D Name Manager [CUnit]  deriving Show
data CUnit    = PU Employee | DU Dept   deriving Show
data Employee = E Person Salary         deriving Show
data Person   = P Name Address          deriving Show
data Salary   = S Float                 deriving Show
type Manager  = Employee
type Name     = String
type Address  = String

instance Representable Company where
  type Repr Company = [Dept]
  toRepr (C ds) = ds
  fromRepr ds   = C ds

instance Representable Dept where
  type Repr Dept = Name :*: Manager :*: [CUnit]
  toRepr (D n m us)         = n :*: m :*: us
  fromRepr (n :*: m :*: us) = D n m us

instance Representable CUnit where
  type Repr CUnit = Employee :+: Dept
  toRepr (PU e) = Inl e
  toRepr (DU d) = Inr d
  fromRepr (Inl e) = PU e
  fromRepr (Inr d) = DU d

instance Representable Employee where
  type Repr Employee = Person :*: Salary
  toRepr (E n a)     = n :*: a
  fromRepr (n :*: a) = E n a

instance Representable Person where
  type Repr Person = Name :*: Address
  toRepr (P p s)     = p :*: s
  fromRepr (p :*: s) = P p s

instance Representable Salary where
  type Repr Salary = Float
  toRepr (S f) = f
  fromRepr f   = S f


-- Test data
--

-- An illustrative company
genCom :: Company
genCom = C [D "Research" laemmel [PU joost, PU marlow],
            D "Strategy" blair   []]

-- A typo for the sake of testing equality;
-- (cf. lammel vs. laemmel)
genCom' :: Company
genCom' = C [D "Research" lammel [PU joost, PU marlow],
             D "Strategy" blair   []]

genCom'' :: Company
genCom'' = C [D "Research" laemmel [PU joost, PU marlow]]

lammel, laemmel, joost, blair :: Employee
lammel  = E (P "Lammel" "Amsterdam") (S 8000)
laemmel = E (P "Laemmel" "Amsterdam") (S 8000)
joost   = E (P "Joost"   "Amsterdam") (S 1000)
marlow  = E (P "Marlow"  "Cambridge") (S 2000)
blair   = E (P "Blair"   "London")    (S 100000)

-- Some more test data
person1 = P "Lazy" "Home"
dept1   = D "Useless" (E person1 undefined) []

