{-# OPTIONS_HADDOCK hide #-}

{-# LANGUAGE NoImplicitPrelude #-}

module Imj.Graphics.Class.DiscreteDistance
( DiscreteDistance(..)
, Successive(..)
) where

import           Imj.Prelude

import           Data.List( length )

-- | Wrapper on a list, to represents successive waypoints.
newtype Successive a = Successive [a] deriving(Show)

{- | Instances should satisfy:

$$\forall (\, from, to)\, \in v,$$

* 'distance' @from to@ >= 0
* 'distance' @from to@ can be different from 'distance' @to from@,
to provide different forward and backward interpolations (or morphings).
-}
class DiscreteDistance v where
-- | Distance between two 'DiscreteDistance's.
distance :: v -- ^ first value
-> v -- ^ last value
-> Int -- ^ the number of steps (including first and last) to go from first to last

-- | Distance between n successive 'DiscreteDistance's.
distanceSuccessive :: Successive v
-> Int
distanceSuccessive (Successive []) =
error "empty successive"
distanceSuccessive (Successive l@(_:_)) =
succ $sum$ zipWith (\a b -> pred $distance a b) l$ tail l

-- | Naïve interpolation.
instance DiscreteDistance Int where
distance i i' =
1 + abs (i-i')

-- | Interpolation between 2 lists, occuring in parallel between same-index elements.
--   Prerequisite : lists have the same lengths.
--
--  For an interpolation that occurs sequentially between same-index elements,
--   use SequentiallyInterpolatedList.
instance (DiscreteDistance a)
=> DiscreteDistance ([] a) where
distance [] _ = 1
distance _ [] = 1
distance l l' =
maximum $zipWith distance l$ assert (length l == length l') l'