module PictureGenerator
  where

import qualified PetrusFiles as PF
import Data.Maybe
import Data.List

drawFloor :: PF.SimpleGameConfiguration -> [PF.BuildingNode] -> Int -> String

drawFloor sgc nodes fl = drawNodes ++ drawEdges
  where
    nodedist = 4
    floorNodes = filter (\node -> (PF.floor node) == fl) nodes
    floorNodeIds = map PF.id floorNodes
    targetIdx = PF.targets $ PF.staticGameConfiguration sgc
    stGC = PF.staticGameConfiguration sgc
    edges = PF.edges $ PF.graph stGC
    payoffLabel :: Int -> String
    payoffLabel tIdx = "\\\\ \\footnotesize D(-" ++ (show $ PF.defenderPenalties stGC !! tIdx !! 0) ++ ")" ++ "\\\\ \\footnotesize A("++(show $ PF.attackerRewards stGC !! tIdx !! 0)++")"
    nodeLabel (PF.BuildingNode idx _ _ _ _) =  (show idx) ++ (
      if elem idx targetIdx  then
        maybe "\\\\ERROR" payoffLabel (elemIndex idx targetIdx)
      else
        ""
      )

    getNeighbour (PF.BuildingNode _ x y floo _) xdiff ydiff = listToMaybe $ filter (\n -> (x+xdiff) == (PF.x n) && (y+ydiff) == (PF.y n) && (PF.floor n) == floo) (nodes)

    diffWallCheckEdge label (PF.BuildingNode idx1 _ _ _ _) (PF.BuildingNode idx2 _ _ _ _) 
      | elem (PF.Edge idx1 idx2) edges = Just label
      | otherwise = Nothing  
    diffWallPos xdiff ydiff label n
      | PF.ntype n == PF.Entrance && (((PF.x n) +xdiff) < 0 || ((PF.x n)+xdiff) > (foldl1 max $ map PF.x nodes) ) = Just label
      | otherwise = getNeighbour n xdiff ydiff >>= diffWallCheckEdge label n

    wallPossibilities :: [PF.BuildingNode -> Maybe String]
    wallPossibilities = [
      diffWallPos (-1) 0 "wopen",
      diffWallPos 1 0 "eopen",
      diffWallPos 0 (-1) "nopen",
      diffWallPos 0 1 "sopen"
                        ]
    wallInfo n = concat $ intersperse ","  (mapMaybe ($n) wallPossibilities)
    drawNodes :: String
    drawEdges :: String 
    drawNodes = concatMap drawNode floorNodes
    specialNode (PF.BuildingNode 0 x y _ _) =  "\\node (dstart) [dstart,xshift="++(show (x*nodedist))++"em,yshift=-"
      ++(show (y*nodedist))++"em] {};\n"
    specialNode _ = ""
    drawNode :: PF.BuildingNode -> String
    drawNode n@(PF.BuildingNode idx x y _ ntype) =
      "\\node (n"++(show idx)++") ["++(wallInfo n)++",xshift="++(show (x*nodedist))++"em,yshift=-"
      ++(show (y*nodedist))++"em,"++(show ntype)++(additionalClasses idx)++"] {"++(nodeLabel n)++"};\n" 
      ++(specialNode n)
    drawEdges = unlines $ mapMaybe drawEdge $ PF.edges $ PF.graph $ PF.staticGameConfiguration sgc
    drawEdge :: PF.Edge -> Maybe String
    drawEdge (PF.Edge e1 e2)
      | (elem from floorNodeIds) && (elem to floorNodeIds) && isHorizontalEdge && e1 == from = Just $ "\\connectnodesh{"++(show from)++"}{"++(show to)++"}\n"
      | (elem from floorNodeIds) && (elem to floorNodeIds) &&  (not isHorizontalEdge) && e1==from = Just $ "\\connectnodesv{"++(show from)++"}{"++(show to)++"}\n"
      | otherwise = Nothing
      where
        getX node = PF.x $ head $ filter ((==node) . PF.id) nodes
        getY node = PF.y $ head $ filter ((==node) . PF.id) nodes
        isHorizontalEdge = (getY e1) == (getY e2)
        coordFun = if isHorizontalEdge then getX else getY
        from = if (coordFun e1) < (coordFun e2) then e1 else e2
        to = if (coordFun e1) > (coordFun e2) then e1 else e2
    classPairs :: [((Int -> Bool), String)]
    classPairs = [
      ((\idx -> elem idx $ PF.targets $ PF.staticGameConfiguration sgc), ",target"),
      ((\idx -> elem idx $ PF.spawns $ PF.staticGameConfiguration sgc), ",spawn"),
      ((==0), ",start")
                 ]
    additionalClasses :: Int -> String
    additionalClasses idx = concatMap snd $ filter  (($idx) . fst) classPairs

drawBuilding :: PF.SimpleGameConfiguration -> [PF.BuildingNode] -> String
drawBuilding sgc nodes = concatMap helper [0..floorCount]
  where
    floorCount = foldl1 max (map PF.floor nodes)
    height = foldl1 max (map PF.y nodes)
    helper :: Int -> String
    helper fl = "\\begin{scope}[yshift=-"++(show ((fromIntegral fl)*((fromIntegral height)+1)*4.5::Float))++"em] "++
      (drawFloor sgc nodes fl)
      ++" \\end{scope}\n"
