packages feed

tinytools-0.1.0.5: src/Potato/Flow/Deprecated/State.hs

-- DEPRECATED
-- keeping around because we use the types for testing

{-# LANGUAGE RecordWildCards #-}

module Potato.Flow.Deprecated.State (
  PFState(..)
  , debugPrintPFState
  , pFState_isValid
  , pFState_selectionIsValid
  , pFState_copyElts
  , pFState_getSuperSEltByPos
  , pFState_getSEltLabels
  , pFState_maxID
  , pFState_getLayerPosMap
  , sPotatoFlow_to_pFState
  , pFState_to_sPotatoFlow
  , pFState_toCanvasCoordinates
  , pfState_layerPos_to_superSEltLabel
  , pFState_to_superSEltLabelSeq

  , emptyPFState
  , do_newElts
  , undo_newElts
  , do_deleteElts
  , undo_deleteElts

  -- TODO test
  , do_move
  , undo_move

  , do_resizeCanvas
  , undo_resizeCanvas
  , do_manipulate
  , undo_manipulate
) where

import           Relude


import           Potato.Flow.Deprecated.Layers
import           Potato.Flow.Math
import           Potato.Flow.Methods.SEltMethods
import           Potato.Flow.Serialization.Snake
import           Potato.Flow.Types

import           Control.Exception       (assert)
import           Data.Aeson
import qualified Data.IntMap.Strict      as IM
import           Data.List.Ordered       (isSorted)
import           Data.Maybe
import qualified Data.Sequence           as Seq


data PFState = PFState {
  -- TODO someday change this to bimap so that we can get rid of _pfo_layerPosMap
  _pFState_layers      :: Seq REltId
  , _pFState_directory :: REltIdMap SEltLabel
  , _pFState_canvas    :: SCanvas
} deriving (Eq, Show, Generic)

instance FromJSON PFState
instance ToJSON PFState
instance NFData PFState

debugPrintPFState :: (IsString a) => PFState -> a
debugPrintPFState PFState {..} = fromString $ "PFState:\n" <> show _pFState_layers <> "\n" <> show (IM.keys _pFState_directory) <> "\n"

pFState_isValid :: PFState -> Bool
pFState_isValid pfs@PFState {..} = pFState_selectionIsValid pfs ([0..Seq.length _pFState_layers - 1])
{-validElts && validScope where
  validElts = all isJust . toList $ fmap ((IM.!?) _pFState_directory) _pFState_layers
  validScope = hasScopingProperty scopeFn _pFState_layers
  scopeFn x = case IM.lookup x _pFState_directory of
    Nothing                            -> Nothing -- this will fail in vaildElts case so it doesn't matter what we do here
    Just (SEltLabel _ SEltFolderStart) -> Just True
    Just (SEltLabel _ SEltFolderEnd)   -> Just False
    _                                  -> Nothing
-}

pFState_selectionIsValid :: PFState -> [LayerPos] -> Bool
pFState_selectionIsValid PFState {..} lps = validElts && validScope && sorted where
  validElts = all isJust . toList $ fmap ((IM.!?) _pFState_directory) _pFState_layers
  validScope = selectionHasScopingProperty scopeFn _pFState_layers lps
  sorted = isSorted lps
  scopeFn x = case IM.lookup x _pFState_directory of
    Nothing                            -> Nothing -- this will fail in vaildElts case so it doesn't matter what we do here
    Just (SEltLabel _ SEltFolderStart) -> Just True
    Just (SEltLabel _ SEltFolderEnd)   -> Just False
    _                                  -> Nothing

-- TODO SOMETHING BROKEN HERE
-- lps must be valid
pFState_copyElts :: PFState -> [LayerPos] -> [SEltLabel]
pFState_copyElts PFState {..} lps = r where
  ridfn lp = Seq.index _pFState_layers lp
  seltlfn rid = fromJust $ IM.lookup rid _pFState_directory
  r = map (seltlfn . ridfn) lps

pFState_getSuperSEltByPos :: PFState -> LayerPos -> Maybe SuperSEltLabel
pFState_getSuperSEltByPos PFState {..} lp = do
  rid <- Seq.lookup lp _pFState_layers
  seltl <- IM.lookup rid _pFState_directory
  return (rid, lp, seltl)

pFState_getSEltLabels :: PFState -> [REltId] -> REltIdMap (Maybe SEltLabel)
pFState_getSEltLabels PFState {..} rids = foldr (\rid acc -> IM.insert rid (IM.lookup rid _pFState_directory) acc) IM.empty rids

pFState_maxID :: PFState -> REltId
pFState_maxID s = maybe 0 fst (IM.lookupMax (_pFState_directory s))

pFState_getLayerPosMap :: PFState -> LayerPosMap
pFState_getLayerPosMap pfs = Seq.foldrWithIndex (\lp rid acc -> IM.insert rid lp acc) IM.empty (_pFState_layers pfs)

emptyPFState :: PFState
emptyPFState = PFState Seq.empty IM.empty (SCanvas (LBox 0 0))

sPotatoFlow_to_pFState :: SPotatoFlow -> PFState
sPotatoFlow_to_pFState SPotatoFlow {..} = r where
  elts = _sPotatoFlow_sEltTree
  dir = foldr (\(rid, e) acc -> IM.insert rid e acc) IM.empty elts
  layers = Seq.fromList (map fst elts)
  r = PFState layers dir _sPotatoFlow_sCanvas

pFState_to_sPotatoFlow :: PFState -> SPotatoFlow
pFState_to_sPotatoFlow PFState {..} = r where
  selttree = toList . fmap (\rid -> (rid, _pFState_directory IM.! rid)) $ _pFState_layers
  r = SPotatoFlow _pFState_canvas selttree

pFState_toCanvasCoordinates :: PFState -> XY -> XY
pFState_toCanvasCoordinates PFState {..} (V2 x y) = V2 (x-sx) (y-sy) where
  LBox (V2 sx sy) _ = _sCanvas_box _pFState_canvas

-- expects LayerPos to be valid in PFState
pfState_layerPos_to_superSEltLabel :: PFState -> LayerPos -> SuperSEltLabel
pfState_layerPos_to_superSEltLabel PFState {..} lp = (rid, lp, seltl) where
  rid = Seq.index _pFState_layers lp
  seltl = (IM.!) _pFState_directory rid

-- i.e. select all
pFState_to_superSEltLabelSeq :: PFState -> Seq SuperSEltLabel
pFState_to_superSEltLabelSeq PFState {..} = Seq.mapWithIndex (\lp rid -> (rid, lp, fromJust $ IM.lookup rid _pFState_directory)) $ _pFState_layers

-- CHANGE [SuperOwl] -> PFState -> (PFState, SEltLabelChanges)
do_newElts :: [SuperSEltLabel] -> PFState -> (PFState, SEltLabelChanges)
do_newElts seltls PFState {..} = (r, fmap Just changes) where
  poss = map (\(x,y,_) -> (y,x)) seltls
  els = map (\(x,_,z) -> (x,z)) seltls
  changes = IM.fromList els
  newLayers = insertEltList_indexAfterInsertion poss _pFState_layers
  newDir = changes `IM.union` _pFState_directory
  r = PFState newLayers newDir _pFState_canvas

-- CHANGE [SuperOwl] -> PFState -> (PFState, SEltLabelChanges)
undo_newElts :: [SuperSEltLabel] -> PFState -> (PFState, SEltLabelChanges)
undo_newElts seltls PFState {..} = (r, changes) where
  poss = map (\(_,y,_) -> y) seltls
  els = map (\(x,_,z) -> (x,z)) seltls
  newLayers = removeEltList poss _pFState_layers
  newDir = _pFState_directory `IM.difference` IM.fromList els
  r = PFState newLayers newDir _pFState_canvas
  changes = IM.fromList $ map (\(x,_)->(x,Nothing)) els

-- CHANGE [SuperOwl] -> PFState -> (PFState, SEltLabelChanges)
do_deleteElts :: [SuperSEltLabel] -> PFState -> (PFState, SEltLabelChanges)
do_deleteElts = undo_newElts

-- CHANGE [SuperOwl] -> PFState -> (PFState, SEltLabelChanges)
undo_deleteElts :: [SuperSEltLabel] -> PFState -> (PFState, SEltLabelChanges)
undo_deleteElts = do_newElts

--
-- CHANGE
-- | (list of parents (assert no repeats), target (placed after or as first child if top owl (no parent)))
--do_move :: ([REltId], Maybe REltId) -> PFState  -> (PFState, SEltLabelChanges)
-- TODO assert selection has all children
do_move :: ([LayerPos], LayerPos) -> PFState -> (PFState, SEltLabelChanges)
do_move (lps, dst) pfs@PFState {..} = assert (pFState_selectionIsValid pfs lps) (r, changes) where
  -- TODO something like this
  --lps' = addChildren lps pfs
  r = PFState (moveEltList lps dst _pFState_layers) _pFState_directory _pFState_canvas
  changes = pFState_getSEltLabels pfs (fmap (Seq.index _pFState_layers) lps)
{--
  rids = foldr (\l acc -> Seq.index _pFState_layers l : acc) [] lps
  newLayers' = assert (isSorted lps) $ foldr (\l acc -> Seq.deleteAt l acc) _pFState_layers lps
  moveToIndex = dst - (length (takeWhile (\x -> x < dst) lps))
  (leftL, rightL) = Seq.splitAt moveToIndex newLayers'
  newLayers = leftL >< fromList rids >< rightL
  r = PFState newLayers _pFState_directory _pFState_canvas
--}

undo_move :: ([LayerPos], LayerPos) -> PFState -> (PFState, SEltLabelChanges)
undo_move (lps, dst) pfs@PFState {..} =  (r, changes) where
  -- TODO something like this
  --lps' = addChildren lps pfs
  r = PFState (undoMoveEltList lps dst _pFState_layers) _pFState_directory _pFState_canvas
  changes = pFState_getSEltLabels pfs (fmap (Seq.index _pFState_layers) lps)
{--
  --assert (isSorted lps)
  nMoved = length lps
  moveToIndex = dst - (length (takeWhile (\x -> x < dst) lps))
  (leftL,rightL') = Seq.splitAt moveToIndex _pFState_layers
  (toMove,rightL) = Seq.splitAt nMoved rightL'
  newLayers' = leftL >< rightL
  newLayers = insertEltList (zip lps (toList toMove)) newLayers'
  r = PFState newLayers _pFState_directory _pFState_canvas
--}

-- | check if the SCanvas is valid or not
-- for now, canvas offset must always be 0, I forget why it's even an option to offset the SCanvas, probably potatoes.
isValidCanvas :: SCanvas -> Bool
isValidCanvas (SCanvas (LBox p (V2 w h))) = p == 0 && w > 0 && h > 0

do_resizeCanvas :: DeltaLBox -> PFState -> PFState
do_resizeCanvas d pfs = assert (isValidCanvas newCanvas) $ pfs { _pFState_canvas = newCanvas } where
  newCanvas = SCanvas $ plusDelta (_sCanvas_box (_pFState_canvas pfs)) d

undo_resizeCanvas :: DeltaLBox -> PFState -> PFState
undo_resizeCanvas d pfs = assert (isValidCanvas newCanvas) $ pfs { _pFState_canvas = newCanvas } where
  newCanvas = SCanvas $ minusDelta (_sCanvas_box (_pFState_canvas pfs)) d

manipulate :: Bool -> ControllersWithId -> PFState -> (PFState, SEltLabelChanges)
manipulate isDo cs pfs = (r, fmap Just changes) where
  dir = _pFState_directory pfs
  changes = IM.intersectionWith (updateFnFromController isDo) cs dir
  newDir = IM.union changes dir
  r = pfs { _pFState_directory = newDir }

do_manipulate :: ControllersWithId -> PFState -> (PFState, SEltLabelChanges)
do_manipulate = manipulate True

undo_manipulate :: ControllersWithId -> PFState -> (PFState, SEltLabelChanges)
undo_manipulate = manipulate False