-- |
-- Module      :  HGE2D.Collision
-- Copyright   :  (c) 2016 Martin Buck
-- License     :  see LICENSE
--
-- Containing functions for collision detection

module HGE2D.Collision where

import HGE2D.Types
import HGE2D.Datas
import HGE2D.Classes

--------------------------------------------------------------------------------

-- | Tests whether two objects collide (overlap in any way)
doCollide :: (HasBoundingBox a, HasBoundingBox b) => a -> b -> Bool
doCollide hasBB1 hasBB2 = 2.0 * xcenterthis - xcenterother < (xsizethis + xsizeother)
                       && 2.0 * ycenterthis - ycenterother < (ysizethis + ysizeother)
    where
      (bb1, bb2)                    = (getBB hasBB1, getBB hasBB2)
      (minthis, maxthis)            = (bbMin bb1, bbMax bb1)
      (minother, maxother)          = (bbMin bb2, bbMax bb2)
      (xsizethis, ysizethis)        = (abs $ (fst minthis) - (fst maxthis),    abs $ (snd minthis) - (snd maxthis))
      (xsizeother, ysizeother)      = (abs $ (fst minother) - (fst maxother),    abs $ (snd minother) - (snd maxother))
      (xcenterthis, ycenterthis)    = ((fst minthis) + (fst maxthis) / 2.0,    (snd minthis) + (snd maxthis) / 2.0)
      (xcenterother, ycenterother)  = ((fst minother) + (fst maxother) / 2.0,    (snd minother) + (snd maxother) / 2.0)

--------------------------------------------------------------------------------

-- | Tests whether either of the two objects fully contain the other
doContain :: (HasBoundingBox a, HasBoundingBox b) => a -> b -> Bool
doContain hasBB1 hasBB2 =   (isInside hasBB1 hasBB2)
                         || (isInside hasBB2 hasBB1)

--------------------------------------------------------------------------------

-- | Tests whether the first is fully in the second
isInside :: (HasBoundingBox a, HasBoundingBox b) => a -> b -> Bool
isInside hasBBIn hasBBOut =  (fst minIn) > (fst minOut)
                          && (snd minIn) > (snd minOut)
                          && (fst maxIn) < (fst maxOut)
                          && (snd maxIn) < (snd maxOut)
  where
    (bbIn, bbOut)       = (getBB hasBBIn, getBB hasBBOut)
    (minIn, maxIn)      = (bbMin bbIn, bbMax bbIn)
    (minOut, maxOut)    = (bbMin bbOut, bbMax bbOut)

--------------------------------------------------------------------------------

-- | Tests whether a position is within the bounding box
isInsideRP :: (Positioned a, HasBoundingBox b) => a -> b -> Bool
isInsideRP pos hasBB =  (posX > bbLeft)
                     && (posX < bbRight)
                     && (posY > bbTop)
                     && (posY < bbBottom)
  where
    posX     = fst $ getPos pos
    posY     = snd $ getPos pos
    bbTop    = snd $ bbMin bb
    bbRight  = fst $ bbMax bb
    bbBottom = snd $ bbMax bb
    bbLeft   = fst $ bbMin bb
    bb       = getBB hasBB