-
Notifications
You must be signed in to change notification settings - Fork 2
/
Editor.elm
141 lines (111 loc) · 5.1 KB
/
Editor.elm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
module Editor where
import Model exposing (..)
import Constants exposing (..)
import Woot exposing (canIntegrate)
import Graph exposing (generateInsert, generateDelete, integrateRemoteDelete, integrateRemoteInsert)
import String
import Set exposing (..)
integrateRemoteUpdate : WUpdate -> Model -> (Model, List Edit)
integrateRemoteUpdate wUpd m =
let
integrate intFunction wCh =
let
(newModel, newEdits) = toEditList (intFunction wCh m)
(newIntModel, newIntEdits) = integratePool newModel
in
(newIntModel, newIntEdits ++ newEdits)
in
case wUpd of
Insert wCh -> integrate integrateRemoteInsert wCh
Delete wCh -> integrate integrateRemoteDelete wCh
_ -> (m, [])
integratePool : Model -> (Model, List Edit)
integratePool model =
case model.pool of
[] -> ({model | pool = model.processedPool, processedPool = []}, [])
wUpdate :: wUpdates ->
if canIntegrate wUpdate model.wSeen then
-- first we move all updates to pool, so that we'll have to start over
-- then we integrate the update
integrateRemoteUpdate wUpdate {model | pool = model.processedPool ++ wUpdates, processedPool = []}
else
-- move this update to the processedPool, and keep integrating pool
integratePool {model | pool = wUpdates, processedPool = wUpdate :: model.processedPool}
processEdits : List Edit -> Model -> (Model, List Edit)
processEdits edits model = processEditsAccum edits model []
processEditsAccum : List Edit -> Model -> List Edit -> (Model, List Edit)
processEditsAccum edits model oldEdits =
case edits of
[] -> (model, oldEdits)
x :: xs ->
let
(newModel, accEdits) = processEdit x model
in
processEditsAccum xs newModel (oldEdits ++ accEdits)
processEdit : Edit -> Model -> (Model, List Edit)
processEdit edit model =
case edit of
T tUpdate -> processTUpdate tUpdate model
W wUpdate -> processServerUpdate wUpdate model
integrateNew : (WChar -> Model -> (Model, Edit)) -> WUpdate -> WChar -> Model -> (Model, List Edit)
integrateNew integrateFunction wUpd wCh model =
let
(newModel, newEdits) = toEditList (integrateFunction wCh model)
(intNewModel, intNewEdits) = integratePool newModel
in
(intNewModel, intNewEdits ++ newEdits)
processServerUpdate : WUpdate -> Model-> (Model, List Edit)
processServerUpdate wUpd model =
let
handleIntegration wCh insert integrateFunction =
if insert && Set.member wCh.id model.wSeen then
(model, [])
else if canIntegrate wUpd model.wSeen then
integrateNew integrateFunction wUpd wCh model
else ({model | pool = wUpd :: model.pool}, [])
in
case wUpd of
SiteId id -> ({model | site = id}, [])
Insert wCh -> handleIntegration wCh True integrateRemoteInsert
Delete wCh -> handleIntegration wCh False integrateRemoteDelete
CurrWString wString str -> ({model | wString = wString}, [])
NoUpdate -> (model, [])
processTUpdate : TUpdate -> Model -> (Model, List Edit)
processTUpdate typ model =
case typ of
I ch index siteId -> toEditList (generateInsert ch index model)
D ch index -> toEditList (generateDelete ch index model)
IS str index ->
let
(newModel, newEdits) = insertString str (index - 1) model
in
(newModel, List.reverse newEdits)
DS str index -> deleteString str index model
RequestWString -> (model, [W (CurrWString model.wString (Woot.wToString model.wString))])
_ -> (model, [W NoUpdate])
deleteString : String -> Int -> Model -> (Model, List Edit)
deleteString str index model =
let
tUpdates = List.map2 (\ ch index -> D ch index) (String.toList str) [index..(index + String.length str - 1)]
|> List.reverse
newModel = {model | debug = model.debug ++ "DELETTTING: " ++ str++"DELETE LIST: " ++ (toString tUpdates)}
in
List.foldr processTUpdateOfString (newModel, []) tUpdates
insertString : String -> Int -> Model -> (Model, List Edit)
insertString string index model =
let
strIndexList = List.map2 (\ch index -> (ch, index, model.site)) (String.toList string) [index..(index + String.length string - 1)]
tUpdates = List.foldr createInsertTUpdate [] strIndexList
in
List.foldl processTUpdateOfString (model, []) tUpdates
processTUpdateOfString : TUpdate -> (Model, List Edit) -> (Model, List Edit)
processTUpdateOfString tUpdate (model, edits) =
let
(newModel, newEdits) = processTUpdate tUpdate model
in
(newModel, edits ++ newEdits)
toEditList : (Model, Edit) -> (Model, List Edit)
toEditList (model, edit) = (model, [edit])
createInsertTUpdate : (Char, Int, Int) -> List TUpdate -> List TUpdate
createInsertTUpdate (char, index, siteId) tUpdates = I char index siteId :: tUpdates
sendDebug model str = ({model | debug = str ++ model.debug}, W NoUpdate)