module Nxt.Types
    (Vector2d,
     Texture(Texture),
     textureWidth,
     textureHeight,
     textureObject,
     Nxt.Types.Rect(Rect),
     rectX,
     rectY,
     rectWidth,
     rectHeight,
     rectRight,
     rectBottom,
     rectIntersect,
     pointInRect,
     overlapRect,
     Poly(Poly),
     polySides,
     polyVertices,
     polyIntersect,
     Direction(DirLeft,DirRight)) where

import Graphics.Rendering.OpenGL as GL hiding (Rect)

-- Direction
data Direction = DirLeft | DirRight

-- Texture
data Texture = Texture
    {
        textureWidth :: GLsizei,
        textureHeight :: GLsizei,
        textureObject :: TextureObject
    }

-- Rect
data Rect = Rect
    {
        rectX :: Double,
        rectY :: Double,
        rectWidth :: Double,
        rectHeight :: Double
    }
    deriving Show

-- rectRight
rectRight :: Rect -> Double
rectRight (Rect x _ w _) = x + w

-- rectBottom
rectBottom :: Rect -> Double
rectBottom (Rect _ y _ h) = y + h

-- rectIntersect
rectIntersect :: Rect -> Rect -> Bool
rectIntersect (Rect r1X r1Y r1Width r1Height) (Rect r2X r2Y r2Width r2Height) =
    not (r1X > (r2X + r2Width) || r2X > (r1X + r1Width) ||
         r1Y > (r2Y + r2Height) || r2Y > (r1Y + r1Height))

-- pointInRect
pointInRect :: Vector2d -> Rect -> Bool
pointInRect (x, y) (Rect rectXt rectYt width height) =
    x >= rectXt && x <= (rectXt + width) && y >= rectYt && y <= (rectYt + height)

-- overlapRect
overlapRect :: Rect -> Rect -> Rect
overlapRect (Rect r1x r1y r1Width r1Height) (Rect r2x r2y r2Width r2Height) =
    Rect x y width height
    where x = max r1x r2x
          y = max r1y r2y
          width = min (r1x + r1Width) (r2x + r2Width) - x
          height = min (r1y + r1Height) (r2y + r2Height) - r2Height

-- Vector2d
type Vector2d = (Double, Double)

-- Poly
data Poly = Poly
    {
        polySides       :: Int,
        polyVertices    :: [Vector2d]
    }
    deriving Show

-- dotProduct
dotProduct :: Vector2d -> Vector2d -> Double
dotProduct (p1X, p1Y) (p2X, p2Y) = p1X * p2X + p1Y * p2Y

-- polyIntersect
polyIntersect :: Poly -> Poly -> Bool
polyIntersect polyA polyB =
    let polyAVerts = polyVertices polyA
        polyAPrevVerts = last polyAVerts : init polyAVerts
        polyAPairVerts = zip polyAPrevVerts polyAVerts
        polyBVerts = polyVertices polyB
        polyBPrevVerts = last polyBVerts : init polyBVerts
        polyBPairVerts = zip polyBPrevVerts polyBVerts

        normalizeAxis :: (Vector2d, Vector2d) -> Vector2d
        normalizeAxis (prevVert, vert) =
            let
                (ptPrevX, ptPrevY) = prevVert
                (ptCurrX, ptCurrY) = vert
                axisX = ptPrevY - ptCurrY
                axisY = ptCurrX - ptPrevX
                tmp = sqrt (axisX * axisX + axisY * axisY)
            in
                (axisX / tmp, axisY / tmp)

        projRange :: [Vector2d] -> Vector2d -> (Double,Double)
        projRange vertices axis =
            let
                projLengths = map (`dotProduct` axis) vertices
                minl = minimum projLengths
                maxl = maximum projLengths
            in
                (minl, maxl)

        overlap :: (Vector2d, Vector2d) -> Bool
        overlap pairVerts =
            not (maxA < minB || minA > maxB)
            where axis = normalizeAxis pairVerts
                  (minA, maxA) = projRange polyAVerts axis
                  (minB, maxB) = projRange polyBVerts axis

    in
        all overlap polyAPairVerts && all overlap polyBPairVerts

