import List
import Data.Typeable

-- zobrazovani obecnych dat (nahrada za deriving Show)

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

genCom :: Company
genCom = C [D "Research" ralf [PU joost, PU marlow], D "Strategy" blair [DU (D "bla" blae [])]]
ralf, joost, marlow, blair, blae :: Employee
ralf = E (P "Ralf" "Amsterdam") (S 8000)
joost = E (P "Joost" "Amsterdam") (S 1000)
marlow = E (P "Marlow" "Cambridge") (S 2000)
blair = E (P "Blair" "London") (S 100000)
blae = E (P "Blae" "London") (S 100000)

data Constr = Constr {cName::String}

class Typeable a => Data a where
  gmapQ :: (forall b. Data b => b -> r) -> a -> [r]
  toConstr :: a -> Constr

instance Data Company where
  gmapQ f (C depts) = [f depts]
  toConstr _ = Constr {cName = "Company"}
instance Data Dept where
  gmapQ f (D name man subs) = [f name, f man, f subs]
  toConstr _ = Constr {cName = "Dept"}
instance Data SubUnit where
  gmapQ f (PU emp) = [f emp]
  gmapQ f (DU dept) = [f dept]
  toConstr (PU _) = Constr {cName = "PU"}
  toConstr (DU _) = Constr {cName = "DU"}
instance Data Employee where
  gmapQ f (E per sal) = [f per, f sal]
  toConstr _ = Constr {cName = "Employee"}
instance Data Person where
  gmapQ f (P n a) = [f n, f a]
  toConstr _ = Constr {cName = "Person"}
instance Data Salary where
  gmapQ f (S x) = [f x]
  toConstr _ = Constr {cName = "Salary"}

instance Data a => Data [a] where
  gmapQ f [] = []
  gmapQ f (x:xs) = [f x, f xs]
  toConstr _ = Constr {cName = "[]"}

instance Data Char where
  gmapQ _ _ = []
  toConstr x = Constr {cName = [x]}

instance Data Float where
  gmapQ _ _ = []
  toConstr x = Constr {cName = show x}

gShow::Data a => a -> String
gShow x = "(" ++ cName (toConstr x) ++ concat (intersperse " " ("" : gmapQ gShow x)) ++ ")"
