-- |
-- Module      :  Languages.UniquenessPeriods.Vector.StrictV
-- Copyright   :  (c) OleksandrZhabenko 2020
-- License     :  MIT
-- Stability   :  Experimental
-- Maintainer  :  olexandr543@yahoo.com
--
-- Generalization of the DobutokO.Poetry.StrictV module functionality from 
-- the @dobutokO-poetry-general@ package. 
-- Can be used to get possible permutations of no more than 7 sublists 
-- in the list separated with the elements of the \"whitespace symbols\" 
-- list. 

{-# LANGUAGE CPP, BangPatterns #-}

module Languages.UniquenessPeriods.Vector.StrictV where

#ifdef __GLASGOW_HASKELL__
#if __GLASGOW_HASKELL__>=804
/* code that applies only to GHC 8.4.* and higher versions */
import Data.Semigroup ((<>))
import Prelude hiding ((<>))
#endif
#endif

import qualified Data.Vector as V
import qualified Data.List as L (permutations,intersperse)

-- | Given a [a] consisting of no more than 7 sublists interspersed with the elements of the first argument, 
-- it returns a 'V.Vector' of possible combinations without repeating of the sublists in different order and for each of them appends also 
-- the information about generalized \"uniqueness periods\" (see @uniqueness-periods-vector@ package) to it and finds out 
-- some different metrics -- named \"properties\". 
-- 
-- Afterwards, depending on these norms some (usually phonetic for the words) properties of the sublists can be specified that 
-- allow to use them for special cases of repetitions (usually, for the words -- poetically or to create a varied melody with them). 
uniquenessVariants2GN ::
  (Eq a, Ord b) => [a]
  -> V.Vector ([b] -> b)
  -> ([a] -> V.Vector c)
  -> (V.Vector c -> [b])
  -> [a]
  -> V.Vector ([b],V.Vector b, [a])
uniquenessVariants2GN whspss vN g1 g2 !xs = uniquenessVariants2GNP [] [] whspss vN g1 g2 xs
{-# INLINE uniquenessVariants2GN #-}

-- | Generalized variant of 'uniquenessVariants2GN' with prepending and appending @[a]@ (given as the first and the second argument). 
uniquenessVariants2GNP ::
  (Eq a, Ord b) => [a]
  -> [a]
  -> [a]
  -> V.Vector ([b] -> b)
  -> ([a] -> V.Vector c)
  -> (V.Vector c -> [b])
  -> [a]
  -> V.Vector ([b],V.Vector b, [a])
uniquenessVariants2GNP !ts !us whspss vN g1 g2 !xs
  | null . sublistsG whspss $ xs = V.empty
  | not . null $ whspss = let !v0 = V.fromList . take 8 . sublistsG whspss $ xs in
     V.fromList . map ((\vs -> let !rs = g2 . g1 $ vs in (rs, (V.map (\f -> f rs) vN), vs)) . concat . L.intersperse (take 1 whspss) . preAppend ts [us] . V.toList .
       V.backpermute v0 . V.fromList) . L.permutations $ ([0..(V.length v0 - 1)]::[Int])
  | otherwise = error "Languages.UniquenessPeriods.Vector.StrictV.uniquenessVariants2GNP: undefined for the empty third argument. "

-- | Inspired by: https://hackage.haskell.org/package/base-4.14.0.0/docs/src/Data.OldList.html#words
sublistsG :: Eq a => [a] -> [a] -> [[a]]
sublistsG whspss xs =
 case dropWhile (`elem` whspss) xs of
   [] -> []
   s' -> w : sublistsG whspss s''
     where (w, s'') = break (`elem` whspss) s'

-- | Prepends and appends the given two first arguments to the third one. 
preAppend :: [a] -> [[a]] -> [[a]] -> [[a]]
#ifdef __GLASGOW_HASKELL__
#if __GLASGOW_HASKELL__>=804
preAppend ts !uss tss = ts:tss <> uss
#endif
#endif
#ifdef __GLASGOW_HASKELL__
#if __GLASGOW_HASKELL__<804
preAppend ts !uss tss = ts:tss ++ uss
#endif
#endif
{-# INLINE preAppend #-}