-- |

-- Module      : Cartesian.Internal.Types

-- Description :

-- Copyright   : (c) Jonatan H Sundqvist, 2015

-- License     : MIT

-- Maintainer  : Jonatan H Sundqvist

-- Stability   : experimental|stable

-- Portability : POSIX (not sure)

--



-- Created October 31 2015



-- TODO | - Use TemplateHaskell (?)

--        - Strictness

--        - Performance, inlining



-- SPEC | -

--        -







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

-- GHC Pragmas

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

{-# LANGUAGE TemplateHaskell        #-}

{-# LANGUAGE MultiParamTypeClasses  #-}

{-# LANGUAGE FunctionalDependencies #-}

{-# LANGUAGE RankNTypes             #-}

{-# LANGUAGE FlexibleInstances      #-}





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

-- API

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

module Cartesian.Internal.Types where







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

-- We'll need these

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

import Control.Lens (Simple, Lens, lens)



import Data.Complex (Complex(..))



import Linear.V1

import Linear.V2

import Linear.V3

import Linear.V4







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

-- Types

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



-- Synonyms ------------------------------------------------------------------------------------------------------------------------------------------



-- TODO: Add some aliased lenses for these aliased types (?)



-- | A lens focusing on a single [vector-]component in a BoundingBox

type BoxLens v v' f f' = Lens (BoundingBox (v f)) (BoundingBox (v' f')) f f'





-- | An axis represented as (begin, length)

type Axis a = (a, a)





-- | A vector where each component represents a single axis (cf. 'Axis')

type Axes v a = v (Axis a)





-- |

-- type Domain





-- |

-- TODO: Rename (eg. 'Shape') (?)

type Polygon m v f = m (v f)





-- | Coordinate system wrappers

newtype Normalised v = Normalised { absolute   :: v } -- 

newtype Absolute   v = Absoloute  { normalised :: v } -- 



-- Types ---------------------------------------------------------------------------------------------------------------------------------------------



-- |

-- TODO: Anchors (eg. C, N, S, E W and combinations thereof, perhaps represented as relative Vectors)

-- TODO: Define some standard instances (eg. Functor, Applicative)

data BoundingBox v = BoundingBox { cornerOf :: v, sizeOf :: v } deriving (Show, Eq)





-- |

-- TODO: Use record (eg. from, to) (?)

data Line v = Line v v deriving (Show, Eq)





-- |

data Linear f = Linear { interceptOf :: f, slopeOf :: f } deriving (Show, Eq)





-- |

data Inclusivity r = Inclusive r | Exclusive r -- TODO: Rename (?)

data Interval r    = Interval (Inclusivity r) (Inclusivity r)





-- |

-- TODO: Use existing type instead (?)

-- data Side = SideLeft | SideRight | SideTop | SideBottom



-- Classes -------------------------------------------------------------------------------------------------------------------------------------------



-- TODO: How do you generate lenses for non-record types (?)

class HasX a f | a -> f where { x :: Simple Lens a f }

class HasY a f | a -> f where { y :: Simple Lens a f }

class HasZ a f | a -> f where { z :: Simple Lens a f }



-- Instances -----------------------------------------------------------------------------------------------------------------------------------------





-- TODO: Generate these instances with TemplateHaskell (?)



instance HasX (V1 f) f where

  x = lens (\(V1 x') -> x') (\_ x' -> V1 x')





instance HasX (V2 f) f where

  x = lens (\(V2 x' _) -> x') (\(V2 _ y') x' -> V2 x' y')





instance HasY (V2 f) f where

  y = lens (\(V2 _ y') -> y') (\(V2 x' _) y' -> V2 x' y')





instance HasX (V3 f) f where

  x = lens (\(V3 x' _ _) -> x') (\(V3 _ y' z') x' -> V3 x' y' z')





instance HasY (V3 f) f where

  y = lens (\(V3 _ y' _) -> y') (\(V3 x' _ z') y' -> V3 x' y' z')





instance HasZ (V3 f) f where

  z = lens (\(V3 _ _ z') -> z') (\(V3 x' y' _) z' -> V3 x' y' z')





instance HasX (V4 f) f where

  x = lens (\(V4 x' _ _ _) -> x') (\(V4 _ y' z' w') x' -> V4 x' y' z' w')





instance HasY (V4 f) f where

  y = lens (\(V4 _ y' _ _) -> y') (\(V4 x' _ z' w') y' -> V4 x' y' z' w')





instance HasZ (V4 f) f where

  z = lens (\(V4 _ _ z' _) -> z') (\(V4 x' y' _ w') z' -> V4 x' y' z' w')





instance HasX (Complex f) f where

  x = lens (\(x':+_) -> x') (\(_:+y') x' -> x':+y')





instance HasY (Complex f) f where

  y = lens (\(_':+y') -> y') (\(x':+_) y' -> x':+y')