---------------------------------------------------------
-- |
-- Copyright   : (c) 2006-2016, alpheccar.org
-- License     : BSD-style
--
-- Maintainer  : misc@NOSPAMalpheccar.org
-- Stability   : experimental
-- Portability : portable
--
-- PDF Navigation
---------------------------------------------------------

module Graphics.PDF.Navigation(
  -- * Navigation
  -- ** Types
    OutlineStyle(..)
  -- ** Functions
  , newSection
  , newSectionWithPage
 ) where

import Graphics.PDF.Pages
import Graphics.PDF.Draw
import Graphics.PDF.LowLevel.Types
import Control.Monad.State(gets)
import Control.Monad(when)
import Data.Maybe(isNothing)
import qualified Data.Text as T

-- | True if we are adding the first outline to this level
isFirst :: [Bool] -> Bool
isFirst r = head r

-- | Start a new outline level  
startNew :: PDF ()
startNew = modifyStrict $ \s -> s{firstOutline = True:(firstOutline s)}

-- | We remember there are outlines at this level
addedOutline :: PDF ()
addedOutline = modifyStrict $ \s -> s{firstOutline = False:tail (firstOutline s)}

-- | Close an outline level
closeNew :: PDF()
closeNew = do
    r <- gets firstOutline
    when (not (isFirst r)) $ moveToParent
    modifyStrict $ \s -> s{firstOutline = tail (firstOutline s)}

-- | Create a new outline section pointing to the last created page
newSection :: T.Text -- ^ Outline title
           -> Maybe Color -- ^ Outline color
           -> Maybe OutlineStyle -- ^Outline style
           -> PDF ()
           -> PDF ()
newSection myS col style p = newSectionPrivate (toPDFString myS) col style Nothing p

-- | Create a new outline section pointing to a given page
newSectionWithPage :: T.Text -- ^ Outline title
                   -> Maybe Color -- ^ Outline color
                   -> Maybe OutlineStyle -- ^ Outline style
                   -> PDFReference PDFPage -- ^ Page reference
                   -> PDF ()
                   -> PDF ()
newSectionWithPage myS col style page p = newSectionPrivate (toPDFString myS) col style (Just page) p

newSectionPrivate :: PDFString -- ^ Outline title
                  -> Maybe Color -- ^ Outline color
                  -> Maybe OutlineStyle -- ^Outline style
                  -> Maybe (PDFReference PDFPage)
                  -> PDF ()
                  -> PDF ()
newSectionPrivate myS col style page p = do
       let newlevel = do
            startNew
            p
            closeNew
       r <- gets firstOutline
       if isFirst r
        then do
            if length r > 1
             then do
                newChild myS col style page
                addedOutline
                newlevel
             else do
                newSibling myS col style page
                newlevel
        else do
           newSibling myS col style page
           newlevel

newSibling :: PDFString -- ^ Outline title
           -> Maybe Color -- ^ Outline color
           -> Maybe OutlineStyle -- ^Outline style
           -> Maybe (PDFReference PDFPage)
           -> PDF ()
newSibling myS col style page = do
    p <- if isNothing page then gets currentPage else return page
    case p of
        Nothing -> return ()
        Just aPage -> do
            ot <- gets outline
            let myValue = (myS,col,style,Destination aPage)
            case ot of
                Nothing -> modifyStrict $ \s -> s {outline = Just $ insertDown myValue (OutlineLoc (Node myValue []) Top)}
                Just r -> modifyStrict $ \s -> s {outline = Just $ insertRight myValue r}

newChild :: PDFString -- ^ Outline title
         -> Maybe Color -- ^ Outline color
         -> Maybe OutlineStyle -- ^Outline style
         -> Maybe (PDFReference PDFPage)
         -> PDF ()
newChild myS col style page = do
    p <- if isNothing page then gets currentPage else return page
    case p of
        Nothing -> return ()
        Just aPage -> do
            ot <- gets outline
            let myValue = (myS,col,style,Destination aPage)
            case ot of
                Nothing -> modifyStrict $ \s -> s {outline = Just $ insertDown myValue (OutlineLoc (Node myValue []) Top)}
                Just r -> modifyStrict $ \s -> s {outline = Just $ insertDown myValue r}

moveToParent :: PDF ()
moveToParent = do
    ot <- gets outline
    case ot of
       Nothing -> return ()
       Just r -> modifyStrict $ \s -> s {outline = Just $ up r}