{-# LANGUAGE DeriveDataTypeable    #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TemplateHaskell       #-}
{-# LANGUAGE TypeFamilies          #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Diagrams.TwoD.Image
-- Copyright   :  (c) 2011 diagrams-lib team (see LICENSE)
-- License     :  BSD-style (see LICENSE)
-- Maintainer  :  diagrams-discuss@googlegroups.com
--
-- Importing external images into diagrams.
--
-----------------------------------------------------------------------------

module Diagrams.TwoD.Image
    (
      Image(..), imgFile, imgSize, imgTransf
    , image
    ) where

import           Control.Lens         (makeLenses)
import           Data.Typeable

import           Diagrams.Core

import           Diagrams.Path
import           Diagrams.TwoD.Path
import           Diagrams.TwoD.Shapes
import           Diagrams.TwoD.Size   (SizeSpec2D (..))
import           Diagrams.TwoD.Types

import           Data.AffineSpace     ((.-.))

import           Data.Semigroup

-- | An external image primitive, representing an image the backend
--   should import from another file when rendering.
data Image = Image { _imgFile   :: FilePath
                   , _imgSize   :: SizeSpec2D
                   , _imgTransf :: T2
                   }
  deriving Typeable

makeLenses ''Image

type instance V Image = R2

instance Transformable Image where
  transform t1 (Image file sz t2) = Image file sz (t1 <> t2)

instance IsPrim Image

instance HasOrigin Image where
  moveOriginTo p = translate (origin .-. p)

instance Renderable Image NullBackend where
  render _ _ = mempty

-- See Note [Image size specification]

-- | Take an external image from the specified file and turn it into a
--   diagram with the specified width and height, centered at the
--   origin.  Note that the image's aspect ratio will be preserved; if
--   the specified width and height have a different ratio than the
--   image's aspect ratio, there will be extra space in one dimension.
image :: (Renderable Image b) => FilePath -> Double -> Double -> Diagram b R2
image file w h = mkQD (Prim (Image file (Dims w h) mempty))
                      (getEnvelope r)
                      (getTrace r)
                      mempty
                      (Query $ \p -> Any (isInsideEvenOdd p r))
  where r :: Path R2
        r = rect w h

{- ~~~~ Note [Image size specification]

It's tempting to make 'image' take a SizeSpec2D instead of two
Doubles.  For example, if I know I want the image to be x units wide
but I don't know the original aspect ratio of the image, I'd like to
be able to just say "make it x units wide".  The problem is that
diagrams would then not know how tall the image is until rendering
time (at least, not without unsafePerformIO yuckiness).  A more
general solution will have to wait until we can specify constraints
and solve them later.

-}