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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/* DreemGL is a collaboration between Teeming Society & Samsung Electronics, sponsored by Samsung and others.
   Copyright 2015-2016 Teeming Society. Licensed under the Apache License, Version 2.0 (the "License"); You may not use this file except in compliance with the License.
   You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing,
   software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and limitations under the License.*/

define.class(function(exports){

        // internal, Reactive renderer

        var initializing = false
        var log_render_cause = false
        var process_list = []
        var process_timer = undefined

        function processTimeout(){
                process_timer = undefined
                var pl = process_list
                process_list = []
                for(var i = 0; i < pl.length; i+=2){
                        //console.log("Processing",pl[i])
                        var node = pl[i+1], iter = node

                        if(log_render_cause){
                                console.log("Re-render caused by "+pl[i]+" on ", node)
                        }

                        while(iter){
                                if(iter.destroyed) break
                                iter = iter.parent
                        }
                        if(!iter) exports.process(node, undefined, undefined, true)
                }
        }

        function __atAttributeGetRender(event, value, pthis, key){
                if(!initializing){
                        //exports.process(this, undefined, undefined, true)
                        if(process_list.indexOf(this) === -1){
                                var oldval = (event && event.old) || this[key];
                                if (! key || ((value !== oldval) || typeof value === 'object')){
                                        // only render if the value changed and isn't an object
                                        process_list.push(key, this)
                                } else {
                                        // console.log('skipping render for', key, value, oldval, this)
                                        return
                                }
                        }
                        if(!process_timer){
                                process_timer = setTimeout(processTimeout, 0)
                        }
                }
        }

        function atAttributeGet(key){
                // lets find out if we already have a listener on it
                if(this.getAttributeConfig(key).rerender !== false && !this.hasListenerProp(key, 'name', '__atAttributeGetRender')){
                        this.addListener(key, __atAttributeGetRender)
                }
        }

        exports.process = function render(inew_version, old_version, state, rerender, nochild){

                var new_version = inew_version
                var is_root = false

                if(!state){
                        state = {render_block:[]}
                        is_root = true
                }

                // call connect wires before
                if(!rerender){
                        var wires = []
                        new_version.connectWires(wires)
                        initializing = true
                        for(var i = 0; i < wires.length; i++){
                                wires[i]()
                        }
                        initializing = false
                }

                var old_children = old_version? old_version.children: undefined

                // lets call init only when not already called
                if(!rerender){
                        if(old_version && old_version._persists && new_version._persists){
                                for(var key in old_version._persists){
                                        if(!(key in new_version._persists)) continue
                                        // we should set it using a special emit
                                        var value =  old_version[key]
                                        new_version['_' + key] = old_version[key]
                                        new_version.emit(key, {type:'persist', owner:new_version, key:key, value:value})
                                }
                        }
                        if(new_version.atAnimate) new_version.screen.device.animate_hooks.push(new_version)
                        if(old_version) old_version.old_flag = true
                        if(new_version.atViewInit) new_version.atViewInit(old_version)
                        new_version.emit('init', old_version)// old_version && old_version.constructor == new_version.constructor? old_version: undefined)
                }
                else{
                        old_children = new_version.children
                }

                // lets only do this if we have a render function
                if(new_version.render){
                        // then call render

                        // store the attribute dependencies
                        new_version.atAttributeGet = atAttributeGet
                        new_version.rerender = __atAttributeGetRender

                        // lets check if object.constructor  a module, ifso
                        if(new_version.classroot === undefined){
                                new_version.classroot = new_version
                                //console.log(object)
                         }

                         define.atConstructor =  new_version.atStyleConstructor.bind(new_version)

                         new_version.children = new_version.render()

                         define.atConstructor = undefined
                        new_version.atAttributeGet = undefined
                }
                else{
                        new_version.children = new_version.constructor_children
                }

                if(!Array.isArray(new_version.children)){
                        if(new_version.children) new_version.children = [new_version.children]
                        else new_version.children = []
                }

                if(new_version.atRender) new_version.atRender()

                if(new_version._viewport){
                        // set up a new layer
                        new_version.parent_viewport = new_version
                        new_version.child_viewport_list = []
                        if(!rerender && new_version.parent && new_version.parent.parent_viewport){
                                new_version.parent.parent_viewport.child_viewport_list.push(new_version)
                        }
                }
                 // what we need to do, is

                var new_children = new_version.children

                if(!nochild && new_children) for(var i = 0; i < new_children.length; i++){
                        var new_child = new_children[i]
                        if(Array.isArray(new_child)){ // splice in the children
                                var args = Array.prototype.slice.call(new_child)
                                args.unshift(1)
                                args.unshift(i)
                                Array.prototype.splice.apply(new_children, args)
                                i-- // hop back one i so we repeat
                                continue
                        }

                        var old_child = undefined
                        if(old_children){
                                old_child = old_children[i]
                                if(new_children.indexOf(old_child) !== -1) old_child = undefined
                        }
                        var childreuse = false
                        if(new_child.parent){
                                childreuse = true
                        }
                        //var name = new_child.name
                        //if(name !== undefined && !(name in new_version)) new_version[name] = new_child

                        new_child.parent = new_version
                        new_child.screen = new_version.screen
                        new_child.rpc = new_version.rpc
                        new_child.parent_viewport = new_version.parent_viewport
                        new_children[i] = render(new_child, old_child, state, childreuse)
                        if(new_version.atChildRendered) new_version.atChildRendered(new_child)
                }

                if(new_version.atChildrenRendered) new_version.atChildrenRendered()

                if(old_children) for(;i < old_children.length;i++){
                        var child = old_children[i]
                        child.destroyed = true
                        child.atViewDestroy()
                        child.emit('destroy')
                }

                if(old_version && !rerender){
                        old_version.destroyed = true
                        // remove draw hook
                        if(old_version.atAnimate){
                                var id = old_version.screen.device.animate_hooks.indexOf(old_version)
                                if(id !== -1) old_version.screen.device.animate_hooks.splice(id, 1)
                        }
                        old_version.atViewDestroy()
                        old_version.emit('destroy')
                }

                if(is_root){


                        // signal to our device we have a newly rendered node
                        if(new_version.screen){
                                new_version.screen.device.atNewlyRendered(new_version)
                        }
                }

                return new_version
        }

        exports.dump = function(node, depth){
                var ret = ''
                if(!depth) depth = ''
                ret += depth + node.name + ': ' + node.constructor.name
                var outer = node.outer
                while(outer){
                        ret += " - " + outer.constructor.name
                        outer = outer.outer
                }
                if(node.children) for(var i = 0; i<node.children.length; i++){
                        ret += "\n"
                        ret += this.dump(node.children[i], depth +'-')
                }
                return ret
        }
})