{-# LANGUAGE FlexibleContexts #-}

module Gamgine.Math.Vect (module Data.Vec,Vect,Vect4,x,y,z,v3,v4,fromTuple,toTuple,fromVect4,len,
                          inverseVec,clampVec,maxVec,minVec,index,absVec,nullVec,and,or,all,any) where

import Gamgine.Utils
#include "Gamgine/Utils.cpp"
import qualified Gamgine.Math.Utils as U
import Data.Vec
import qualified Data.Vec as V
import Prelude hiding (and, or, all, any)
import Debug.Trace

type Vect  = Vec3 Double
type Vect4 = Vec4 Double

x :: Vect -> Double
x (x:._) = x

y :: Vect -> Double
y (_:.y:._) = y

z :: Vect -> Double
z (_:._:.z:.()) = z

v3 :: Double -> Double -> Double -> Vect
v3 x y z = x:.y:.z:.()

v4 :: Double -> Double -> Double -> Double -> Vect4
v4 x y z w = x:.y:.z:.w:.()

fromTuple :: (Double,Double,Double) -> Vect
fromTuple (x,y,z) = v3 x y z

toTuple :: Vect -> (Double,Double,Double)
toTuple (x:.y:.z:.()) = (x,y,z)

fromVect4 :: Vect4 -> Vect
fromVect4 (x:.y:.z:.w:.()) = v3 x y z

len :: Vect -> Double
len = norm

inverseVec v = V.map (* (-1)) v

index :: (Double -> Bool) -> Vect -> Int
index f (x:.y:.z:.())
   | f x = 0
   | f y = 1
   | f z = 2
   | otherwise = ERROR "Couldn't find elem!"

clampVec :: Vect -> Vect -> Vect -> Vect
clampVec (minX:.minY:.minZ:.()) (maxX:.maxY:.maxZ:.()) (x:.y:.z:.()) =
   v3 (U.clamp minX maxX x) (U.clamp minY maxY y) (U.clamp minZ maxZ z)

maxVec v1 v2 = V.zipWith max v1 v2

minVec v1 v2 = V.zipWith min v1 v2

absVec v = V.map abs v

nullVec = v3 0 0 0

and v = V.foldr (&&) True v

or v = V.foldr (||) False v

all f v1 v2 = and $ V.zipWith f v1 v2

any f v1 v2 = or $ V.zipWith f v1 v2