{- Exercise 5.1 -}
{- Cities, States and Countries -}
data City = Innsbruck | Munich | Graz | Gramais
data Country = Austria | Germany
data State = Tyrol | Bavaria | Styria

class Info a where
  population :: a -> Integer
  area :: a -> Integer

{- TODO: Make City, Country and State instances of Info -}
instance Info City where
  population = undefined
  area = undefined

instance Info Country where
  population = undefined
  area = undefined

instance Info State where
  population = undefined
  area = undefined

{- TODO: Define the following functions -}
inhabitantsPerSkm :: (Info a) => a -> Integer
inhabitantsPerSkm = undefined

hasMoreArea :: (Info a, Info b) => a -> b -> Bool
hasMoreArea = undefined

hasMoreInhabitants :: (Info a, Info b) => a -> b -> Bool
hasMoreInhabitants = undefined

{- TODO: Make Country and State instances of Located -}
class Located a where
  isIn :: City -> a -> Bool


{- Exercise 5.2 -}
{- Add the solution to Exercise 5.2 as comment here -}


{- Exercise 5.3 -}
code :: Char -> String
code 'a' = "01"
code 'b' = "1"
code 'c' = "001"
code 'd' = "0001"

{- 5.3.1 -}
encode :: String -> String
encode s = undefined

{- 5.3.2 -}
isPrefix, neitherPrefix :: String -> String -> Bool
isPrefix s t = undefined
neitherPrefix s t = undefined

{- 5.3.3 -}
decode :: String -> String
decode s = undefined

{- 5.3.4 -}
isPrefixCode :: Bool
isPrefixCode = undefined


{- Tests -}
{- You don't have to understand the Haskell-code in the tests,
   but you can just invoke them after having implemented
   some exercises -}
test_locations = hasMoreArea Austria Tyrol &&
                 inhabitantsPerSkm Gramais == 1 &&
                 hasMoreInhabitants Tyrol Gramais &&
                 not (hasMoreInhabitants Gramais Germany)

{- Tests for exc 5.2 -}

testFun :: (Show a,Show b,Eq b) => (a -> b) -> [(a,b)] -> Bool
testFun f = all (\p -> f (fst p) == snd p ||
  error ("on input "++(show (fst p))++" output is "++(show (f (fst p)))++" but should be "++(show (snd p))))

testFun2 f l = testFun (\p -> f (fst p) (snd p)) (map (\(x,y,z) -> ((x,y),z)) l)
testFun0 f l = testFun (\() -> f) (map (\x -> ((),x)) l)

testEncode = testFun encode ioEncode
ioEncode = [("",""),("c","001"),("abcd","0110010001"),("dcba","0001001101")]

testIsPrefix = testFun2 isPrefix ioIsPrefix
ioIsPrefix = [("","0",True),("1","",False),("1110","111",False),("00","0001",True),("aab","aaaab",False)]

testNeitherPrefix = testFun2 neitherPrefix ioNeitherPrefix
ioNeitherPrefix = [("","a",False),("000","00",False),("010","1",True),("001","0001",True)]

testDecode = testFun decode ioDecode
ioDecode = [("0110010001","abcd"),("0001001101","dcba"),("010101","aaa"),("","")]

testIsPrefixCode = testFun0 isPrefixCode ioIsPrefixCode
ioIsPrefixCode = [True]

testExc52 = testEncode && testIsPrefix && testNeitherPrefix && testDecode && testIsPrefixCode

test_all = testExc52 && test_locations