LayoutBinderWriter.kt revision 5d454e5f2397a3b160f081ce123b4ca7ff0fc356
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
17716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport android.databinding.tool.LayoutBinder
18fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.Expr
19fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.ExprModel
20fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.FieldAccessExpr
21716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport android.databinding.tool.expr.IdentifierExpr
22793e979f25e190162eacf46d6a4efc3efc1d2f91George Mountimport android.databinding.tool.expr.ListenerExpr
23716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport android.databinding.tool.expr.TernaryExpr
247b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyarimport android.databinding.tool.ext.androidId
257b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyarimport android.databinding.tool.ext.br
267b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyarimport android.databinding.tool.ext.joinToCamelCaseAsVar
27716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport android.databinding.tool.ext.lazy
28716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport android.databinding.tool.ext.versionedLazy
2992a428505b9102bc0560d2d5be1768da097909c2George Mountimport android.databinding.tool.processing.ErrorMessages
30fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelAnalyzer
317b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyarimport android.databinding.tool.util.L
3296e1c821dd446d1ed78f8ae61131550588f60a24George Mountimport java.util.ArrayList
33716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport java.util.Arrays
34716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport java.util.BitSet
3534a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mountimport java.util.HashMap
36716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport kotlin.properties.Delegates
3743596c2b2997e40b709627419732100d78a62ff0Yigit Boyar
38fda1703c88eb22e9f166d957d6bda2cd8d645b8fYigit Boyarfun String.stripNonJava() = this.split("[^a-zA-Z0-9]".toRegex()).map{ it.trim() }.joinToCamelCaseAsVar()
39d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
40019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarenum class Scope {
41fda1703c88eb22e9f166d957d6bda2cd8d645b8fYigit Boyar    FIELD,
42fda1703c88eb22e9f166d957d6bda2cd8d645b8fYigit Boyar    METHOD,
43fda1703c88eb22e9f166d957d6bda2cd8d645b8fYigit Boyar    FLAG,
44fda1703c88eb22e9f166d957d6bda2cd8d645b8fYigit Boyar    EXECUTE_PENDING_METHOD,
45019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    CONSTRUCTOR_PARAM
46019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar}
47019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
48d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarclass ExprModelExt {
49019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    val usedFieldNames = hashMapOf<Scope, MutableSet<String>>();
50fda1703c88eb22e9f166d957d6bda2cd8d645b8fYigit Boyar    init {
51019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        Scope.values().forEach { usedFieldNames[it] = hashSetOf<String>() }
52019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    }
53d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    val localizedFlags = arrayListOf<FlagSet>()
54d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
55d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun localizeFlag(set : FlagSet, name:String) : FlagSet {
56d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        localizedFlags.add(set)
57793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        val result = getUniqueName(name, Scope.FLAG, false)
58d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        set.setLocalName(result)
59d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return set
60d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
61d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
62793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    fun getUniqueName(base : String, scope : Scope, isPublic : kotlin.Boolean) : String {
63793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        var candidateBase = base
64793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        if (!isPublic && candidateBase.length() > 20) {
65793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            candidateBase = candidateBase.substring(0, 20);
66793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        }
67793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        var candidate = candidateBase
68d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        var i = 0
695d454e5f2397a3b160f081ce123b4ca7ff0fc356Yigit Boyar        while (usedFieldNames[scope]!!.contains(candidate)) {
70d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            i ++
71793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            candidate = candidateBase + i
72d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
735d454e5f2397a3b160f081ce123b4ca7ff0fc356Yigit Boyar        usedFieldNames[scope]!!.add(candidate)
74d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return candidate
75d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
76d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
77d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
78de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval ExprModel.ext by Delegates.lazy { target : ExprModel ->
79d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    ExprModelExt()
80d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
81d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
82793e979f25e190162eacf46d6a4efc3efc1d2f91George Mountfun ExprModel.getUniqueFieldName(base : String, isPublic : kotlin.Boolean) : String = ext.getUniqueName(base, Scope.FIELD, isPublic)
83793e979f25e190162eacf46d6a4efc3efc1d2f91George Mountfun ExprModel.getUniqueMethodName(base : String, isPublic : kotlin.Boolean) : String = ext.getUniqueName(base, Scope.METHOD, isPublic)
84793e979f25e190162eacf46d6a4efc3efc1d2f91George Mountfun ExprModel.getUniqueFlagName(base : String) : String = ext.getUniqueName(base, Scope.FLAG, false)
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
89019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar// not necessarily unique. Uniqueness is solved per scope
90019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarval BindingTarget.readableName by Delegates.lazy { target: BindingTarget ->
9100da715547ee7d5d38a3b8576090ca427a94daa5George Mount    if (target.getId() == null) {
92019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        "boundView" + indexFromTag(target.getTag())
9300da715547ee7d5d38a3b8576090ca427a94daa5George Mount    } else {
94019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        target.getId().androidId().stripNonJava()
9500da715547ee7d5d38a3b8576090ca427a94daa5George Mount    }
96d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
977551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar
98de38dd3ef0577d25b2d59863603abe5750d0c231George Mountfun BindingTarget.superConversion(variable : String) : String {
9996e1c821dd446d1ed78f8ae61131550588f60a24George Mount    if (getResolvedType() != null && getResolvedType().extendsViewStub()) {
100de38dd3ef0577d25b2d59863603abe5750d0c231George Mount        return "new android.databinding.ViewStubProxy((android.view.ViewStub) ${variable})"
101de38dd3ef0577d25b2d59863603abe5750d0c231George Mount    } else {
102de38dd3ef0577d25b2d59863603abe5750d0c231George Mount        return "(${interfaceType}) ${variable}"
103de38dd3ef0577d25b2d59863603abe5750d0c231George Mount    }
104de38dd3ef0577d25b2d59863603abe5750d0c231George Mount}
105de38dd3ef0577d25b2d59863603abe5750d0c231George Mount
106019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarval BindingTarget.fieldName : String by Delegates.lazy { target : BindingTarget ->
107019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    val name : String
108793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    val isPublic : kotlin.Boolean
109019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    if (target.getId() == null) {
110019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        name = "m${target.readableName}"
111793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        isPublic = false
112019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    } else {
113019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        name = target.readableName
114793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount        isPublic = true
11534a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount    }
116793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    target.getModel().getUniqueFieldName(name, isPublic)
117d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
118d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
119de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval BindingTarget.androidId by Delegates.lazy { target : BindingTarget ->
120fdfbbcd5ecf37d77a4b9ab1cefdebd68de71ca2bGeorge Mount    if (target.getId().startsWith("@android:id/")) {
121fdfbbcd5ecf37d77a4b9ab1cefdebd68de71ca2bGeorge Mount        "android.R.id.${target.getId().androidId()}"
122fdfbbcd5ecf37d77a4b9ab1cefdebd68de71ca2bGeorge Mount    } else {
123fdfbbcd5ecf37d77a4b9ab1cefdebd68de71ca2bGeorge Mount        "R.id.${target.getId().androidId()}"
124fdfbbcd5ecf37d77a4b9ab1cefdebd68de71ca2bGeorge Mount    }
125d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
126d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
127de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval BindingTarget.interfaceType by Delegates.lazy { target : BindingTarget ->
128de38dd3ef0577d25b2d59863603abe5750d0c231George Mount    if (target.getResolvedType() != null && target.getResolvedType().extendsViewStub()) {
129de38dd3ef0577d25b2d59863603abe5750d0c231George Mount        "android.databinding.ViewStubProxy"
130de38dd3ef0577d25b2d59863603abe5750d0c231George Mount    } else {
131de38dd3ef0577d25b2d59863603abe5750d0c231George Mount        target.getInterfaceType()
132de38dd3ef0577d25b2d59863603abe5750d0c231George Mount    }
133de38dd3ef0577d25b2d59863603abe5750d0c231George Mount}
134de38dd3ef0577d25b2d59863603abe5750d0c231George Mount
135019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarval BindingTarget.constructorParamName by Delegates.lazy { target : BindingTarget ->
136019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    target.getModel().getConstructorParamName(target.readableName)
137d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
138d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
139019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar// not necessarily unique. Uniqueness is decided per scope
140de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.readableName by Delegates.lazy { expr : Expr ->
141019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    val stripped = "${expr.getUniqueKey().stripNonJava()}"
142b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar    L.d("readableUniqueName for [%s] %s is %s", System.identityHashCode(expr), expr.getUniqueKey(), stripped)
143019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    stripped
144de38dd3ef0577d25b2d59863603abe5750d0c231George Mount}
145de38dd3ef0577d25b2d59863603abe5750d0c231George Mount
146de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.fieldName by Delegates.lazy { expr : Expr ->
147793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    expr.getModel().getUniqueFieldName("m${expr.readableName.capitalize()}", false)
148d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
149d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
150716ba89e7f459f49ea85070d4710c1d79d715298George Mountval Expr.listenerClassName by Delegates.lazy { expr : Expr ->
151793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    expr.getModel().getUniqueFieldName("${expr.getResolvedType().getSimpleName()}Impl", false)
152716ba89e7f459f49ea85070d4710c1d79d715298George Mount}
153716ba89e7f459f49ea85070d4710c1d79d715298George Mount
15420c7182163d99575d382e065f5a5fe45ed6b87e2George Mountval Expr.oldValueName by Delegates.lazy { expr : Expr ->
155793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    expr.getModel().getUniqueFieldName("mOld${expr.readableName.capitalize()}", false)
15620c7182163d99575d382e065f5a5fe45ed6b87e2George Mount}
15720c7182163d99575d382e065f5a5fe45ed6b87e2George Mount
158019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarval Expr.executePendingLocalName by Delegates.lazy { expr : Expr ->
159793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    "${expr.getModel().ext.getUniqueName(expr.readableName, Scope.EXECUTE_PENDING_METHOD, false)}"
160d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
161d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
162de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.setterName by Delegates.lazy { expr : Expr ->
163793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    expr.getModel().getUniqueMethodName("set${expr.readableName.capitalize()}", true)
164d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
165d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
166de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.onChangeName by Delegates.lazy { expr : Expr ->
167793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    expr.getModel().getUniqueMethodName("onChange${expr.readableName.capitalize()}", false)
168d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
169d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
170de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.getterName by Delegates.lazy { expr : Expr ->
171793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount    expr.getModel().getUniqueMethodName("get${expr.readableName.capitalize()}", true)
172d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
173d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
174de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.dirtyFlagName by Delegates.lazy { expr : Expr ->
175019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    expr.getModel().getUniqueFlagName("sFlag${expr.readableName.capitalize()}")
176d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
177d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
178d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
179d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun Expr.isVariable() = this is IdentifierExpr && this.isDynamic()
180d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
181d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun Expr.conditionalFlagName(output : Boolean, suffix : String) = "${dirtyFlagName}_${output}$suffix"
182d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
183de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.dirtyFlagSet by Delegates.lazy { expr : Expr ->
184d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar    FlagSet(expr.getInvalidFlags(), expr.getModel().getFlagBucketCount())
185d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
186d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
187de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.invalidateFlagSet by Delegates.lazy { expr : Expr ->
188d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar    FlagSet(expr.getId())
189d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
190d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
1917b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyarval Expr.shouldReadFlagSet by Delegates.versionedLazy { expr : Expr ->
192d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar    FlagSet(expr.getShouldReadFlags(), expr.getModel().getFlagBucketCount())
193d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
194d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
195eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyarval Expr.shouldReadWithConditionalsFlagSet by Delegates.versionedLazy { expr : Expr ->
196eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar    FlagSet(expr.getShouldReadFlagsWithConditionals(), expr.getModel().getFlagBucketCount())
197eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar}
198eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar
199de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.conditionalFlags by Delegates.lazy { expr : Expr ->
200d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar    arrayListOf(FlagSet(expr.getRequirementFlagIndex(false)),
201d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar            FlagSet(expr.getRequirementFlagIndex(true)))
202d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
203d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
204e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mountval LayoutBinder.requiredComponent by Delegates.lazy { layoutBinder: LayoutBinder ->
205e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount    val required = layoutBinder.
206e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            getBindingTargets().
207e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            flatMap { it.getBindings() }.
208e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            firstOrNull { it.getBindingAdapterInstanceClass() != null }
209e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount    required?.getBindingAdapterInstanceClass()
210e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount}
211e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount
212d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun Expr.getRequirementFlagSet(expected : Boolean) : FlagSet = conditionalFlags[if(expected) 1 else 0]
213d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
214d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun FlagSet.notEmpty(cb : (suffix : String, value : Long) -> Unit) {
215d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    buckets.withIndex().forEach {
216d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (it.value != 0L) {
217d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            cb(getWordSuffix(it.index), buckets[it.index])
218d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
219d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
220d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
221d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
222d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun FlagSet.getWordSuffix(wordIndex : Int) : String {
223d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    return if(wordIndex == 0) "" else "_${wordIndex}"
224d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
225d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
226d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun FlagSet.localValue(bucketIndex : Int) =
227d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar        if (getLocalName() == null) binaryCode(bucketIndex)
228d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        else "${getLocalName()}${getWordSuffix(bucketIndex)}"
229d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
230d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyarfun FlagSet.binaryCode(bucketIndex : Int) = longToBinary(buckets[bucketIndex])
231d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar
232d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar
233d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyarfun longToBinary(l : Long) =
234d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar        "0b${java.lang.Long.toBinaryString(l)}L"
235d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
236d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun <T> FlagSet.mapOr(other : FlagSet, cb : (suffix : String, index : Int) -> T) : List<T> {
237d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    val min = Math.min(buckets.size(), other.buckets.size())
238d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    val result = arrayListOf<T>()
239d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    for (i in 0..(min - 1)) {
240d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // if these two can match by any chance, call the callback
241d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (intersect(other, i)) {
242d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            result.add(cb(getWordSuffix(i), i))
243d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
244d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
245d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    return result
246d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
247d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
24896e1c821dd446d1ed78f8ae61131550588f60a24George Mountfun indexFromTag(tag : String) : kotlin.Int {
24996e1c821dd446d1ed78f8ae61131550588f60a24George Mount    val startIndex : kotlin.Int
2507ff60c24c6de7ba0c674fe65a82ad4a88dab2e5dGeorge Mount    if (tag.startsWith("binding_")) {
2517ff60c24c6de7ba0c674fe65a82ad4a88dab2e5dGeorge Mount        startIndex = "binding_".length();
25296e1c821dd446d1ed78f8ae61131550588f60a24George Mount    } else {
25396e1c821dd446d1ed78f8ae61131550588f60a24George Mount        startIndex = tag.lastIndexOf('_') + 1
25496e1c821dd446d1ed78f8ae61131550588f60a24George Mount    }
25596e1c821dd446d1ed78f8ae61131550588f60a24George Mount    return Integer.parseInt(tag.substring(startIndex))
25696e1c821dd446d1ed78f8ae61131550588f60a24George Mount}
25796e1c821dd446d1ed78f8ae61131550588f60a24George Mount
25843596c2b2997e40b709627419732100d78a62ff0Yigit Boyarclass LayoutBinderWriter(val layoutBinder : LayoutBinder) {
259d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    val model = layoutBinder.getModel()
26034a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount    val indices = HashMap<BindingTarget, kotlin.Int>()
26143596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    val mDirtyFlags by Delegates.lazy {
26243596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        val fs = FlagSet(BitSet(), model.getFlagBucketCount());
26343596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        Arrays.fill(fs.buckets, -1)
26443596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        fs.setDynamic(true)
26543596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        model.localizeFlag(fs, "mDirtyFlags")
26643596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        fs
267d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
268d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
26943596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    val dynamics by Delegates.lazy { model.getExprMap().values().filter { it.isDynamic() } }
270dea555cf42dc3583604699c8c018d22681f56166George Mount    val className = layoutBinder.getImplementationName()
271d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
272dea555cf42dc3583604699c8c018d22681f56166George Mount    val baseClassName = "${layoutBinder.getClassName()}"
273d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
2747551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar    val includedBinders by Delegates.lazy {
2757551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar        layoutBinder.getBindingTargets().filter { it.isBinder() }
2767551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar    }
2777551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar
27843596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    val variables by Delegates.lazy {
27943596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        model.getExprMap().values().filterIsInstance(javaClass<IdentifierExpr>()).filter { it.isVariable() }
28043596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    }
281d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
2825bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    val usedVariables by Delegates.lazy {
2835bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        variables.filter {it.isUsed()}
2845bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    }
285d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
28696e1c821dd446d1ed78f8ae61131550588f60a24George Mount    public fun write(minSdk : kotlin.Int) : String  {
2875bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        layoutBinder.resolveWhichExpressionsAreUsed()
28834a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        calculateIndices();
2895bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        return kcode("package ${layoutBinder.getPackage()};") {
290a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            nl("import ${layoutBinder.getModulePackage()}.R;")
291a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            nl("import ${layoutBinder.getModulePackage()}.BR;")
2925bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("import android.view.View;")
293dea555cf42dc3583604699c8c018d22681f56166George Mount            val classDeclaration : String
294dea555cf42dc3583604699c8c018d22681f56166George Mount            if (layoutBinder.hasVariations()) {
295dea555cf42dc3583604699c8c018d22681f56166George Mount                classDeclaration = "${className} extends ${baseClassName}"
296dea555cf42dc3583604699c8c018d22681f56166George Mount            } else {
297dea555cf42dc3583604699c8c018d22681f56166George Mount                classDeclaration = "${className} extends android.databinding.ViewDataBinding"
298dea555cf42dc3583604699c8c018d22681f56166George Mount            }
299dea555cf42dc3583604699c8c018d22681f56166George Mount            nl("public class ${classDeclaration} {") {
3004c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab(declareIncludeViews())
3015bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareViews())
3025bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareVariables())
30320c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                tab(declareBoundValues())
304716ba89e7f459f49ea85070d4710c1d79d715298George Mount                tab(declareListeners())
30596e1c821dd446d1ed78f8ae61131550588f60a24George Mount                tab(declareConstructor(minSdk))
3065bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareInvalidateAll())
307447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                tab(declareHasPendingBindings())
3085bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareLog())
3095bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareSetVariable())
3105bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(variableSettersAndGetters())
3115bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(onFieldChange())
3125bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
3134c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab(executePendingBindings())
3145bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
315716ba89e7f459f49ea85070d4710c1d79d715298George Mount                tab(declareListenerImpls())
3165bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareDirtyFlags())
317dea555cf42dc3583604699c8c018d22681f56166George Mount                if (!layoutBinder.hasVariations()) {
318dea555cf42dc3583604699c8c018d22681f56166George Mount                    tab(declareFactories())
319dea555cf42dc3583604699c8c018d22681f56166George Mount                }
3205bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            }
3215bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("}")
3225bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            tab(flagMapping())
3235bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            tab("//end")
3245bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        }.generate()
3255bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    }
32634a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount    fun calculateIndices() : Unit {
32796e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val taggedViews = layoutBinder.getBindingTargets().filter{
328d6527ee28cc3aa05818799af8def9593346f91bcGeorge Mount            it.isUsed() && it.getTag() != null && !it.isBinder()
32934a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        }
33096e1c821dd446d1ed78f8ae61131550588f60a24George Mount        taggedViews.forEach {
33196e1c821dd446d1ed78f8ae61131550588f60a24George Mount            indices.put(it, indexFromTag(it.getTag()))
33296e1c821dd446d1ed78f8ae61131550588f60a24George Mount        }
33396e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val indexStart = maxIndex() + 1
33496e1c821dd446d1ed78f8ae61131550588f60a24George Mount        layoutBinder.getBindingTargets().filter{
33596e1c821dd446d1ed78f8ae61131550588f60a24George Mount            it.isUsed() && !taggedViews.contains(it)
33696e1c821dd446d1ed78f8ae61131550588f60a24George Mount        }.withIndex().forEach {
33796e1c821dd446d1ed78f8ae61131550588f60a24George Mount            indices.put(it.value, it.index + indexStart)
33834a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        }
33934a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount    }
3404c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount    fun declareIncludeViews() = kcode("") {
341239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount        nl("private static final android.databinding.ViewDataBinding.IncludedLayouts sIncludes;")
3424c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount        nl("private static final android.util.SparseIntArray sViewsWithIds;")
3434c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount        nl("static {") {
3444c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            val hasBinders = layoutBinder.getBindingTargets().firstOrNull{ it.isUsed() && it.isBinder()} != null
3454c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            if (!hasBinders) {
3464c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab("sIncludes = null;")
34700da715547ee7d5d38a3b8576090ca427a94daa5George Mount            } else {
34896e1c821dd446d1ed78f8ae61131550588f60a24George Mount                val numBindings = layoutBinder.getBindingTargets().filter{ it.isUsed() }.count()
349239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                tab("sIncludes = new android.databinding.ViewDataBinding.IncludedLayouts(${numBindings});")
35096e1c821dd446d1ed78f8ae61131550588f60a24George Mount                val includeMap = HashMap<BindingTarget, ArrayList<BindingTarget>>()
35196e1c821dd446d1ed78f8ae61131550588f60a24George Mount                layoutBinder.getBindingTargets().filter{ it.isUsed() && it.isBinder() }.forEach {
35296e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    val includeTag = it.getTag();
35396e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    val parent = layoutBinder.getBindingTargets().firstOrNull {
35496e1c821dd446d1ed78f8ae61131550588f60a24George Mount                        it.isUsed() && !it.isBinder() && includeTag.equals(it.getTag())
35596e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    }
35696e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    if (parent == null) {
35796e1c821dd446d1ed78f8ae61131550588f60a24George Mount                        throw IllegalStateException("Could not find parent of include file")
35896e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    }
35996e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    var list = includeMap.get(parent)
36096e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    if (list == null) {
36196e1c821dd446d1ed78f8ae61131550588f60a24George Mount                        list = ArrayList<BindingTarget>()
36296e1c821dd446d1ed78f8ae61131550588f60a24George Mount                        includeMap.put(parent, list)
36396e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    }
36496e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    list.add(it)
3654c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                }
36696e1c821dd446d1ed78f8ae61131550588f60a24George Mount
36796e1c821dd446d1ed78f8ae61131550588f60a24George Mount                includeMap.keySet().forEach {
36896e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    val index = indices.get(it)
369239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                    tab("sIncludes.setIncludes(${index}, ") {
370239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        tab ("new String[] {${
3715d454e5f2397a3b160f081ce123b4ca7ff0fc356Yigit Boyar                        includeMap.get(it)!!.map {
372239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                            "\"${it.getIncludedLayout()}\""
373239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        }.joinToString(", ")
374239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        }},")
375239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        tab("new int[] {${
3765d454e5f2397a3b160f081ce123b4ca7ff0fc356Yigit Boyar                        includeMap.get(it)!!.map {
377239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                            "${indices.get(it)}"
378239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        }.joinToString(", ")
379239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        }},")
380239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        tab("new int[] {${
3815d454e5f2397a3b160f081ce123b4ca7ff0fc356Yigit Boyar                        includeMap.get(it)!!.map {
382239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                            "R.layout.${it.getIncludedLayout()}"
383239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        }.joinToString(", ")
384239e15adad52d3a7d77852953a5dd7eee82f7f2cGeorge Mount                        }});")
38596e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    }
38696e1c821dd446d1ed78f8ae61131550588f60a24George Mount                }
38796e1c821dd446d1ed78f8ae61131550588f60a24George Mount            }
38896e1c821dd446d1ed78f8ae61131550588f60a24George Mount            val viewsWithIds = layoutBinder.getBindingTargets().filter {
389d6527ee28cc3aa05818799af8def9593346f91bcGeorge Mount                it.isUsed() && !it.isBinder() && (!it.supportsTag() || (it.getId() != null && it.getTag() == null))
39000da715547ee7d5d38a3b8576090ca427a94daa5George Mount            }
39196e1c821dd446d1ed78f8ae61131550588f60a24George Mount            if (viewsWithIds.isEmpty()) {
3924c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab("sViewsWithIds = null;")
39300da715547ee7d5d38a3b8576090ca427a94daa5George Mount            } else {
3944c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab("sViewsWithIds = new android.util.SparseIntArray();")
39596e1c821dd446d1ed78f8ae61131550588f60a24George Mount                viewsWithIds.forEach {
39634a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                    tab("sViewsWithIds.put(${it.androidId}, ${indices.get(it)});")
3974c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                }
39800da715547ee7d5d38a3b8576090ca427a94daa5George Mount            }
3994c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount        }
4004c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount        nl("}")
4014c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount    }
40296e1c821dd446d1ed78f8ae61131550588f60a24George Mount
40396e1c821dd446d1ed78f8ae61131550588f60a24George Mount    fun maxIndex() : kotlin.Int {
40496e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val maxIndex = indices.values().max()
40596e1c821dd446d1ed78f8ae61131550588f60a24George Mount        if (maxIndex == null) {
40696e1c821dd446d1ed78f8ae61131550588f60a24George Mount            return -1
40796e1c821dd446d1ed78f8ae61131550588f60a24George Mount        } else {
40896e1c821dd446d1ed78f8ae61131550588f60a24George Mount            return maxIndex
40996e1c821dd446d1ed78f8ae61131550588f60a24George Mount        }
41096e1c821dd446d1ed78f8ae61131550588f60a24George Mount    }
41196e1c821dd446d1ed78f8ae61131550588f60a24George Mount
41296e1c821dd446d1ed78f8ae61131550588f60a24George Mount    fun declareConstructor(minSdk : kotlin.Int) = kcode("") {
41396e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val bindingCount = maxIndex() + 1
41496e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val parameterType : String
41596e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val superParam : String
41696e1c821dd446d1ed78f8ae61131550588f60a24George Mount        if (layoutBinder.isMerge()) {
41796e1c821dd446d1ed78f8ae61131550588f60a24George Mount            parameterType = "View[]"
41896e1c821dd446d1ed78f8ae61131550588f60a24George Mount            superParam = "root[0]"
41996e1c821dd446d1ed78f8ae61131550588f60a24George Mount        } else {
42096e1c821dd446d1ed78f8ae61131550588f60a24George Mount            parameterType = "View"
42196e1c821dd446d1ed78f8ae61131550588f60a24George Mount            superParam = "root"
42296e1c821dd446d1ed78f8ae61131550588f60a24George Mount        }
42396e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val rootTagsSupported = minSdk >= 14
424dea555cf42dc3583604699c8c018d22681f56166George Mount        if (layoutBinder.hasVariations()) {
425dea555cf42dc3583604699c8c018d22681f56166George Mount            nl("")
426e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            nl("public ${className}(android.databinding.DataBindingComponent bindingComponent, ${parameterType} root) {") {
427e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                tab("this(bindingComponent, ${superParam}, mapBindings(bindingComponent, root, ${bindingCount}, sIncludes, sViewsWithIds));")
428dea555cf42dc3583604699c8c018d22681f56166George Mount            }
429dea555cf42dc3583604699c8c018d22681f56166George Mount            nl("}")
430e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            nl("private ${className}(android.databinding.DataBindingComponent bindingComponent, ${parameterType} root, Object[] bindings) {") {
431e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                tab("super(bindingComponent, ${superParam}, ${model.getObservables().size()}") {
43296e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    layoutBinder.getSortedTargets().filter { it.getId() != null }.forEach {
433dea555cf42dc3583604699c8c018d22681f56166George Mount                        tab(", ${fieldConversion(it)}")
43434a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                    }
435dea555cf42dc3583604699c8c018d22681f56166George Mount                    tab(");")
43634a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                }
43734a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            }
438dea555cf42dc3583604699c8c018d22681f56166George Mount        } else {
439e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            nl("public ${baseClassName}(android.databinding.DataBindingComponent bindingComponent, ${parameterType} root) {") {
440e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                tab("super(bindingComponent, ${superParam}, ${model.getObservables().size()});")
441e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                tab("final Object[] bindings = mapBindings(bindingComponent, root, ${bindingCount}, sIncludes, sViewsWithIds);")
442dea555cf42dc3583604699c8c018d22681f56166George Mount            }
443dea555cf42dc3583604699c8c018d22681f56166George Mount        }
444e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        if (layoutBinder.requiredComponent != null) {
445e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            tab("ensureBindingComponentIsNotNull(${layoutBinder.requiredComponent}.class);")
446e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        }
44796e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val taggedViews = layoutBinder.getSortedTargets().filter{it.isUsed()}
448dea555cf42dc3583604699c8c018d22681f56166George Mount        taggedViews.forEach {
449dea555cf42dc3583604699c8c018d22681f56166George Mount            if (!layoutBinder.hasVariations() || it.getId() == null) {
450dea555cf42dc3583604699c8c018d22681f56166George Mount                tab("this.${it.fieldName} = ${fieldConversion(it)};")
451dea555cf42dc3583604699c8c018d22681f56166George Mount            }
452d6527ee28cc3aa05818799af8def9593346f91bcGeorge Mount            if (!it.isBinder()) {
453de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                if (it.getResolvedType() != null && it.getResolvedType().extendsViewStub()) {
454de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                    tab("this.${it.fieldName}.setContainingBinding(this);")
455de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                }
45696e1c821dd446d1ed78f8ae61131550588f60a24George Mount                if (it.supportsTag() && it.getTag() != null &&
4577ff60c24c6de7ba0c674fe65a82ad4a88dab2e5dGeorge Mount                        (rootTagsSupported || it.getTag().startsWith("binding_"))) {
458dea555cf42dc3583604699c8c018d22681f56166George Mount                    val originalTag = it.getOriginalTag();
459dea555cf42dc3583604699c8c018d22681f56166George Mount                    var tagValue = "null"
46092a428505b9102bc0560d2d5be1768da097909c2George Mount                    if (originalTag != null && !originalTag.startsWith("@{")) {
461dea555cf42dc3583604699c8c018d22681f56166George Mount                        tagValue = "\"${originalTag}\""
462dea555cf42dc3583604699c8c018d22681f56166George Mount                        if (originalTag.startsWith("@")) {
463dea555cf42dc3583604699c8c018d22681f56166George Mount                            var packageName = layoutBinder.getModulePackage()
464dea555cf42dc3583604699c8c018d22681f56166George Mount                            if (originalTag.startsWith("@android:")) {
465dea555cf42dc3583604699c8c018d22681f56166George Mount                                packageName = "android"
46600da715547ee7d5d38a3b8576090ca427a94daa5George Mount                            }
467dea555cf42dc3583604699c8c018d22681f56166George Mount                            val slashIndex = originalTag.indexOf('/')
468dea555cf42dc3583604699c8c018d22681f56166George Mount                            val resourceId = originalTag.substring(slashIndex + 1)
469dea555cf42dc3583604699c8c018d22681f56166George Mount                            tagValue = "root.getResources().getString(${packageName}.R.string.${resourceId})"
47000da715547ee7d5d38a3b8576090ca427a94daa5George Mount                        }
47100da715547ee7d5d38a3b8576090ca427a94daa5George Mount                    }
472dea555cf42dc3583604699c8c018d22681f56166George Mount                    tab("this.${it.fieldName}.setTag(${tagValue});")
47392a428505b9102bc0560d2d5be1768da097909c2George Mount                } else if (it.getTag() != null && !it.getTag().startsWith("binding_") &&
47492a428505b9102bc0560d2d5be1768da097909c2George Mount                    it.getOriginalTag() != null) {
47592a428505b9102bc0560d2d5be1768da097909c2George Mount                    L.e(ErrorMessages.ROOT_TAG_NOT_SUPPORTED, it.getOriginalTag())
4767551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar                }
477d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
478d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
4794d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount        tab("setRootTag(root);")
480dea555cf42dc3583604699c8c018d22681f56166George Mount        tab("invalidateAll();");
4810fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("}")
482d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
483d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
484dea555cf42dc3583604699c8c018d22681f56166George Mount    fun fieldConversion(target : BindingTarget) : String {
485dea555cf42dc3583604699c8c018d22681f56166George Mount        if (!target.isUsed()) {
486dea555cf42dc3583604699c8c018d22681f56166George Mount            return "null"
487dea555cf42dc3583604699c8c018d22681f56166George Mount        } else {
48896e1c821dd446d1ed78f8ae61131550588f60a24George Mount            val index = indices.get(target)
489dea555cf42dc3583604699c8c018d22681f56166George Mount            if (index == null) {
49096e1c821dd446d1ed78f8ae61131550588f60a24George Mount                throw IllegalStateException("Unknown binding target")
491dea555cf42dc3583604699c8c018d22681f56166George Mount            }
49296e1c821dd446d1ed78f8ae61131550588f60a24George Mount            val variableName = "bindings[${index}]"
493dea555cf42dc3583604699c8c018d22681f56166George Mount            return target.superConversion(variableName)
494dea555cf42dc3583604699c8c018d22681f56166George Mount        }
495dea555cf42dc3583604699c8c018d22681f56166George Mount    }
496dea555cf42dc3583604699c8c018d22681f56166George Mount
497d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareInvalidateAll() = kcode("") {
4987551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar        nl("@Override")
4997551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar        nl("public void invalidateAll() {") {
500019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            val fs = FlagSet(layoutBinder.getModel().getInvalidateAnyBitSet(),
501019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                    layoutBinder.getModel().getFlagBucketCount());
5021c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar            tab("synchronized(this) {") {
5031c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                for (i in (0..(mDirtyFlags.buckets.size() - 1))) {
5041c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                    tab("${mDirtyFlags.localValue(i)} = ${fs.localValue(i)};")
5051c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                }
5061c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar            } tab("}")
5075bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            includedBinders.filter{it.isUsed()}.forEach { binder ->
5087551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar                tab("${binder.fieldName}.invalidateAll();")
5097551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar            }
5102f64c44e4fa296cf658ca986c095eab62f82a31dYigit Boyar            tab("requestRebind();");
511d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
5120fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("}")
513d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
514d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
515447971abca811b11b8c1d8e7bfaa294856d03c16George Mount    fun declareHasPendingBindings()  = kcode("") {
516447971abca811b11b8c1d8e7bfaa294856d03c16George Mount        nl("@Override")
517447971abca811b11b8c1d8e7bfaa294856d03c16George Mount        nl("public boolean hasPendingBindings() {") {
518447971abca811b11b8c1d8e7bfaa294856d03c16George Mount            if (mDirtyFlags.buckets.size() > 0) {
519447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                tab("synchronized(this) {") {
520447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                    val flagCheck = 0.rangeTo(mDirtyFlags.buckets.size() - 1).map {
521447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                            "${mDirtyFlags.localValue(it)} != 0"
522447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                    }.joinToString(" || ")
523447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                    tab("if (${flagCheck}) {") {
524447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                        tab("return true;")
525447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                    }
526447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                    tab("}")
527447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                }
528447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                tab("}")
529447971abca811b11b8c1d8e7bfaa294856d03c16George Mount            }
530447971abca811b11b8c1d8e7bfaa294856d03c16George Mount            includedBinders.filter{it.isUsed()}.forEach { binder ->
531447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                tab("if (${binder.fieldName}.hasPendingBindings()) {") {
532447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                    tab("return true;")
533447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                }
534447971abca811b11b8c1d8e7bfaa294856d03c16George Mount                tab("}")
535447971abca811b11b8c1d8e7bfaa294856d03c16George Mount            }
536447971abca811b11b8c1d8e7bfaa294856d03c16George Mount            tab("return false;")
537447971abca811b11b8c1d8e7bfaa294856d03c16George Mount        }
538447971abca811b11b8c1d8e7bfaa294856d03c16George Mount        nl("}")
539447971abca811b11b8c1d8e7bfaa294856d03c16George Mount    }
540447971abca811b11b8c1d8e7bfaa294856d03c16George Mount
541d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareSetVariable() = kcode("") {
5420fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("public boolean setVariable(int variableId, Object variable) {") {
543d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("switch(variableId) {") {
5445bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                usedVariables.forEach {
54543596c2b2997e40b709627419732100d78a62ff0Yigit Boyar                    tab ("case ${it.getName().br()} :") {
546d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        tab("${it.setterName}((${it.getResolvedType().toJavaCode()}) variable);")
547d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        tab("return true;")
548d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
549d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
55023910cf498c35704a03ba4f3889de2ab97ccbe21George Mount                val declaredOnly = variables.filter { !it.isUsed() && it.isDeclared() };
55123910cf498c35704a03ba4f3889de2ab97ccbe21George Mount                declaredOnly.forEachIndexed { i, identifierExpr ->
55223910cf498c35704a03ba4f3889de2ab97ccbe21George Mount                    tab ("case ${identifierExpr.getName().br()} :") {
55323910cf498c35704a03ba4f3889de2ab97ccbe21George Mount                        if (i == declaredOnly.size() - 1) {
55423910cf498c35704a03ba4f3889de2ab97ccbe21George Mount                            tab("return true;")
55523910cf498c35704a03ba4f3889de2ab97ccbe21George Mount                        }
55623910cf498c35704a03ba4f3889de2ab97ccbe21George Mount                    }
55723910cf498c35704a03ba4f3889de2ab97ccbe21George Mount                }
558d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
559d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("}")
560d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("return false;")
561d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
5620fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("}")
563d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
564d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
565d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareLog() = kcode("") {
5660fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("private void log(String msg, long i) {") {
567d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("""android.util.Log.d("BINDER", msg + ":" + Long.toHexString(i));""")
5680fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        }
5690fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("}")
570d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
571d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
572d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun variableSettersAndGetters() = kcode("") {
5735bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        variables.filterNot{it.isUsed()}.forEach {
574019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            nl("public void ${it.setterName}(${it.getResolvedType().toJavaCode()} ${it.readableName}) {") {
5755bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab("// not used, ignore")
5765bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            }
5775bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("}")
5785bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("")
5795bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("public ${it.getResolvedType().toJavaCode()} ${it.getterName}() {") {
5805bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab("return ${it.getDefaultValue()};")
5815bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            }
5825bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("}")
5835bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        }
5845bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        usedVariables.forEach {
58518243f6f1b7527272ef4feccdf4327d80d9f2241George Mount            if (it.getUserDefinedType() != null) {
586019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                nl("public void ${it.setterName}(${it.getResolvedType().toJavaCode()} ${it.readableName}) {") {
58718243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    if (it.isObservable()) {
588019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                        tab("updateRegistration(${it.getId()}, ${it.readableName});");
58918243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    }
590019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                    tab("this.${it.fieldName} = ${it.readableName};")
59118243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    // set dirty flags!
59218243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    val flagSet = it.invalidateFlagSet
5931c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                    tab("synchronized(this) {") {
5941c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                        mDirtyFlags.mapOr(flagSet) { suffix, index ->
5951c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                            tab("${mDirtyFlags.getLocalName()}$suffix |= ${flagSet.localValue(index)};")
5961c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                        }
5971c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                    } tab ("}")
59818243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    tab("super.requestRebind();")
599d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
60018243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                nl("}")
60118243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                nl("")
60218243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                nl("public ${it.getResolvedType().toJavaCode()} ${it.getterName}() {") {
60318243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    tab("return ${it.fieldName};")
604d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
60518243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                nl("}")
606d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
607d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
608d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
609d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
610d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun onFieldChange() = kcode("") {
61134a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        nl("@Override")
61234a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        nl("protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {") {
6134c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            tab("switch (localFieldId) {") {
614d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                model.getObservables().forEach {
615d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    tab("case ${it.getId()} :") {
616d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        tab("return ${it.onChangeName}((${it.getResolvedType().toJavaCode()}) object, fieldId);")
617d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
618d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
619d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
620d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("}")
621d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("return false;")
622d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
62334a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        nl("}")
62434a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        nl("")
625d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
626d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        model.getObservables().forEach {
627019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            nl("private boolean ${it.onChangeName}(${it.getResolvedType().toJavaCode()} ${it.readableName}, int fieldId) {") {
628d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                tab("switch (fieldId) {", {
629d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    val accessedFields: List<FieldAccessExpr> = it.getParents().filterIsInstance(javaClass<FieldAccessExpr>())
630c4a07bddb4dd5c3bfbecf4d87909c5b447ae56dcGeorge Mount                    accessedFields.filter { it.hasBindableAnnotations() }
631d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            .groupBy { it.getName() }
632d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            .forEach {
63343596c2b2997e40b709627419732100d78a62ff0Yigit Boyar                                tab("case ${it.key.br()}:") {
634d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                                    val field = it.value.first()
6351c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                                    tab("synchronized(this) {") {
6361c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                                        mDirtyFlags.mapOr(field.invalidateFlagSet) { suffix, index ->
6371c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                                            tab("${mDirtyFlags.localValue(index)} |= ${field.invalidateFlagSet.localValue(index)};")
6381c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                                        }
6391c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                                    } tab("}")
640d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                                    tab("return true;")
641d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                                }
642d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
643d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            }
64443596c2b2997e40b709627419732100d78a62ff0Yigit Boyar                    tab("case ${"".br()}:") {
645d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        val flagSet = it.invalidateFlagSet
6461c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                        tab("synchronized(this) {") {
6471c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                            mDirtyFlags.mapOr(flagSet) { suffix, index ->
6481c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                                tab("${mDirtyFlags.getLocalName()}$suffix |= ${flagSet.localValue(index)};")
6491c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                            }
6501c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                        } tab("}")
651d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        tab("return true;")
652d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
653d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
654d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                })
655d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                tab("}")
656d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                tab("return false;")
657d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
65834a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            nl("}")
65934a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            nl("")
660d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
661d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
662d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
663d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareViews() = kcode("// views") {
664dea555cf42dc3583604699c8c018d22681f56166George Mount        val oneLayout = !layoutBinder.hasVariations();
66596e1c821dd446d1ed78f8ae61131550588f60a24George Mount        layoutBinder.getSortedTargets().filter {it.isUsed() && (oneLayout || it.getId() == null)}.forEach {
666dea555cf42dc3583604699c8c018d22681f56166George Mount            val access : String
667dea555cf42dc3583604699c8c018d22681f56166George Mount            if (oneLayout && it.getId() != null) {
668dea555cf42dc3583604699c8c018d22681f56166George Mount                access = "public"
669dea555cf42dc3583604699c8c018d22681f56166George Mount            } else {
670dea555cf42dc3583604699c8c018d22681f56166George Mount                access = "private"
671dea555cf42dc3583604699c8c018d22681f56166George Mount            }
672dea555cf42dc3583604699c8c018d22681f56166George Mount            nl("${access} final ${it.interfaceType} ${it.fieldName};")
673d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
674d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
675d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
676d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareVariables() = kcode("// variables") {
6775bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        usedVariables.forEach {
6780fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar            nl("private ${it.getResolvedType().toJavaCode()} ${it.fieldName};")
679d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
680d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
681d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
68220c7182163d99575d382e065f5a5fe45ed6b87e2George Mount    fun declareBoundValues() = kcode("// values") {
68320c7182163d99575d382e065f5a5fe45ed6b87e2George Mount        layoutBinder.getSortedTargets().filter { it.isUsed() }
68420c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                .flatMap { it.getBindings() }
68520c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                .filter { it.requiresOldValue() }
68620c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                .flatMap{ it.getComponentExpressions().toArrayList() }
68720c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                .groupBy { it }
68820c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                .forEach {
68920c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                    val expr = it.getKey()
69020c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                    nl("private ${expr.getResolvedType().toJavaCode()} ${expr.oldValueName};")
69120c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                }
69220c7182163d99575d382e065f5a5fe45ed6b87e2George Mount    }
69320c7182163d99575d382e065f5a5fe45ed6b87e2George Mount
694716ba89e7f459f49ea85070d4710c1d79d715298George Mount    fun declareListeners() = kcode("// listeners") {
695716ba89e7f459f49ea85070d4710c1d79d715298George Mount        model.getExprMap().values().filter {
696793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            it is ListenerExpr
697716ba89e7f459f49ea85070d4710c1d79d715298George Mount        }.groupBy { it }.forEach {
698793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            val expr = it.key as ListenerExpr
699716ba89e7f459f49ea85070d4710c1d79d715298George Mount            nl("private ${expr.listenerClassName} ${expr.fieldName};")
700716ba89e7f459f49ea85070d4710c1d79d715298George Mount        }
701716ba89e7f459f49ea85070d4710c1d79d715298George Mount    }
702716ba89e7f459f49ea85070d4710c1d79d715298George Mount
703d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareDirtyFlags() = kcode("// dirty flag") {
704d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        model.ext.localizedFlags.forEach { flag ->
705de38dd3ef0577d25b2d59863603abe5750d0c231George Mount            flag.notEmpty { suffix, value ->
7060fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                nl("private")
707d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                app(" ", if(flag.isDynamic()) null else "static final");
708d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar                app(" ", " ${flag.type} ${flag.getLocalName()}$suffix = ${longToBinary(value)};")
709d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
710d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
711d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
712d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
713d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun flagMapping() = kcode("/* flag mapping") {
714d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (model.getFlagMapping() != null) {
715d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            val mapping = model.getFlagMapping()
716d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (i in mapping.indices) {
717d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                tab("flag $i: ${mapping[i]}")
718d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
719d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
720d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        nl("flag mapping end*/")
721d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
722d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
7234c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount    fun executePendingBindings() = kcode("") {
7240fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("@Override")
725e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount        nl("protected void executeBindings() {") {
726d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            val tmpDirtyFlags = FlagSet(mDirtyFlags.buckets)
727d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tmpDirtyFlags.setLocalName("dirtyFlags");
728d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (i in (0..mDirtyFlags.buckets.size() - 1)) {
7291c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                tab("${tmpDirtyFlags.type} ${tmpDirtyFlags.localValue(i)} = 0;")
730d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
7311c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar            tab("synchronized(this) {") {
7321c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                for (i in (0..mDirtyFlags.buckets.size() - 1)) {
7331c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                    tab("${tmpDirtyFlags.localValue(i)} = ${mDirtyFlags.localValue(i)};")
7341c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                    tab("${mDirtyFlags.localValue(i)} = 0;")
7351c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                }
7361c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar            } tab("}")
737a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            model.getPendingExpressions().filterNot { !it.canBeEvaluatedToAVariable() || (it.isVariable() && !it.isUsed()) }.forEach {
738a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                tab("${it.getResolvedType().toJavaCode()} ${it.executePendingLocalName} = ${if (it.isVariable()) it.fieldName else it.getDefaultValue()};")
739d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
740b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar            L.d("writing executePendingBindings for %s", className)
741d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            do {
74274f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar                val batch = ExprModel.filterShouldRead(model.getPendingExpressions()).toArrayList()
743a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                val justRead = arrayListOf<Expr>()
744b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar                L.d("batch: %s", batch)
745d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                while (!batch.none()) {
746a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    val readNow = batch.filter { it.shouldReadNow(justRead) }
747d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    if (readNow.isEmpty()) {
748d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        throw IllegalStateException("do not know what I can read. bailing out ${batch.joinToString("\n")}")
749d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
750b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar                    L.d("new read now. batch size: %d, readNow size: %d", batch.size(), readNow.size())
751a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    nl(readWithDependants(readNow, justRead, batch, tmpDirtyFlags))
752a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    batch.removeAll(justRead)
753d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
7540fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                tab("// batch finished")
755a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            } while (model.markBitsRead())
7567b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar            // verify everything is read.
7577b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar            val batch = ExprModel.filterShouldRead(model.getPendingExpressions()).toArrayList()
7587b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar            if (batch.isNotEmpty()) {
7597b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar                L.e("could not generate code for %s. This might be caused by circular dependencies."
760e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount                        + "Please report on b.android.com. %d %s %s", layoutBinder.getLayoutname(),
761e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount                        batch.size(), batch.get(0), batch.get(0).toCode().generate())
7627b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar            }
763d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            //
76496e1c821dd446d1ed78f8ae61131550588f60a24George Mount            layoutBinder.getSortedTargets().filter { it.isUsed() }
765d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    .flatMap { it.getBindings() }
766a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    .groupBy {
767a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        "${tmpDirtyFlags.mapOr(it.getExpr().dirtyFlagSet) { suffix, index ->
768a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            "(${tmpDirtyFlags.localValue(index)} & ${it.getExpr().dirtyFlagSet.localValue(index)}) != 0"
769a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        }.joinToString(" || ") }"
770a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    }.forEach {
771a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                tab("if (${it.key}) {") {
772a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    it.value.groupBy { Math.max(1, it.getMinApi()) }.forEach {
773a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        val setterValues = kcode("") {
774d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            it.value.forEach { binding ->
775a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                val fieldName: String
776d6527ee28cc3aa05818799af8def9593346f91bcGeorge Mount                                if (binding.getTarget().getViewClass().
77734a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                                        equals(binding.getTarget().getInterfaceType())) {
77834a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                                    fieldName = "this.${binding.getTarget().fieldName}"
77934a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                                } else {
78034a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                                    fieldName = "((${binding.getTarget().getViewClass()}) this.${binding.getTarget().fieldName})"
78134a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                                }
782a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                tab(binding.toJavaCode(fieldName, "this.mBindingComponent")).app(";")
783a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            }
784a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        }
785a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        tab("// api target ${it.key}")
786a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        if (it.key > 1) {
787a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            tab("if(getBuildSdkInt() >= ${it.key}) {") {
788a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                app("", setterValues)
789d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            }
790a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            tab("}")
791a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        } else {
792a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            app("", setterValues)
79320c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                        }
79420c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                    }
795a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                }
796a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                tab("}")
797a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            }
798a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount
79920c7182163d99575d382e065f5a5fe45ed6b87e2George Mount
80020c7182163d99575d382e065f5a5fe45ed6b87e2George Mount            layoutBinder.getSortedTargets().filter { it.isUsed() }
80120c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                    .flatMap { it.getBindings() }
80220c7182163d99575d382e065f5a5fe45ed6b87e2George Mount                    .filter { it.requiresOldValue() }
803a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    .groupBy {"${tmpDirtyFlags.mapOr(it.getExpr().dirtyFlagSet) { suffix, index ->
804a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        "(${tmpDirtyFlags.localValue(index)} & ${it.getExpr().dirtyFlagSet.localValue(index)}) != 0"
805a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    }.joinToString(" || ")
806a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    }"}.forEach {
807a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                tab("if (${it.key}) {") {
808a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    it.value.groupBy { it.getExpr() }.map { it.value.first() }.forEach {
809a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        it.getComponentExpressions().forEach { expr ->
810a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            tab("this.${expr.oldValueName} = ${expr.toCode().generate()};")
811d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        }
812d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
813a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                }
814a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                tab("}")
815a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            }
8165bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            includedBinders.filter{it.isUsed()}.forEach { binder ->
8174c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab("${binder.fieldName}.executePendingBindings();")
8187551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar            }
81996e1c821dd446d1ed78f8ae61131550588f60a24George Mount            layoutBinder.getSortedTargets().filter{
820de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                it.isUsed() && it.getResolvedType() != null && it.getResolvedType().extendsViewStub()
821de38dd3ef0577d25b2d59863603abe5750d0c231George Mount            }.forEach {
822de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                tab("if (${it.fieldName}.getBinding() != null) {") {
823de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                    tab("${it.fieldName}.getBinding().executePendingBindings();")
824de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                }
825de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                tab("}")
826de38dd3ef0577d25b2d59863603abe5750d0c231George Mount            }
827d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
8280fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("}")
829d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
830d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
831a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount    fun readWithDependants(expressionList: List<Expr>, justRead: MutableList<Expr>,
832a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            batch: MutableList<Expr>, tmpDirtyFlags: FlagSet,
833a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            inheritedFlags: FlagSet? = null) : KCode = kcode("") {
834a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount        expressionList.groupBy { it.shouldReadFlagSet }.forEach {
835a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            val flagSet = it.key
836a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            val needsIfWrapper = inheritedFlags == null || !flagSet.bitsEqual(inheritedFlags)
837a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            val expressions = it.value
838a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            val ifClause = "if (${tmpDirtyFlags.mapOr(flagSet){ suffix, index ->
839a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                "(${tmpDirtyFlags.localValue(index)} & ${flagSet.localValue(index)}) != 0"
840a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            }.joinToString(" || ")
841a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            })"
842a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            val readCode = kcode("") {
843a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                val dependants = ArrayList<Expr>()
844a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                expressions.groupBy { condition(it) }.forEach {
845a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    val condition = it.key
846a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    val assignedValues = it.value.filter {
847a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        it.canBeEvaluatedToAVariable() && !it.isVariable()
848d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
849a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    if (!assignedValues.isEmpty()) {
850a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        val assignment = kcode("") {
851a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            assignedValues.forEach { expr: Expr ->
852a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                tab("// read ${expr.getUniqueKey()}")
853a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                tab("${expr.executePendingLocalName}").app(" = ", expr.toFullCode()).app(";")
854a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            }
855a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        }
856a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        if (condition != null) {
857a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            tab("if (${condition}) {") {
858a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                app("", assignment)
859a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            }
860a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            tab ("}")
861a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        } else {
862a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            app("", assignment)
863d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        }
8649e7a4ce47ae5f4428f7630fe03a7ad66d06177fbGeorge Mount                        it.value.filter { it.isObservable() }.forEach { expr: Expr ->
8659e7a4ce47ae5f4428f7630fe03a7ad66d06177fbGeorge Mount                            tab("updateRegistration(${expr.getId()}, ${expr.executePendingLocalName});")
8669e7a4ce47ae5f4428f7630fe03a7ad66d06177fbGeorge Mount                        }
867a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    }
868a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount
869a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    it.value.forEach { expr: Expr ->
870a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        justRead.add(expr)
871a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        L.d("%s / readWithDependants %s", className, expr.getUniqueKey());
872a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        L.d("flag set:%s . inherited flags: %s. need another if: %s", flagSet, inheritedFlags, needsIfWrapper);
873a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount
874a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        // if I am the condition for an expression, set its flag
875eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                        expr.getDependants().filter {
876a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            !it.isConditional() && it.getDependant() is TernaryExpr &&
877a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                    (it.getDependant() as TernaryExpr).getPred() == expr
878eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                        }.map { it.getDependant() }.groupBy {
879eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                            // group by when those ternaries will be evaluated (e.g. don't set conditional flags for no reason)
880eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                            val ternaryBitSet = it.getShouldReadFlagsWithConditionals()
881eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                            val isBehindTernary = ternaryBitSet.nextSetBit(model.getInvalidateAnyFlagIndex()) == -1
882eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                            if (!isBehindTernary) {
883eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                val ternaryFlags = it.shouldReadWithConditionalsFlagSet
884eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                "if(${tmpDirtyFlags.mapOr(ternaryFlags){ suffix, index ->
885eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                    "(${tmpDirtyFlags.localValue(index)} & ${ternaryFlags.localValue(index)}) != 0"
886eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                }.joinToString(" || ")}) {"
887eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                            } else {
888eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                // TODO if it is behind a ternary, we should set it when its predicate is elevated
889eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                // Normally, this would mean that there is another code path to re-read our current expression.
890eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                // Unfortunately, this may not be true due to the coverage detection in `expr#markAsReadIfDone`, this may never happen.
891eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                // for v1.0, we'll go with always setting it and suffering an unnecessary calculation for this edge case.
892eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                // we can solve this by listening to elevation events from the model.
893eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                ""
894a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            }
895eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                        }.forEach {
896eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                            val hasAnotherIf = it.key != ""
897eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                            if (hasAnotherIf) {
898eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                tab(it.key) {
899eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                    tab("if (${expr.executePendingLocalName}) {") {
900eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                        it.value.forEach {
901eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                            val set = it.getRequirementFlagSet(true)
902eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                            mDirtyFlags.mapOr(set) { suffix, index ->
903eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                                tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
904eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                            }
905eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                        }
906eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                    }
907eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                    tab("} else {") {
908eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                        it.value.forEach {
909eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                            val set = it.getRequirementFlagSet(false)
910eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                            mDirtyFlags.mapOr(set) { suffix, index ->
911eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                                tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
912eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                            }
913eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                        }
914eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                    }.tab("}")
915eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                }.app("}")
916eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                            } else {
917eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                tab("if (${expr.executePendingLocalName}) {") {
918eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                    it.value.forEach {
919eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                        val set = it.getRequirementFlagSet(true)
920eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                        mDirtyFlags.mapOr(set) { suffix, index ->
921eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                            tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
922eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                        }
923a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                    }
924a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                }
925eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                tab("} else {") {
926eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                    it.value.forEach {
927eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                        val set = it.getRequirementFlagSet(false)
928eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                        mDirtyFlags.mapOr(set) { suffix, index ->
929eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                            tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
930eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                        }
931eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                    }
932eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar                                } app("}")
933a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            }
934a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        }
935a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        val chosen = expr.getDependants().filter {
936a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            val dependant = it.getDependant()
937a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            batch.contains(dependant) &&
938a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                    dependant.shouldReadFlagSet.andNot(flagSet).isEmpty() &&
939a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                                    dependant.shouldReadNow(justRead)
940a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        }
941a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                        if (chosen.isNotEmpty()) {
942a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                            dependants.addAll(chosen.map { it.getDependant() })
9430fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                        }
9440fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                    }
945a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                }
946a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                if (dependants.isNotEmpty()) {
947a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    val nextInheritedFlags = if (needsIfWrapper) flagSet else inheritedFlags
948a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    nl(readWithDependants(dependants, justRead, batch, tmpDirtyFlags, nextInheritedFlags))
949a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                }
950d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
9510fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
952a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            if (needsIfWrapper) {
953a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                tab(ifClause) {
954a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    app(" {")
955a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                    app("", readCode)
956d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
957a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                tab("}")
958a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            } else {
959a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                app("", readCode)
960d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
961d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
962a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount    }
963a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount
964a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount    fun condition(expr : Expr) : String? {
965a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount        if (expr.canBeEvaluatedToAVariable() && !expr.isVariable()) {
966a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            // create an if case for all dependencies that might be null
967a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            val nullables = expr.getDependencies().filter {
968a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                it.isMandatory() && it.getOther().getResolvedType().isNullable()
969a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            }.map { it.getOther() }
970a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            if (!expr.isEqualityCheck() && nullables.isNotEmpty()) {
971a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                return "${nullables.map { "${it.executePendingLocalName} != null" }.joinToString(" && ")}"
972a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            } else {
973a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount                return null
974d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar            }
975d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar        } else {
976a0820baa03e731f274ef55c5541e9fc101bbaddbGeorge Mount            return null
977d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar        }
978d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
979716ba89e7f459f49ea85070d4710c1d79d715298George Mount
980716ba89e7f459f49ea85070d4710c1d79d715298George Mount    fun declareListenerImpls() = kcode("// Listener Stub Implementations") {
981716ba89e7f459f49ea85070d4710c1d79d715298George Mount        model.getExprMap().values().filter {
982793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            it.isUsed() && it is ListenerExpr
983716ba89e7f459f49ea85070d4710c1d79d715298George Mount        }.groupBy { it }.forEach {
984793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            val expr = it.key as ListenerExpr
985793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            val listenerType = expr.getResolvedType();
986793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            val extendsImplements : String
987793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            if (listenerType.isInterface()) {
988793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                extendsImplements = "implements"
989793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            } else {
990793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                extendsImplements = "extends"
991793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            }
992793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount            nl("public static class ${expr.listenerClassName} ${extendsImplements} ${listenerType.getCanonicalName()}{") {
993716ba89e7f459f49ea85070d4710c1d79d715298George Mount                if (expr.getChild().isDynamic()) {
994716ba89e7f459f49ea85070d4710c1d79d715298George Mount                    tab("private ${expr.getChild().getResolvedType().toJavaCode()} value;")
995716ba89e7f459f49ea85070d4710c1d79d715298George Mount                    tab("public ${expr.listenerClassName} setValue(${expr.getChild().getResolvedType().toJavaCode()} value) {") {
996716ba89e7f459f49ea85070d4710c1d79d715298George Mount                        tab("this.value = value;")
997716ba89e7f459f49ea85070d4710c1d79d715298George Mount                        tab("return value == null ? null : this;")
998716ba89e7f459f49ea85070d4710c1d79d715298George Mount                    }
999716ba89e7f459f49ea85070d4710c1d79d715298George Mount                    tab("}")
1000716ba89e7f459f49ea85070d4710c1d79d715298George Mount                }
1001793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                val listenerMethod = expr.getMethod()
1002793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                val parameterTypes = listenerMethod.getParameterTypes()
1003793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                val returnType = listenerMethod.getReturnType(parameterTypes.toArrayList())
1004793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                tab("@Override")
1005793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                tab("public ${returnType} ${listenerMethod.getName()}(${
1006716ba89e7f459f49ea85070d4710c1d79d715298George Mount                    parameterTypes.withIndex().map {
1007716ba89e7f459f49ea85070d4710c1d79d715298George Mount                        "${it.value.toJavaCode()} arg${it.index}"
1008716ba89e7f459f49ea85070d4710c1d79d715298George Mount                    }.joinToString(", ")
1009793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                }) {") {
1010793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                    val obj : String
1011793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                    if (expr.getChild().isDynamic()) {
1012793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                        obj = "this.value"
1013793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                    } else {
1014793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                        obj = expr.getChild().toCode().generate();
1015793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                    }
1016793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                    val returnStr : String
1017793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                    if (!returnType.isVoid()) {
1018793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                        returnStr = "return "
1019793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                    } else {
1020793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                        returnStr = ""
1021716ba89e7f459f49ea85070d4710c1d79d715298George Mount                    }
1022793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                    val args = parameterTypes.withIndex().map {
1023793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                        "arg${it.index}"
1024793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                    }.joinToString(", ")
1025793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                    tab("${returnStr}${obj}.${expr.getName()}(${args});")
1026716ba89e7f459f49ea85070d4710c1d79d715298George Mount                }
1027793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount                tab("}")
1028716ba89e7f459f49ea85070d4710c1d79d715298George Mount            }
1029716ba89e7f459f49ea85070d4710c1d79d715298George Mount            nl("}")
1030716ba89e7f459f49ea85070d4710c1d79d715298George Mount        }
1031716ba89e7f459f49ea85070d4710c1d79d715298George Mount    }
103243596c2b2997e40b709627419732100d78a62ff0Yigit Boyar
1033dea555cf42dc3583604699c8c018d22681f56166George Mount    fun declareFactories() = kcode("") {
1034081ec223f1f2f801bd907ec6344b0c6aeee133e5George Mount        nl("public static ${baseClassName} inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot) {") {
1035e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            tab("return inflate(inflater, root, attachToRoot, android.databinding.DataBindingUtil.getDefaultComponent());")
1036e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        }
1037e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        nl("}")
1038e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        nl("public static ${baseClassName} inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot, android.databinding.DataBindingComponent bindingComponent) {") {
1039e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            tab("return android.databinding.DataBindingUtil.<${baseClassName}>inflate(inflater, ${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()}, root, attachToRoot, bindingComponent);")
1040081ec223f1f2f801bd907ec6344b0c6aeee133e5George Mount        }
1041081ec223f1f2f801bd907ec6344b0c6aeee133e5George Mount        nl("}")
104296e1c821dd446d1ed78f8ae61131550588f60a24George Mount        if (!layoutBinder.isMerge()) {
1043081ec223f1f2f801bd907ec6344b0c6aeee133e5George Mount            nl("public static ${baseClassName} inflate(android.view.LayoutInflater inflater) {") {
1044e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                tab("return inflate(inflater, android.databinding.DataBindingUtil.getDefaultComponent());")
1045e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            }
1046e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            nl("}")
1047e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            nl("public static ${baseClassName} inflate(android.view.LayoutInflater inflater, android.databinding.DataBindingComponent bindingComponent) {") {
1048e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                tab("return bind(inflater.inflate(${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()}, null, false), bindingComponent);")
104996e1c821dd446d1ed78f8ae61131550588f60a24George Mount            }
105096e1c821dd446d1ed78f8ae61131550588f60a24George Mount            nl("}")
105196e1c821dd446d1ed78f8ae61131550588f60a24George Mount            nl("public static ${baseClassName} bind(android.view.View view) {") {
1052e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                tab("return bind(view, android.databinding.DataBindingUtil.getDefaultComponent());")
1053e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            }
1054e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            nl("}")
1055e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            nl("public static ${baseClassName} bind(android.view.View view, android.databinding.DataBindingComponent bindingComponent) {") {
105696e1c821dd446d1ed78f8ae61131550588f60a24George Mount                tab("if (!\"${layoutBinder.getTag()}_0\".equals(view.getTag())) {") {
1057f80b08430f11515ff944f89006799f21545602b9George Mount                    tab("throw new RuntimeException(\"view tag isn't correct on view:\" + view.getTag());")
105896e1c821dd446d1ed78f8ae61131550588f60a24George Mount                }
105996e1c821dd446d1ed78f8ae61131550588f60a24George Mount                tab("}")
1060e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                tab("return new ${baseClassName}(bindingComponent, view);")
106196e1c821dd446d1ed78f8ae61131550588f60a24George Mount            }
106296e1c821dd446d1ed78f8ae61131550588f60a24George Mount            nl("}")
1063dea555cf42dc3583604699c8c018d22681f56166George Mount        }
1064dea555cf42dc3583604699c8c018d22681f56166George Mount    }
1065dea555cf42dc3583604699c8c018d22681f56166George Mount
10668b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar    /**
10678b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar     * When called for a library compilation, we do not generate real implementations
10688b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar     */
10698b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar    public fun writeBaseClass(forLibrary : Boolean) : String =
107043596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        kcode("package ${layoutBinder.getPackage()};") {
1071fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount            nl("import android.databinding.Bindable;")
1072fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount            nl("import android.databinding.DataBindingUtil;")
1073fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount            nl("import android.databinding.ViewDataBinding;")
10744c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            nl("public abstract class ${baseClassName} extends ViewDataBinding {")
107596e1c821dd446d1ed78f8ae61131550588f60a24George Mount            layoutBinder.getSortedTargets().filter{it.getId() != null}.forEach {
1076de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                tab("public final ${it.interfaceType} ${it.fieldName};")
107734a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            }
107834a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            nl("")
1079e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            tab("protected ${baseClassName}(android.databinding.DataBindingComponent bindingComponent, android.view.View root_, int localFieldCount") {
108096e1c821dd446d1ed78f8ae61131550588f60a24George Mount                layoutBinder.getSortedTargets().filter{it.getId() != null}.forEach {
1081019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                    tab(", ${it.interfaceType} ${it.constructorParamName}")
108234a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                }
108334a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            }
108434a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            tab(") {") {
1085e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                tab("super(bindingComponent, root_, localFieldCount);")
108696e1c821dd446d1ed78f8ae61131550588f60a24George Mount                layoutBinder.getSortedTargets().filter{it.getId() != null}.forEach {
1087019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                    tab("this.${it.fieldName} = ${it.constructorParamName};")
108834a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                }
10894c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            }
10904c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            tab("}")
10914c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            nl("")
109243596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            variables.forEach {
109318243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                if (it.getUserDefinedType() != null) {
1094895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar                    val type = ModelAnalyzer.getInstance().applyImports(it.getUserDefinedType(), model.getImports())
1095019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                    tab("public abstract void ${it.setterName}(${type} ${it.readableName});")
109618243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                }
109743596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            }
10989bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount            tab("public static ${baseClassName} inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot) {") {
1099e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                tab("return inflate(inflater, root, attachToRoot, android.databinding.DataBindingUtil.getDefaultComponent());")
1100e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            }
1101e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            tab("}")
1102e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            tab("public static ${baseClassName} inflate(android.view.LayoutInflater inflater) {") {
1103e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                tab("return inflate(inflater, android.databinding.DataBindingUtil.getDefaultComponent());")
1104e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            }
1105e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            tab("}")
1106e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            tab("public static ${baseClassName} bind(android.view.View view) {") {
11078b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar                if (forLibrary) {
11088b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar                    tab("return null;")
11098b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar                } else {
1110e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                    tab("return bind(view, android.databinding.DataBindingUtil.getDefaultComponent());")
11118b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar                }
111243596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            }
11134c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            tab("}")
1114e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            tab("public static ${baseClassName} inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot, android.databinding.DataBindingComponent bindingComponent) {") {
11158b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar                if (forLibrary) {
11168b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar                    tab("return null;")
11178b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar                } else {
1118e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                    tab("return DataBindingUtil.<${baseClassName}>inflate(inflater, ${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()}, root, attachToRoot, bindingComponent);")
11198b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar                }
11204c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            }
11214c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            tab("}")
1122e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            tab("public static ${baseClassName} inflate(android.view.LayoutInflater inflater, android.databinding.DataBindingComponent bindingComponent) {") {
1123e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                if (forLibrary) {
1124e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                    tab("return null;")
1125e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                } else {
1126e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                    tab("return DataBindingUtil.<${baseClassName}>inflate(inflater, ${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()}, null, false, bindingComponent);")
1127e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                }
1128e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            }
1129e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            tab("}")
1130e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            tab("public static ${baseClassName} bind(android.view.View view, android.databinding.DataBindingComponent bindingComponent) {") {
11318b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar                if (forLibrary) {
11328b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar                    tab("return null;")
11338b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar                } else {
1134e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                    tab("return (${baseClassName})bind(bindingComponent, view, ${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()});")
11358b1da958f181639d33dfaa907c0ee66add2decd6Yigit Boyar                }
11364c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            }
11374c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            tab("}")
113843596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            nl("}")
113943596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        }.generate()
1140dea555cf42dc3583604699c8c018d22681f56166George Mount}
1141