1d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar/*
2d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Copyright (C) 2015 The Android Open Source Project
3d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
4d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * you may not use this file except in compliance with the License.
5d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * You may obtain a copy of the License at
6d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
7d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Unless required by applicable law or agreed to in writing, software
8d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
9d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * See the License for the specific language governing permissions and
11d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * limitations under the License.
12d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar */
13d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
14fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool.writer
15d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
16e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyarimport android.databinding.tool.BindingTarget
17d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.InverseBinding
18716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport android.databinding.tool.LayoutBinder
19fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.Expr
20fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.ExprModel
21fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.FieldAccessExpr
22716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport android.databinding.tool.expr.IdentifierExpr
23793e979f25e190162eacf46d6a4efc3efc1d2f91George Mountimport android.databinding.tool.expr.ListenerExpr
2409aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyarimport android.databinding.tool.expr.ResourceExpr
25d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.expr.TernaryExpr
267b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyarimport android.databinding.tool.ext.androidId
27d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.ext.br
287b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyarimport android.databinding.tool.ext.joinToCamelCaseAsVar
2959229481aec5a284d322a2ca80dff836485feb0cYigit Boyarimport android.databinding.tool.ext.lazyProp
30716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport android.databinding.tool.ext.versionedLazy
3192a428505b9102bc0560d2d5be1768da097909c2George Mountimport android.databinding.tool.processing.ErrorMessages
32fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelAnalyzer
337b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyarimport android.databinding.tool.util.L
3496e1c821dd446d1ed78f8ae61131550588f60a24George Mountimport java.util.ArrayList
35716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport java.util.Arrays
36716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport java.util.BitSet
3734a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mountimport java.util.HashMap
3843596c2b2997e40b709627419732100d78a62ff0Yigit Boyar
39fda1703c88eb22e9f166d957d6bda2cd8d645b8fYigit Boyarfun String.stripNonJava() = this.split("[^a-zA-Z0-9]".toRegex()).map{ it.trim() }.joinToCamelCaseAsVar()
40d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
41019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarenum class Scope {
42fda1703c88eb22e9f166d957d6bda2cd8d645b8fYigit Boyar    FIELD,
43fda1703c88eb22e9f166d957d6bda2cd8d645b8fYigit Boyar    METHOD,
44fda1703c88eb22e9f166d957d6bda2cd8d645b8fYigit Boyar    FLAG,
45fda1703c88eb22e9f166d957d6bda2cd8d645b8fYigit Boyar    EXECUTE_PENDING_METHOD,
46019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    CONSTRUCTOR_PARAM
47019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar}
48019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
49d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarclass ExprModelExt {
50019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    val usedFieldNames = hashMapOf<Scope, MutableSet<String>>();
51fda1703c88eb22e9f166d957d6bda2cd8d645b8fYigit Boyar    init {
5239113ca579a3d4e1c24e204f102e6dc9b26125afTor Norbye        Scope.values().forEach { usedFieldNames[it] = hashSetOf<String>() }
53019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    }
54d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    val localizedFlags = arrayListOf<FlagSet>()
55d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
56d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun localizeFlag(set : FlagSet, name:String) : FlagSet {
57d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        localizedFlags.add(set)
58793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        val result = getUniqueName(name, Scope.FLAG, false)
5959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        set.localName = result
60d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return set
61d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
62d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
63793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    fun getUniqueName(base : String, scope : Scope, isPublic : kotlin.Boolean) : String {
64793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        var candidateBase = base
6559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        if (!isPublic && candidateBase.length > 20) {
66793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            candidateBase = candidateBase.substring(0, 20);
67793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        }
68793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        var candidate = candidateBase
69d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        var i = 0
705d454e5f2397a3b160f081ce123b4ca7ff0fc356Yigit Boyar        while (usedFieldNames[scope]!!.contains(candidate)) {
71d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            i ++
72793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            candidate = candidateBase + i
73d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
745d454e5f2397a3b160f081ce123b4ca7ff0fc356Yigit Boyar        usedFieldNames[scope]!!.add(candidate)
75d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return candidate
76d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
77d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
78d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
7959229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval ExprModel.ext by lazyProp { target : ExprModel ->
80d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    ExprModelExt()
81d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
82d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
83793e979f25e190162eacf46d6a4efc3efc1d2f91George Mountfun ExprModel.getUniqueFieldName(base : String, isPublic : kotlin.Boolean) : String = ext.getUniqueName(base, Scope.FIELD, isPublic)
84793e979f25e190162eacf46d6a4efc3efc1d2f91George Mountfun ExprModel.getUniqueMethodName(base : String, isPublic : kotlin.Boolean) : String = ext.getUniqueName(base, Scope.METHOD, isPublic)
85793e979f25e190162eacf46d6a4efc3efc1d2f91George Mountfun ExprModel.getConstructorParamName(base : String) : String = ext.getUniqueName(base, Scope.CONSTRUCTOR_PARAM, false)
86d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
87d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun ExprModel.localizeFlag(set : FlagSet, base : String) : FlagSet = ext.localizeFlag(set, base)
88d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
8959229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval Expr.needsLocalField by lazyProp { expr : Expr ->
9059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    expr.canBeEvaluatedToAVariable() && !(expr.isVariable() && !expr.isUsed) && (expr.isDynamic || expr is ResourceExpr)
9109aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar}
9209aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar
9309aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar
94019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar// not necessarily unique. Uniqueness is solved per scope
9559229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval BindingTarget.readableName by lazyProp { target: BindingTarget ->
9659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    if (target.id == null) {
9759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        "boundView" + indexFromTag(target.tag)
9800da715547ee7d5d38a3b8576090ca427a94daa5George Mount    } else {
9959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        target.id.androidId().stripNonJava()
10000da715547ee7d5d38a3b8576090ca427a94daa5George Mount    }
101d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
1027551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar
103de38dd3ef0577d25b2d59863603abe5750d0c231George Mountfun BindingTarget.superConversion(variable : String) : String {
10459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    if (resolvedType != null && resolvedType.extendsViewStub()) {
10559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        return "new android.databinding.ViewStubProxy((android.view.ViewStub) $variable)"
106de38dd3ef0577d25b2d59863603abe5750d0c231George Mount    } else {
10759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        return "($interfaceClass) $variable"
108de38dd3ef0577d25b2d59863603abe5750d0c231George Mount    }
109de38dd3ef0577d25b2d59863603abe5750d0c231George Mount}
110de38dd3ef0577d25b2d59863603abe5750d0c231George Mount
11159229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval BindingTarget.fieldName : String by lazyProp { target : BindingTarget ->
112019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    val name : String
113793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    val isPublic : kotlin.Boolean
11459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    if (target.id == null) {
115019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        name = "m${target.readableName}"
116793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        isPublic = false
117019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    } else {
118019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        name = target.readableName
119793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        isPublic = true
12034a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount    }
12159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    target.model.getUniqueFieldName(name, isPublic)
122d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
123d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
12459229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval BindingTarget.androidId by lazyProp { target : BindingTarget ->
12559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    if (target.id.startsWith("@android:id/")) {
12659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        "android.R.id.${target.id.androidId()}"
127fdfbbcd5ecf37d77a4b9ab1cefdebd68de71ca2bGeorge Mount    } else {
12859229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        "R.id.${target.id.androidId()}"
129fdfbbcd5ecf37d77a4b9ab1cefdebd68de71ca2bGeorge Mount    }
130d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
131d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
13259229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval BindingTarget.interfaceClass by lazyProp { target : BindingTarget ->
13359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    if (target.resolvedType != null && target.resolvedType.extendsViewStub()) {
134de38dd3ef0577d25b2d59863603abe5750d0c231George Mount        "android.databinding.ViewStubProxy"
135de38dd3ef0577d25b2d59863603abe5750d0c231George Mount    } else {
13659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        target.interfaceType
137de38dd3ef0577d25b2d59863603abe5750d0c231George Mount    }
138de38dd3ef0577d25b2d59863603abe5750d0c231George Mount}
139de38dd3ef0577d25b2d59863603abe5750d0c231George Mount
14059229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval BindingTarget.constructorParamName by lazyProp { target : BindingTarget ->
14159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    target.model.getConstructorParamName(target.readableName)
142d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
143d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
144019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar// not necessarily unique. Uniqueness is decided per scope
14559229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval Expr.readableName by lazyProp { expr : Expr ->
14659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    val stripped = "${expr.uniqueKey.stripNonJava()}"
14759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    L.d("readableUniqueName for [%s] %s is %s", System.identityHashCode(expr), expr.uniqueKey, stripped)
148019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    stripped
149de38dd3ef0577d25b2d59863603abe5750d0c231George Mount}
150de38dd3ef0577d25b2d59863603abe5750d0c231George Mount
15159229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval Expr.fieldName by lazyProp { expr : Expr ->
15259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    expr.model.getUniqueFieldName("m${expr.readableName.capitalize()}", false)
153d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
154d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
155d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountval InverseBinding.fieldName by lazyProp { inverseBinding : InverseBinding ->
156af146d6a8c0efcf5682d14047c06866a5548f78fYigit Boyar    val targetName = inverseBinding.target.fieldName;
157af146d6a8c0efcf5682d14047c06866a5548f78fYigit Boyar    val eventName = inverseBinding.eventAttribute.stripNonJava()
158af146d6a8c0efcf5682d14047c06866a5548f78fYigit Boyar    inverseBinding.model.getUniqueFieldName("$targetName$eventName", false)
159d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount}
160d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
16159229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval Expr.listenerClassName by lazyProp { expr : Expr ->
16259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    expr.model.getUniqueFieldName("${expr.resolvedType.simpleName}Impl", false)
163716ba89e7f459f49ea85070d4710c1d79d715298George Mount}
164716ba89e7f459f49ea85070d4710c1d79d715298George Mount
16559229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval Expr.oldValueName by lazyProp { expr : Expr ->
16659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    expr.model.getUniqueFieldName("mOld${expr.readableName.capitalize()}", false)
16720c7182163d99575d382e065f5a5fe45ed6b87e2George Mount}
16820c7182163d99575d382e065f5a5fe45ed6b87e2George Mount
16959229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval Expr.executePendingLocalName by lazyProp { expr : Expr ->
17059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    if(expr.needsLocalField) "${expr.model.ext.getUniqueName(expr.readableName, Scope.EXECUTE_PENDING_METHOD, false)}"
17109aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar    else expr.toCode().generate()
172d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
173d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
17459229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval Expr.setterName by lazyProp { expr : Expr ->
17559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    expr.model.getUniqueMethodName("set${expr.readableName.capitalize()}", true)
176d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
177d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
17859229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval Expr.onChangeName by lazyProp { expr : Expr ->
17959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    expr.model.getUniqueMethodName("onChange${expr.readableName.capitalize()}", false)
180d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
181d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
18259229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval Expr.getterName by lazyProp { expr : Expr ->
18359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    expr.model.getUniqueMethodName("get${expr.readableName.capitalize()}", true)
184d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
185d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
18659229481aec5a284d322a2ca80dff836485feb0cYigit Boyarfun Expr.isVariable() = this is IdentifierExpr && this.isDynamic
187d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
18859229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval Expr.dirtyFlagSet by lazyProp { expr : Expr ->
18959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    FlagSet(expr.invalidFlags, expr.model.flagBucketCount)
190d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
191d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
19259229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval Expr.invalidateFlagSet by lazyProp { expr : Expr ->
19359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    FlagSet(expr.id)
194d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
195d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
19659229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval Expr.shouldReadFlagSet by versionedLazy { expr : Expr ->
19759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    FlagSet(expr.shouldReadFlags, expr.model.flagBucketCount)
198d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
199d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
20059229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval Expr.shouldReadWithConditionalsFlagSet by versionedLazy { expr : Expr ->
20159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    FlagSet(expr.shouldReadFlagsWithConditionals, expr.model.flagBucketCount)
202eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar}
203eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar
20459229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval Expr.conditionalFlags by lazyProp { expr : Expr ->
205d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar    arrayListOf(FlagSet(expr.getRequirementFlagIndex(false)),
206d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar            FlagSet(expr.getRequirementFlagIndex(true)))
207d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
208d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
20959229481aec5a284d322a2ca80dff836485feb0cYigit Boyarval LayoutBinder.requiredComponent by lazyProp { layoutBinder: LayoutBinder ->
210d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    val requiredFromBindings = layoutBinder.
21159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            bindingTargets.
21259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            flatMap { it.bindings }.
213d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            firstOrNull { it.bindingAdapterInstanceClass != null }?.bindingAdapterInstanceClass
214d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    val requiredFromInverse = layoutBinder.
215d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            bindingTargets.
216d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            flatMap { it.inverseBindings }.
217d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            firstOrNull { it.bindingAdapterInstanceClass != null }?.bindingAdapterInstanceClass
218d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    requiredFromBindings ?: requiredFromInverse
219e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount}
220e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount
221d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun Expr.getRequirementFlagSet(expected : Boolean) : FlagSet = conditionalFlags[if(expected) 1 else 0]
222d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
223d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun FlagSet.notEmpty(cb : (suffix : String, value : Long) -> Unit) {
224d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    buckets.withIndex().forEach {
225d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (it.value != 0L) {
226d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            cb(getWordSuffix(it.index), buckets[it.index])
227d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
228d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
229d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
230d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
23159229481aec5a284d322a2ca80dff836485feb0cYigit Boyarfun getWordSuffix(wordIndex : Int) : String {
23259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    return if(wordIndex == 0) "" else "_$wordIndex"
233d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
234d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
235d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun FlagSet.localValue(bucketIndex : Int) =
23659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        if (localName == null) binaryCode(bucketIndex)
23759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        else "$localName${getWordSuffix(bucketIndex)}"
238d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
239d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyarfun FlagSet.binaryCode(bucketIndex : Int) = longToBinary(buckets[bucketIndex])
240d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar
241d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar
24259229481aec5a284d322a2ca80dff836485feb0cYigit Boyarfun longToBinary(l : Long) = "0x${java.lang.Long.toHexString(l)}L"
243d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
244d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun <T> FlagSet.mapOr(other : FlagSet, cb : (suffix : String, index : Int) -> T) : List<T> {
24559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    val min = Math.min(buckets.size, other.buckets.size)
246d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    val result = arrayListOf<T>()
247d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    for (i in 0..(min - 1)) {
248d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // if these two can match by any chance, call the callback
249d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (intersect(other, i)) {
250d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            result.add(cb(getWordSuffix(i), i))
251d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
252d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
253d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    return result
254d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
255d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
25696e1c821dd446d1ed78f8ae61131550588f60a24George Mountfun indexFromTag(tag : String) : kotlin.Int {
25796e1c821dd446d1ed78f8ae61131550588f60a24George Mount    val startIndex : kotlin.Int
2587ff60c24c6de7ba0c674fe65a82ad4a88dab2e5dGeorge Mount    if (tag.startsWith("binding_")) {
25959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        startIndex = "binding_".length;
26096e1c821dd446d1ed78f8ae61131550588f60a24George Mount    } else {
26196e1c821dd446d1ed78f8ae61131550588f60a24George Mount        startIndex = tag.lastIndexOf('_') + 1
26296e1c821dd446d1ed78f8ae61131550588f60a24George Mount    }
26396e1c821dd446d1ed78f8ae61131550588f60a24George Mount    return Integer.parseInt(tag.substring(startIndex))
26496e1c821dd446d1ed78f8ae61131550588f60a24George Mount}
26596e1c821dd446d1ed78f8ae61131550588f60a24George Mount
26643596c2b2997e40b709627419732100d78a62ff0Yigit Boyarclass LayoutBinderWriter(val layoutBinder : LayoutBinder) {
26759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    val model = layoutBinder.model
26834a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount    val indices = HashMap<BindingTarget, kotlin.Int>()
26959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    val mDirtyFlags by lazy {
27059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        val fs = FlagSet(BitSet(), model.flagBucketCount);
27143596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        Arrays.fill(fs.buckets, -1)
27259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        fs.isDynamic = true
27343596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        model.localizeFlag(fs, "mDirtyFlags")
27443596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        fs
275d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
276d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
27759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    val className = layoutBinder.implementationName
278d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
27959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    val baseClassName = "${layoutBinder.className}"
280d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
28159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    val includedBinders by lazy {
28259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        layoutBinder.bindingTargets.filter { it.isBinder }
2837551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar    }
2847551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar
28559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    val variables by lazy {
28659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        model.exprMap.values.filterIsInstance(IdentifierExpr::class.java).filter { it.isVariable() }
28743596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    }
288d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
28959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    val usedVariables by lazy {
29059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        variables.filter {it.isUsed }
2915bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    }
292d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
29396e1c821dd446d1ed78f8ae61131550588f60a24George Mount    public fun write(minSdk : kotlin.Int) : String  {
2945bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        layoutBinder.resolveWhichExpressionsAreUsed()
29534a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        calculateIndices();
29659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        return kcode("package ${layoutBinder.`package`};") {
29759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            nl("import ${layoutBinder.modulePackage}.R;")
29859229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            nl("import ${layoutBinder.modulePackage}.BR;")
2995bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("import android.view.View;")
300dea555cf42dc3583604699c8c018d22681f56166George Mount            val classDeclaration : String
301dea555cf42dc3583604699c8c018d22681f56166George Mount            if (layoutBinder.hasVariations()) {
30259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                classDeclaration = "$className extends $baseClassName"
303dea555cf42dc3583604699c8c018d22681f56166George Mount            } else {
30459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                classDeclaration = "$className extends android.databinding.ViewDataBinding"
305dea555cf42dc3583604699c8c018d22681f56166George Mount            }
30659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            nl("public class $classDeclaration {") {
3074c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab(declareIncludeViews())
3085bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareViews())
3095bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareVariables())
31020c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                tab(declareBoundValues())
311716ba89e7f459f49ea85070d4710c1d79d715298George Mount                tab(declareListeners())
312d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                tab(declareInverseBindingImpls());
31396e1c821dd446d1ed78f8ae61131550588f60a24George Mount                tab(declareConstructor(minSdk))
3145bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareInvalidateAll())
315447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                tab(declareHasPendingBindings())
3165bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareSetVariable())
3175bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(variableSettersAndGetters())
3185bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(onFieldChange())
3195bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
3204c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab(executePendingBindings())
3215bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
322716ba89e7f459f49ea85070d4710c1d79d715298George Mount                tab(declareListenerImpls())
3235bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareDirtyFlags())
324dea555cf42dc3583604699c8c018d22681f56166George Mount                if (!layoutBinder.hasVariations()) {
325dea555cf42dc3583604699c8c018d22681f56166George Mount                    tab(declareFactories())
326dea555cf42dc3583604699c8c018d22681f56166George Mount                }
3275bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            }
3285bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("}")
3295bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            tab(flagMapping())
3305bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            tab("//end")
3315bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        }.generate()
3325bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    }
33334a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount    fun calculateIndices() : Unit {
33459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        val taggedViews = layoutBinder.bindingTargets.filter{
33559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            it.isUsed && it.tag != null && !it.isBinder
33634a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        }
33796e1c821dd446d1ed78f8ae61131550588f60a24George Mount        taggedViews.forEach {
33859229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            indices.put(it, indexFromTag(it.tag))
33996e1c821dd446d1ed78f8ae61131550588f60a24George Mount        }
34096e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val indexStart = maxIndex() + 1
34159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        layoutBinder.bindingTargets.filter{
34259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            it.isUsed && !taggedViews.contains(it)
34396e1c821dd446d1ed78f8ae61131550588f60a24George Mount        }.withIndex().forEach {
34496e1c821dd446d1ed78f8ae61131550588f60a24George Mount            indices.put(it.value, it.index + indexStart)
34534a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        }
34634a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount    }
3474c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount    fun declareIncludeViews() = kcode("") {
348239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount        nl("private static final android.databinding.ViewDataBinding.IncludedLayouts sIncludes;")
3494c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount        nl("private static final android.util.SparseIntArray sViewsWithIds;")
3504c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount        nl("static {") {
35159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            val hasBinders = layoutBinder.bindingTargets.firstOrNull{ it.isUsed && it.isBinder } != null
3524c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            if (!hasBinders) {
3534c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab("sIncludes = null;")
35400da715547ee7d5d38a3b8576090ca427a94daa5George Mount            } else {
35559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                val numBindings = layoutBinder.bindingTargets.filter{ it.isUsed }.count()
35659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                tab("sIncludes = new android.databinding.ViewDataBinding.IncludedLayouts($numBindings);")
35796e1c821dd446d1ed78f8ae61131550588f60a24George Mount                val includeMap = HashMap<BindingTarget, ArrayList<BindingTarget>>()
35859229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                layoutBinder.bindingTargets.filter{ it.isUsed && it.isBinder }.forEach {
35959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    val includeTag = it.tag;
36059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    val parent = layoutBinder.bindingTargets.firstOrNull {
36159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        it.isUsed && !it.isBinder && includeTag.equals(it.tag)
36259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    } ?: throw IllegalStateException("Could not find parent of include file")
36359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    var list = includeMap[parent]
36496e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    if (list == null) {
36596e1c821dd446d1ed78f8ae61131550588f60a24George Mount                        list = ArrayList<BindingTarget>()
36696e1c821dd446d1ed78f8ae61131550588f60a24George Mount                        includeMap.put(parent, list)
36796e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    }
36896e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    list.add(it)
3694c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                }
37096e1c821dd446d1ed78f8ae61131550588f60a24George Mount
37159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                includeMap.keys.forEach {
37259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    val index = indices[it]
37359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    tab("sIncludes.setIncludes($index, ") {
374239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        tab ("new String[] {${
37559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        includeMap[it]!!.map {
37659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                            "\"${it.includedLayout}\""
377239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        }.joinToString(", ")
378239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        }},")
379239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        tab("new int[] {${
38059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        includeMap[it]!!.map {
38159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                            "${indices[it]}"
382239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        }.joinToString(", ")
383239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        }},")
384239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        tab("new int[] {${
38559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        includeMap[it]!!.map {
38659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                            "R.layout.${it.includedLayout}"
387239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        }.joinToString(", ")
388239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        }});")
38996e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    }
39096e1c821dd446d1ed78f8ae61131550588f60a24George Mount                }
39196e1c821dd446d1ed78f8ae61131550588f60a24George Mount            }
39259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            val viewsWithIds = layoutBinder.bindingTargets.filter {
39359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                it.isUsed && !it.isBinder && (!it.supportsTag() || (it.id != null && it.tag == null))
39400da715547ee7d5d38a3b8576090ca427a94daa5George Mount            }
39596e1c821dd446d1ed78f8ae61131550588f60a24George Mount            if (viewsWithIds.isEmpty()) {
3964c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab("sViewsWithIds = null;")
39700da715547ee7d5d38a3b8576090ca427a94daa5George Mount            } else {
3984c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab("sViewsWithIds = new android.util.SparseIntArray();")
39996e1c821dd446d1ed78f8ae61131550588f60a24George Mount                viewsWithIds.forEach {
40059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    tab("sViewsWithIds.put(${it.androidId}, ${indices[it]});")
4014c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                }
40200da715547ee7d5d38a3b8576090ca427a94daa5George Mount            }
4034c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount        }
4044c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount        nl("}")
4054c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount    }
40696e1c821dd446d1ed78f8ae61131550588f60a24George Mount
40796e1c821dd446d1ed78f8ae61131550588f60a24George Mount    fun maxIndex() : kotlin.Int {
40859229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        val maxIndex = indices.values.max()
40996e1c821dd446d1ed78f8ae61131550588f60a24George Mount        if (maxIndex == null) {
41096e1c821dd446d1ed78f8ae61131550588f60a24George Mount            return -1
41196e1c821dd446d1ed78f8ae61131550588f60a24George Mount        } else {
41296e1c821dd446d1ed78f8ae61131550588f60a24George Mount            return maxIndex
41396e1c821dd446d1ed78f8ae61131550588f60a24George Mount        }
41496e1c821dd446d1ed78f8ae61131550588f60a24George Mount    }
41596e1c821dd446d1ed78f8ae61131550588f60a24George Mount
41696e1c821dd446d1ed78f8ae61131550588f60a24George Mount    fun declareConstructor(minSdk : kotlin.Int) = kcode("") {
41796e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val bindingCount = maxIndex() + 1
41896e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val parameterType : String
41996e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val superParam : String
42059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        if (layoutBinder.isMerge) {
42196e1c821dd446d1ed78f8ae61131550588f60a24George Mount            parameterType = "View[]"
42296e1c821dd446d1ed78f8ae61131550588f60a24George Mount            superParam = "root[0]"
42396e1c821dd446d1ed78f8ae61131550588f60a24George Mount        } else {
42496e1c821dd446d1ed78f8ae61131550588f60a24George Mount            parameterType = "View"
42596e1c821dd446d1ed78f8ae61131550588f60a24George Mount            superParam = "root"
42696e1c821dd446d1ed78f8ae61131550588f60a24George Mount        }
42796e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val rootTagsSupported = minSdk >= 14
428dea555cf42dc3583604699c8c018d22681f56166George Mount        if (layoutBinder.hasVariations()) {
429dea555cf42dc3583604699c8c018d22681f56166George Mount            nl("")
43059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            nl("public $className(android.databinding.DataBindingComponent bindingComponent, $parameterType root) {") {
43159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                tab("this(bindingComponent, $superParam, mapBindings(bindingComponent, root, $bindingCount, sIncludes, sViewsWithIds));")
432dea555cf42dc3583604699c8c018d22681f56166George Mount            }
433dea555cf42dc3583604699c8c018d22681f56166George Mount            nl("}")
43459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            nl("private $className(android.databinding.DataBindingComponent bindingComponent, $parameterType root, Object[] bindings) {") {
43559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                tab("super(bindingComponent, $superParam, ${model.observables.size}") {
43659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    layoutBinder.sortedTargets.filter { it.id != null }.forEach {
437dea555cf42dc3583604699c8c018d22681f56166George Mount                        tab(", ${fieldConversion(it)}")
43834a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                    }
439dea555cf42dc3583604699c8c018d22681f56166George Mount                    tab(");")
44034a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                }
44134a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            }
442dea555cf42dc3583604699c8c018d22681f56166George Mount        } else {
44359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            nl("public $baseClassName(android.databinding.DataBindingComponent bindingComponent, $parameterType root) {") {
44459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                tab("super(bindingComponent, $superParam, ${model.observables.size});")
44559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                tab("final Object[] bindings = mapBindings(bindingComponent, root, $bindingCount, sIncludes, sViewsWithIds);")
446dea555cf42dc3583604699c8c018d22681f56166George Mount            }
447dea555cf42dc3583604699c8c018d22681f56166George Mount        }
448e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        if (layoutBinder.requiredComponent != null) {
449e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            tab("ensureBindingComponentIsNotNull(${layoutBinder.requiredComponent}.class);")
450e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        }
45159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        val taggedViews = layoutBinder.sortedTargets.filter{it.isUsed }
452dea555cf42dc3583604699c8c018d22681f56166George Mount        taggedViews.forEach {
45359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            if (!layoutBinder.hasVariations() || it.id == null) {
454dea555cf42dc3583604699c8c018d22681f56166George Mount                tab("this.${it.fieldName} = ${fieldConversion(it)};")
455dea555cf42dc3583604699c8c018d22681f56166George Mount            }
45659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            if (!it.isBinder) {
45759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                if (it.resolvedType != null && it.resolvedType.extendsViewStub()) {
458de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                    tab("this.${it.fieldName}.setContainingBinding(this);")
459de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                }
46059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                if (it.supportsTag() && it.tag != null &&
46159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        (rootTagsSupported || it.tag.startsWith("binding_"))) {
46259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    val originalTag = it.originalTag;
463dea555cf42dc3583604699c8c018d22681f56166George Mount                    var tagValue = "null"
46492a428505b9102bc0560d2d5be1768da097909c2George Mount                    if (originalTag != null && !originalTag.startsWith("@{")) {
46559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        tagValue = "\"$originalTag\""
466dea555cf42dc3583604699c8c018d22681f56166George Mount                        if (originalTag.startsWith("@")) {
46759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                            var packageName = layoutBinder.modulePackage
468dea555cf42dc3583604699c8c018d22681f56166George Mount                            if (originalTag.startsWith("@android:")) {
469dea555cf42dc3583604699c8c018d22681f56166George Mount                                packageName = "android"
47000da715547ee7d5d38a3b8576090ca427a94daa5George Mount                            }
471dea555cf42dc3583604699c8c018d22681f56166George Mount                            val slashIndex = originalTag.indexOf('/')
472dea555cf42dc3583604699c8c018d22681f56166George Mount                            val resourceId = originalTag.substring(slashIndex + 1)
47359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                            tagValue = "root.getResources().getString($packageName.R.string.$resourceId)"
47400da715547ee7d5d38a3b8576090ca427a94daa5George Mount                        }
47500da715547ee7d5d38a3b8576090ca427a94daa5George Mount                    }
47659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    tab("this.${it.fieldName}.setTag($tagValue);")
47759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                } else if (it.tag != null && !it.tag.startsWith("binding_") &&
47859229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    it.originalTag != null) {
47959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    L.e(ErrorMessages.ROOT_TAG_NOT_SUPPORTED, it.originalTag)
4807551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar                }
481d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
482d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
4834d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount        tab("setRootTag(root);")
484dea555cf42dc3583604699c8c018d22681f56166George Mount        tab("invalidateAll();");
4850fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("}")
486d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
487d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
488dea555cf42dc3583604699c8c018d22681f56166George Mount    fun fieldConversion(target : BindingTarget) : String {
48959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        if (!target.isUsed) {
490dea555cf42dc3583604699c8c018d22681f56166George Mount            return "null"
491dea555cf42dc3583604699c8c018d22681f56166George Mount        } else {
49259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            val index = indices[target] ?: throw IllegalStateException("Unknown binding target")
49359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            val variableName = "bindings[$index]"
494dea555cf42dc3583604699c8c018d22681f56166George Mount            return target.superConversion(variableName)
495dea555cf42dc3583604699c8c018d22681f56166George Mount        }
496dea555cf42dc3583604699c8c018d22681f56166George Mount    }
497dea555cf42dc3583604699c8c018d22681f56166George Mount
498d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareInvalidateAll() = kcode("") {
4997551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar        nl("@Override")
5007551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar        nl("public void invalidateAll() {") {
50159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            val fs = FlagSet(layoutBinder.model.invalidateAnyBitSet,
50259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    layoutBinder.model.flagBucketCount);
5031c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar            tab("synchronized(this) {") {
50459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                for (i in (0..(mDirtyFlags.buckets.size - 1))) {
5051c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                    tab("${mDirtyFlags.localValue(i)} = ${fs.localValue(i)};")
5061c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                }
5071c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar            } tab("}")
50859229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            includedBinders.filter{it.isUsed }.forEach { binder ->
5097551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar                tab("${binder.fieldName}.invalidateAll();")
5107551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar            }
5112f64c44e4fa296cf658ca986c095eab62f82a31dYigit Boyar            tab("requestRebind();");
512d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
5130fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("}")
514d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
515d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
516447971abca811b11b8c1d8e7bfaa294856d03c16George Mount    fun declareHasPendingBindings()  = kcode("") {
517447971abca811b11b8c1d8e7bfaa294856d03c16George Mount        nl("@Override")
518447971abca811b11b8c1d8e7bfaa294856d03c16George Mount        nl("public boolean hasPendingBindings() {") {
51959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            if (mDirtyFlags.buckets.size > 0) {
520447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                tab("synchronized(this) {") {
52159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    val flagCheck = 0.rangeTo(mDirtyFlags.buckets.size - 1).map {
522447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                            "${mDirtyFlags.localValue(it)} != 0"
523447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                    }.joinToString(" || ")
52459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    tab("if ($flagCheck) {") {
525447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                        tab("return true;")
526447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                    }
527447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                    tab("}")
528447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                }
529447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                tab("}")
530447971abca811b11b8c1d8e7bfaa294856d03c16George Mount            }
53159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            includedBinders.filter{it.isUsed }.forEach { binder ->
532447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                tab("if (${binder.fieldName}.hasPendingBindings()) {") {
533447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                    tab("return true;")
534447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                }
535447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                tab("}")
536447971abca811b11b8c1d8e7bfaa294856d03c16George Mount            }
537447971abca811b11b8c1d8e7bfaa294856d03c16George Mount            tab("return false;")
538447971abca811b11b8c1d8e7bfaa294856d03c16George Mount        }
539447971abca811b11b8c1d8e7bfaa294856d03c16George Mount        nl("}")
540447971abca811b11b8c1d8e7bfaa294856d03c16George Mount    }
541447971abca811b11b8c1d8e7bfaa294856d03c16George Mount
542d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareSetVariable() = kcode("") {
5430fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("public boolean setVariable(int variableId, Object variable) {") {
544d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("switch(variableId) {") {
5455bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                usedVariables.forEach {
54659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    tab ("case ${it.name.br()} :") {
54759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        tab("${it.setterName}((${it.resolvedType.toJavaCode()}) variable);")
548d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        tab("return true;")
549d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
550d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
55159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                val declaredOnly = variables.filter { !it.isUsed && it.isDeclared };
55223910cf498c35704a03ba4f3889de2ab97ccbe21George Mount                declaredOnly.forEachIndexed { i, identifierExpr ->
55359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    tab ("case ${identifierExpr.name.br()} :") {
55459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        if (i == declaredOnly.size - 1) {
55523910cf498c35704a03ba4f3889de2ab97ccbe21George Mount                            tab("return true;")
55623910cf498c35704a03ba4f3889de2ab97ccbe21George Mount                        }
55723910cf498c35704a03ba4f3889de2ab97ccbe21George Mount                    }
55823910cf498c35704a03ba4f3889de2ab97ccbe21George Mount                }
559d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
560d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("}")
561d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("return false;")
562d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
5630fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("}")
564d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
565d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
566d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun variableSettersAndGetters() = kcode("") {
56759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        variables.filterNot{it.isUsed }.forEach {
56859229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            nl("public void ${it.setterName}(${it.resolvedType.toJavaCode()} ${it.readableName}) {") {
5695bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab("// not used, ignore")
5705bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            }
5715bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("}")
5725bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("")
57359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            nl("public ${it.resolvedType.toJavaCode()} ${it.getterName}() {") {
57459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                tab("return ${it.defaultValue};")
5755bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            }
5765bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("}")
5775bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        }
5785bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        usedVariables.forEach {
57959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            if (it.userDefinedType != null) {
58059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                nl("public void ${it.setterName}(${it.resolvedType.toJavaCode()} ${it.readableName}) {") {
58159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    if (it.isObservable) {
58259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        tab("updateRegistration(${it.id}, ${it.readableName});");
58318243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    }
584019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                    tab("this.${it.fieldName} = ${it.readableName};")
58518243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    // set dirty flags!
58618243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    val flagSet = it.invalidateFlagSet
5871c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                    tab("synchronized(this) {") {
5881c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                        mDirtyFlags.mapOr(flagSet) { suffix, index ->
58959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                            tab("${mDirtyFlags.localName}$suffix |= ${flagSet.localValue(index)};")
5901c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                        }
5911c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                    } tab ("}")
592d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    // TODO: Remove this condition after releasing version 1.1 of SDK
593d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    if (ModelAnalyzer.getInstance().findClass("android.databinding.ViewDataBinding", null).isObservable) {
594d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                        tab("notifyPropertyChanged(${it.name.br()});")
595d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    }
59618243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    tab("super.requestRebind();")
597d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
59818243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                nl("}")
59918243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                nl("")
60059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                nl("public ${it.resolvedType.toJavaCode()} ${it.getterName}() {") {
60118243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    tab("return ${it.fieldName};")
602d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
60318243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                nl("}")
604d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
605d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
606d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
607d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
608d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun onFieldChange() = kcode("") {
60934a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        nl("@Override")
61034a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        nl("protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {") {
6114c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            tab("switch (localFieldId) {") {
61259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                model.observables.forEach {
61359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    tab("case ${it.id} :") {
61459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        tab("return ${it.onChangeName}((${it.resolvedType.toJavaCode()}) object, fieldId);")
615d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
616d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
617d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
618d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("}")
619d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("return false;")
620d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
62134a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        nl("}")
62234a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        nl("")
623d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
62459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        model.observables.forEach {
62559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            nl("private boolean ${it.onChangeName}(${it.resolvedType.toJavaCode()} ${it.readableName}, int fieldId) {") {
626d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                tab("switch (fieldId) {", {
62759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    val accessedFields: List<FieldAccessExpr> = it.parents.filterIsInstance(FieldAccessExpr::class.java)
628c4a07bddb4dd5c3bfbecf4d87909c5b447ae56dcGeorge Mount                    accessedFields.filter { it.hasBindableAnnotations() }
62988ce44ccc65e74a8553244ca246cc9f4c48483e0Yigit Boyar                            .groupBy { it.brName }
630d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            .forEach {
63188ce44ccc65e74a8553244ca246cc9f4c48483e0Yigit Boyar                                // If two expressions look different but resolve to the same method,
63288ce44ccc65e74a8553244ca246cc9f4c48483e0Yigit Boyar                                // we are not yet able to merge them. This is why we merge their
63388ce44ccc65e74a8553244ca246cc9f4c48483e0Yigit Boyar                                // flags below.
63488ce44ccc65e74a8553244ca246cc9f4c48483e0Yigit Boyar                                tab("case ${it.key}:") {
6351c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                                    tab("synchronized(this) {") {
63688ce44ccc65e74a8553244ca246cc9f4c48483e0Yigit Boyar                                        val flagSet = it.value.foldRight(FlagSet()) { l, r -> l.invalidateFlagSet.or(r) }
63788ce44ccc65e74a8553244ca246cc9f4c48483e0Yigit Boyar
63888ce44ccc65e74a8553244ca246cc9f4c48483e0Yigit Boyar                                        mDirtyFlags.mapOr(flagSet) { suffix, index ->
63988ce44ccc65e74a8553244ca246cc9f4c48483e0Yigit Boyar                                            tab("${mDirtyFlags.localValue(index)} |= ${flagSet.localValue(index)};")
6401c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                                        }
6411c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                                    } tab("}")
642d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                                    tab("return true;")
643d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                                }
644d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
645d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            }
64643596c2b2997e40b709627419732100d78a62ff0Yigit Boyar                    tab("case ${"".br()}:") {
647d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        val flagSet = it.invalidateFlagSet
6481c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                        tab("synchronized(this) {") {
6491c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                            mDirtyFlags.mapOr(flagSet) { suffix, index ->
65059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                                tab("${mDirtyFlags.localName}$suffix |= ${flagSet.localValue(index)};")
6511c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                            }
6521c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                        } tab("}")
653d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        tab("return true;")
654d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
655d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
656d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                })
657d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                tab("}")
658d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                tab("return false;")
659d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
66034a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            nl("}")
66134a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            nl("")
662d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
663d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
664d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
665d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareViews() = kcode("// views") {
666dea555cf42dc3583604699c8c018d22681f56166George Mount        val oneLayout = !layoutBinder.hasVariations();
66759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        layoutBinder.sortedTargets.filter {it.isUsed && (oneLayout || it.id == null)}.forEach {
668dea555cf42dc3583604699c8c018d22681f56166George Mount            val access : String
66959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            if (oneLayout && it.id != null) {
670dea555cf42dc3583604699c8c018d22681f56166George Mount                access = "public"
671dea555cf42dc3583604699c8c018d22681f56166George Mount            } else {
672dea555cf42dc3583604699c8c018d22681f56166George Mount                access = "private"
673dea555cf42dc3583604699c8c018d22681f56166George Mount            }
67459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            nl("$access final ${it.interfaceClass} ${it.fieldName};")
675d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
676d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
677d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
678d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareVariables() = kcode("// variables") {
6795bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        usedVariables.forEach {
68059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            nl("private ${it.resolvedType.toJavaCode()} ${it.fieldName};")
681d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
682d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
683d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
68420c7182163d99575d382e065f5a5fe45ed6b87e2George Mount    fun declareBoundValues() = kcode("// values") {
68559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        layoutBinder.sortedTargets.filter { it.isUsed }
68659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                .flatMap { it.bindings }
68720c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                .filter { it.requiresOldValue() }
68859229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                .flatMap{ it.componentExpressions.toArrayList() }
68920c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                .groupBy { it }
69020c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                .forEach {
69159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    val expr = it.key
69259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    nl("private ${expr.resolvedType.toJavaCode()} ${expr.oldValueName};")
69320c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                }
69420c7182163d99575d382e065f5a5fe45ed6b87e2George Mount    }
69520c7182163d99575d382e065f5a5fe45ed6b87e2George Mount
696716ba89e7f459f49ea85070d4710c1d79d715298George Mount    fun declareListeners() = kcode("// listeners") {
69759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        model.exprMap.values.filter {
698793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            it is ListenerExpr
699716ba89e7f459f49ea85070d4710c1d79d715298George Mount        }.groupBy { it }.forEach {
700793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            val expr = it.key as ListenerExpr
701716ba89e7f459f49ea85070d4710c1d79d715298George Mount            nl("private ${expr.listenerClassName} ${expr.fieldName};")
702716ba89e7f459f49ea85070d4710c1d79d715298George Mount        }
703716ba89e7f459f49ea85070d4710c1d79d715298George Mount    }
704716ba89e7f459f49ea85070d4710c1d79d715298George Mount
705d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    fun declareInverseBindingImpls() = kcode("// Inverse Binding Event Handlers") {
706af146d6a8c0efcf5682d14047c06866a5548f78fYigit Boyar        layoutBinder.sortedTargets.filter { it.isUsed }.forEach { target ->
707af146d6a8c0efcf5682d14047c06866a5548f78fYigit Boyar            target.inverseBindings.forEach { inverseBinding ->
708d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                val className : String
709d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                val param : String
710af146d6a8c0efcf5682d14047c06866a5548f78fYigit Boyar                if (inverseBinding.isOnBinder) {
711d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    className = "android.databinding.ViewDataBinding.PropertyChangedInverseListener"
712d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    param = "BR.${inverseBinding.eventAttribute}"
713d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                } else {
714d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    className = "android.databinding.InverseBindingListener"
715d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    param = ""
716d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                }
717af146d6a8c0efcf5682d14047c06866a5548f78fYigit Boyar                nl("private $className ${inverseBinding.fieldName} = new $className($param) {") {
718d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    tab("@Override")
719d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    tab("public void onChange() {") {
720d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                        tab(inverseBinding.toJavaCode("mBindingComponent", mDirtyFlags)).app(";");
721d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    }
722d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                    tab("}")
723d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                }
724d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount                nl("};")
725d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            }
726d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        }
727d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
728d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareDirtyFlags() = kcode("// dirty flag") {
729d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        model.ext.localizedFlags.forEach { flag ->
730de38dd3ef0577d25b2d59863603abe5750d0c231George Mount            flag.notEmpty { suffix, value ->
7310fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                nl("private")
73259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                app(" ", if(flag.isDynamic) null else "static final");
73359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                app(" ", " ${flag.type} ${flag.localName}$suffix = ${longToBinary(value)};")
734d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
735d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
736d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
737d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
738d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun flagMapping() = kcode("/* flag mapping") {
73959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar        if (model.flagMapping != null) {
74059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            val mapping = model.flagMapping
741d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (i in mapping.indices) {
742d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                tab("flag $i: ${mapping[i]}")
743d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
744d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
745d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        nl("flag mapping end*/")
746d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
747d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
7484c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount    fun executePendingBindings() = kcode("") {
7490fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("@Override")
750e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount        nl("protected void executeBindings() {") {
751d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            val tmpDirtyFlags = FlagSet(mDirtyFlags.buckets)
75259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            tmpDirtyFlags.localName = "dirtyFlags";
75359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            for (i in (0..mDirtyFlags.buckets.size - 1)) {
7541c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                tab("${tmpDirtyFlags.type} ${tmpDirtyFlags.localValue(i)} = 0;")
755d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
7561c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar            tab("synchronized(this) {") {
75759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                for (i in (0..mDirtyFlags.buckets.size - 1)) {
7581c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                    tab("${tmpDirtyFlags.localValue(i)} = ${mDirtyFlags.localValue(i)};")
7591c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                    tab("${mDirtyFlags.localValue(i)} = 0;")
7601c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                }
7611c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar            } tab("}")
76259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            model.pendingExpressions.filter { it.needsLocalField }.forEach {
76359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                tab("${it.resolvedType.toJavaCode()} ${it.executePendingLocalName} = ${if (it.isVariable()) it.fieldName else it.defaultValue};")
764d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
765b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar            L.d("writing executePendingBindings for %s", className)
766d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            do {
76759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                val batch = ExprModel.filterShouldRead(model.pendingExpressions).toArrayList()
768a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                val justRead = arrayListOf<Expr>()
769b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar                L.d("batch: %s", batch)
770d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                while (!batch.none()) {
771a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    val readNow = batch.filter { it.shouldReadNow(justRead) }
772d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    if (readNow.isEmpty()) {
773d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        throw IllegalStateException("do not know what I can read. bailing out ${batch.joinToString("\n")}")
774d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
77559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    L.d("new read now. batch size: %d, readNow size: %d", batch.size, readNow.size)
776a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    nl(readWithDependants(readNow, justRead, batch, tmpDirtyFlags))
777a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    batch.removeAll(justRead)
778d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
7790fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                tab("// batch finished")
780a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            } while (model.markBitsRead())
7817b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar            // verify everything is read.
78259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            val batch = ExprModel.filterShouldRead(model.pendingExpressions).toArrayList()
7837b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar            if (batch.isNotEmpty()) {
7847b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar                L.e("could not generate code for %s. This might be caused by circular dependencies."
78559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        + "Please report on b.android.com. %d %s %s", layoutBinder.layoutname,
78659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        batch.size, batch[0], batch[0].toCode().generate())
7877b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar            }
788d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            //
78959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            layoutBinder.sortedTargets.filter { it.isUsed }
79059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    .flatMap { it.bindings }
791a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    .groupBy {
79259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        "${tmpDirtyFlags.mapOr(it.expr.dirtyFlagSet) { suffix, index ->
79359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                            "(${tmpDirtyFlags.localValue(index)} & ${it.expr.dirtyFlagSet.localValue(index)}) != 0"
794a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        }.joinToString(" || ") }"
795a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    }.forEach {
796a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                tab("if (${it.key}) {") {
79759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    it.value.groupBy { Math.max(1, it.minApi) }.forEach {
798a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        val setterValues = kcode("") {
799d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            it.value.forEach { binding ->
800a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                val fieldName: String
80159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                                if (binding.target.viewClass.
80259229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                                        equals(binding.target.interfaceType)) {
80359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                                    fieldName = "this.${binding.target.fieldName}"
80434a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                                } else {
80559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                                    fieldName = "((${binding.target.viewClass}) this.${binding.target.fieldName})"
80634a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                                }
807a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                tab(binding.toJavaCode(fieldName, "this.mBindingComponent")).app(";")
808a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            }
809a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        }
810a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        tab("// api target ${it.key}")
811a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        if (it.key > 1) {
812a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            tab("if(getBuildSdkInt() >= ${it.key}) {") {
813a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                app("", setterValues)
814d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            }
815a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            tab("}")
816a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        } else {
817a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            app("", setterValues)
81820c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                        }
81920c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                    }
820a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                }
821a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                tab("}")
822a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            }
823a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount
82420c7182163d99575d382e065f5a5fe45ed6b87e2George Mount
82559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            layoutBinder.sortedTargets.filter { it.isUsed }
82659229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    .flatMap { it.bindings }
82720c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                    .filter { it.requiresOldValue() }
82859229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    .groupBy {"${tmpDirtyFlags.mapOr(it.expr.dirtyFlagSet) { suffix, index ->
82959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        "(${tmpDirtyFlags.localValue(index)} & ${it.expr.dirtyFlagSet.localValue(index)}) != 0"
830a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    }.joinToString(" || ")
831a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    }"}.forEach {
832a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                tab("if (${it.key}) {") {
83359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                    it.value.groupBy { it.expr }.map { it.value.first() }.forEach {
83459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        it.componentExpressions.forEach { expr ->
835a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            tab("this.${expr.oldValueName} = ${expr.toCode().generate()};")
836d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        }
837d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
838a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                }
839a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                tab("}")
840a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            }
84159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            includedBinders.filter{it.isUsed }.forEach { binder ->
8424c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab("${binder.fieldName}.executePendingBindings();")
8437551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar            }
84459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            layoutBinder.sortedTargets.filter{
84559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                it.isUsed && it.resolvedType != null && it.resolvedType.extendsViewStub()
846de38dd3ef0577d25b2d59863603abe5750d0c231George Mount            }.forEach {
847de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                tab("if (${it.fieldName}.getBinding() != null) {") {
848de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                    tab("${it.fieldName}.getBinding().executePendingBindings();")
849de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                }
850de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                tab("}")
851de38dd3ef0577d25b2d59863603abe5750d0c231George Mount            }
852d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
8530fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("}")
854d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
855d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
856a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount    fun readWithDependants(expressionList: List<Expr>, justRead: MutableList<Expr>,
857a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            batch: MutableList<Expr>, tmpDirtyFlags: FlagSet,
858a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            inheritedFlags: FlagSet? = null) : KCode = kcode("") {
859a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount        expressionList.groupBy { it.shouldReadFlagSet }.forEach {
860a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            val flagSet = it.key
861a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            val needsIfWrapper = inheritedFlags == null || !flagSet.bitsEqual(inheritedFlags)
862a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            val expressions = it.value
863a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            val ifClause = "if (${tmpDirtyFlags.mapOr(flagSet){ suffix, index ->
864a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                "(${tmpDirtyFlags.localValue(index)} & ${flagSet.localValue(index)}) != 0"
865a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            }.joinToString(" || ")
866a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            })"
867a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            val readCode = kcode("") {
868a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                val dependants = ArrayList<Expr>()
869a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                expressions.groupBy { condition(it) }.forEach {
870a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    val condition = it.key
8710b6d118e6eeb3bc100fc6a6e66016ab812cb2783Yigit Boyar                    val assignedValues = it.value.filter { it.needsLocalField && !it.isVariable() }
872a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    if (!assignedValues.isEmpty()) {
873a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        val assignment = kcode("") {
874a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            assignedValues.forEach { expr: Expr ->
87559229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                                tab("// read ${expr.uniqueKey}")
876a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                tab("${expr.executePendingLocalName}").app(" = ", expr.toFullCode()).app(";")
877a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            }
878a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        }
879a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        if (condition != null) {
88059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                            tab("if ($condition) {") {
881a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                app("", assignment)
882a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            }
883a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            tab ("}")
884a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        } else {
885a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            app("", assignment)
886d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        }
88759229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        it.value.filter { it.isObservable }.forEach { expr: Expr ->
88859229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                            tab("updateRegistration(${expr.id}, ${expr.executePendingLocalName});")
8899e7a4ce47ae5f4428f7630fe03a7ad66d06177fbGeorge Mount                        }
890a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    }
891a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount
892a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    it.value.forEach { expr: Expr ->
893a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        justRead.add(expr)
89459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        L.d("%s / readWithDependants %s", className, expr.uniqueKey);
895a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        L.d("flag set:%s . inherited flags: %s. need another if: %s", flagSet, inheritedFlags, needsIfWrapper);
896a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount
897a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        // if I am the condition for an expression, set its flag
89859229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        expr.dependants.filter {
89959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                            !it.isConditional && it.dependant is TernaryExpr &&
90059229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                                    (it.dependant as TernaryExpr).pred == expr
90159229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                        }.map { it.dependant }.groupBy {
902eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                            // group by when those ternaries will be evaluated (e.g. don't set conditional flags for no reason)
90359229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                            val ternaryBitSet = it.shouldReadFlagsWithConditionals
90459229481aec5a284d322a2ca80dff836485feb0cYigit Boyar                            val isBehindTernary = ternaryBitSet.nextSetBit(model.invalidateAnyFlagIndex) == -1
905eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                            if (!isBehindTernary) {
906eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                val ternaryFlags = it.shouldReadWithConditionalsFlagSet
907eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                "if(${tmpDirtyFlags.mapOr(ternaryFlags){ suffix, index ->
908eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                    "(${tmpDirtyFlags.localValue(index)} & ${ternaryFlags.localValue(index)}) != 0"
909eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                }.joinToString(" || ")}) {"
910eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                            } else {
911eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                // TODO if it is behind a ternary, we should set it when its predicate is elevated
912eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                // Normally, this would mean that there is another code path to re-read our current expression.
913eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                // Unfortunately, this may not be true due to the coverage detection in `expr#markAsReadIfDone`, this may never happen.
914eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                // for v1.0, we'll go with always setting it and suffering an unnecessary calculation for this edge case.
915eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                // we can solve this by listening to elevation events from the model.
916eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                ""
917a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            }
918eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                        }.forEach {
919eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                            val hasAnotherIf = it.key != ""
920eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                            if (hasAnotherIf) {
921eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                tab(it.key) {
922eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                    tab("if (${expr.executePendingLocalName}) {") {
923