LayoutBinderWriter.kt revision e9b33bac04bb1ce1444d7f1744fcec1ecd3a57da
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
16fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.LayoutBinder
17e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyarimport kotlin.properties.Delegates
18e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyarimport android.databinding.tool.BindingTarget
19fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.Expr
20d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport kotlin.properties.Delegates
21fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.ext.joinToCamelCaseAsVar
22fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.BindingTarget
23fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.IdentifierExpr
24fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.util.Log
25d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.BitSet
26fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.ExprModel
27d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.Arrays
28c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mountimport android.databinding.tool.expr.BitShiftExpr
29fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.TernaryExpr
30fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.FieldAccessExpr
31fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.ComparisonExpr
32fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.GroupExpr
33c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mountimport android.databinding.tool.expr.InstanceOfExpr
34fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.MathExpr
35fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.MethodCallExpr
36fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.StaticIdentifierExpr
37fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.SymbolExpr
38c6bcb7bf9cab139b3141c4644e5b3267deed5213George Mountimport android.databinding.tool.expr.UnaryExpr
39fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.ext.androidId
40fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.ext.lazy
41fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.ext.br
42fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.ResourceExpr
43fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.expr.BracketExpr
44e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyarimport android.databinding.tool.ext;
45e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyarimport android.databinding.tool.util.Log
46e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyarimport java.util.BitSet
47e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyarimport java.util.Arrays
48fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.Callable
49fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelAnalyzer
5096e1c821dd446d1ed78f8ae61131550588f60a24George Mountimport java.util.ArrayList
5134a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mountimport java.util.HashMap
5243596c2b2997e40b709627419732100d78a62ff0Yigit Boyar
53d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun String.stripNonJava() = this.split("[^a-zA-Z0-9]").map{ it.trim() }.joinToCamelCaseAsVar()
54d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
55019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarenum class Scope {
56019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    FIELD
57019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    METHOD
58019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    FLAG
59019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    EXECUTE_PENDING_METHOD
60019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    CONSTRUCTOR_PARAM
61019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar}
62019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
63d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarclass ExprModelExt {
64019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    val usedFieldNames = hashMapOf<Scope, MutableSet<String>>();
65019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    {
66019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        Scope.values().forEach { usedFieldNames[it] = hashSetOf<String>() }
67019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    }
68d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    val localizedFlags = arrayListOf<FlagSet>()
69d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
70d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun localizeFlag(set : FlagSet, name:String) : FlagSet {
71d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        localizedFlags.add(set)
72019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        val result = getUniqueName(name, Scope.FLAG)
73d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        set.setLocalName(result)
74d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return set
75d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
76d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
77019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    fun getUniqueName(base : String, scope : Scope) : String {
78d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        var candidate = base
79d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        var i = 0
80019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        while (usedFieldNames[scope].contains(candidate)) {
81d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            i ++
82d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            candidate = base + i
83d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
84019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        usedFieldNames[scope].add(candidate)
85d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return candidate
86d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
87d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
88d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
89de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval ExprModel.ext by Delegates.lazy { target : ExprModel ->
90d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    ExprModelExt()
91d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
92d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
93019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarfun ExprModel.getUniqueFieldName(base : String) : String = ext.getUniqueName(base, Scope.FIELD)
94019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarfun ExprModel.getUniqueMethodName(base : String) : String = ext.getUniqueName(base, Scope.METHOD)
95019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarfun ExprModel.getUniqueFlagName(base : String) : String = ext.getUniqueName(base, Scope.FLAG)
96019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarfun ExprModel.getConstructorParamName(base : String) : String = ext.getUniqueName(base, Scope.CONSTRUCTOR_PARAM)
97d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
98d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun ExprModel.localizeFlag(set : FlagSet, base : String) : FlagSet = ext.localizeFlag(set, base)
99d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
100019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar// not necessarily unique. Uniqueness is solved per scope
101019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarval BindingTarget.readableName by Delegates.lazy { target: BindingTarget ->
10200da715547ee7d5d38a3b8576090ca427a94daa5George Mount    if (target.getId() == null) {
103019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        "boundView" + indexFromTag(target.getTag())
10400da715547ee7d5d38a3b8576090ca427a94daa5George Mount    } else {
105019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        target.getId().androidId().stripNonJava()
10600da715547ee7d5d38a3b8576090ca427a94daa5George Mount    }
107d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
1087551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar
109de38dd3ef0577d25b2d59863603abe5750d0c231George Mountfun BindingTarget.superConversion(variable : String) : String {
11096e1c821dd446d1ed78f8ae61131550588f60a24George Mount    if (getResolvedType() != null && getResolvedType().extendsViewStub()) {
111de38dd3ef0577d25b2d59863603abe5750d0c231George Mount        return "new android.databinding.ViewStubProxy((android.view.ViewStub) ${variable})"
112de38dd3ef0577d25b2d59863603abe5750d0c231George Mount    } else {
113de38dd3ef0577d25b2d59863603abe5750d0c231George Mount        return "(${interfaceType}) ${variable}"
114de38dd3ef0577d25b2d59863603abe5750d0c231George Mount    }
115de38dd3ef0577d25b2d59863603abe5750d0c231George Mount}
116de38dd3ef0577d25b2d59863603abe5750d0c231George Mount
117019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarval BindingTarget.fieldName : String by Delegates.lazy { target : BindingTarget ->
118019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    val name : String
119019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    if (target.getId() == null) {
120019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        name = "m${target.readableName}"
121019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    } else {
122019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        name = target.readableName
12334a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount    }
124019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    target.getModel().getUniqueFieldName(name)
125d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
126d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
127de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval BindingTarget.androidId by Delegates.lazy { target : BindingTarget ->
12843596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    "R.id.${target.getId().androidId()}"
129d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
130d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
131de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval BindingTarget.interfaceType by Delegates.lazy { target : BindingTarget ->
132de38dd3ef0577d25b2d59863603abe5750d0c231George Mount    if (target.getResolvedType() != null && target.getResolvedType().extendsViewStub()) {
133de38dd3ef0577d25b2d59863603abe5750d0c231George Mount        "android.databinding.ViewStubProxy"
134de38dd3ef0577d25b2d59863603abe5750d0c231George Mount    } else {
135de38dd3ef0577d25b2d59863603abe5750d0c231George Mount        target.getInterfaceType()
136de38dd3ef0577d25b2d59863603abe5750d0c231George Mount    }
137de38dd3ef0577d25b2d59863603abe5750d0c231George Mount}
138de38dd3ef0577d25b2d59863603abe5750d0c231George Mount
139019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarval BindingTarget.constructorParamName by Delegates.lazy { target : BindingTarget ->
140019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    target.getModel().getConstructorParamName(target.readableName)
141d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
142d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
143019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar// not necessarily unique. Uniqueness is decided per scope
144de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.readableName by Delegates.lazy { expr : Expr ->
145019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    val stripped = "${expr.getUniqueKey().stripNonJava()}"
146019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    Log.d { "readableUniqueName for [${System.identityHashCode(expr)}] ${expr.getUniqueKey()} is $stripped" }
147019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    stripped
148de38dd3ef0577d25b2d59863603abe5750d0c231George Mount}
149de38dd3ef0577d25b2d59863603abe5750d0c231George Mount
150de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.fieldName by Delegates.lazy { expr : Expr ->
151019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    expr.getModel().getUniqueFieldName("m${expr.readableName.capitalize()}")
152d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
153d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
154019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyarval Expr.executePendingLocalName by Delegates.lazy { expr : Expr ->
155019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    if(expr.isVariable()) expr.fieldName else "${expr.getModel().ext.getUniqueName(expr.readableName, Scope.EXECUTE_PENDING_METHOD)}"
156d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
157d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
158de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.setterName by Delegates.lazy { expr : Expr ->
159019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    expr.getModel().getUniqueMethodName("set${expr.readableName.capitalize()}")
160d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
161d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
162de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.onChangeName by Delegates.lazy { expr : Expr ->
163019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    expr.getModel().getUniqueMethodName("onChange${expr.readableName.capitalize()}")
164d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
165d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
166de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.getterName by Delegates.lazy { expr : Expr ->
167019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    expr.getModel().getUniqueMethodName("get${expr.readableName.capitalize()}")
168d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
169d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
170de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.dirtyFlagName by Delegates.lazy { expr : Expr ->
171019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    expr.getModel().getUniqueFlagName("sFlag${expr.readableName.capitalize()}")
172d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
173d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
174d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
175e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyarfun Expr.toCode(full : Boolean = false) : KCode = CodeGenUtil.toCode(this, full)
176d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
177d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun Expr.isVariable() = this is IdentifierExpr && this.isDynamic()
178d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
179d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun Expr.conditionalFlagName(output : Boolean, suffix : String) = "${dirtyFlagName}_${output}$suffix"
180d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
181d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
182de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.dirtyFlagSet by Delegates.lazy { expr : Expr ->
183d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar    FlagSet(expr.getInvalidFlags(), expr.getModel().getFlagBucketCount())
184d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
185d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
186de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.invalidateFlagSet by Delegates.lazy { expr : Expr ->
187d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar    FlagSet(expr.getId())
188d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
189d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
190de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.shouldReadFlagSet by Delegates.lazy { expr : Expr ->
191d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar    FlagSet(expr.getShouldReadFlags(), expr.getModel().getFlagBucketCount())
192d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
193d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
194de38dd3ef0577d25b2d59863603abe5750d0c231George Mountval Expr.conditionalFlags by Delegates.lazy { expr : Expr ->
195d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar    arrayListOf(FlagSet(expr.getRequirementFlagIndex(false)),
196d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar            FlagSet(expr.getRequirementFlagIndex(true)))
197d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
198d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
199d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun Expr.getRequirementFlagSet(expected : Boolean) : FlagSet = conditionalFlags[if(expected) 1 else 0]
200d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
201d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun FlagSet.notEmpty(cb : (suffix : String, value : Long) -> Unit) {
202d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    buckets.withIndex().forEach {
203d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (it.value != 0L) {
204d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            cb(getWordSuffix(it.index), buckets[it.index])
205d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
206d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
207d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
208d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
209d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun FlagSet.getWordSuffix(wordIndex : Int) : String {
210d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    return if(wordIndex == 0) "" else "_${wordIndex}"
211d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
212d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
213d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun FlagSet.localValue(bucketIndex : Int) =
214d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar        if (getLocalName() == null) binaryCode(bucketIndex)
215d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        else "${getLocalName()}${getWordSuffix(bucketIndex)}"
216d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
217d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyarfun FlagSet.binaryCode(bucketIndex : Int) = longToBinary(buckets[bucketIndex])
218d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar
219d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar
220d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyarfun longToBinary(l : Long) =
221d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar        "0b${java.lang.Long.toBinaryString(l)}L"
222d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
223d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun <T> FlagSet.mapOr(other : FlagSet, cb : (suffix : String, index : Int) -> T) : List<T> {
224d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    val min = Math.min(buckets.size(), other.buckets.size())
225d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    val result = arrayListOf<T>()
226d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    for (i in 0..(min - 1)) {
227d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // if these two can match by any chance, call the callback
228d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (intersect(other, i)) {
229d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            result.add(cb(getWordSuffix(i), i))
230d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
231d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
232d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    return result
233d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
234d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
23596e1c821dd446d1ed78f8ae61131550588f60a24George Mountfun indexFromTag(tag : String) : kotlin.Int {
23696e1c821dd446d1ed78f8ae61131550588f60a24George Mount    val startIndex : kotlin.Int
2377ff60c24c6de7ba0c674fe65a82ad4a88dab2e5dGeorge Mount    if (tag.startsWith("binding_")) {
2387ff60c24c6de7ba0c674fe65a82ad4a88dab2e5dGeorge Mount        startIndex = "binding_".length();
23996e1c821dd446d1ed78f8ae61131550588f60a24George Mount    } else {
24096e1c821dd446d1ed78f8ae61131550588f60a24George Mount        startIndex = tag.lastIndexOf('_') + 1
24196e1c821dd446d1ed78f8ae61131550588f60a24George Mount    }
24296e1c821dd446d1ed78f8ae61131550588f60a24George Mount    return Integer.parseInt(tag.substring(startIndex))
24396e1c821dd446d1ed78f8ae61131550588f60a24George Mount}
24496e1c821dd446d1ed78f8ae61131550588f60a24George Mount
24543596c2b2997e40b709627419732100d78a62ff0Yigit Boyarclass LayoutBinderWriter(val layoutBinder : LayoutBinder) {
246d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    val model = layoutBinder.getModel()
24734a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount    val indices = HashMap<BindingTarget, kotlin.Int>()
24843596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    val mDirtyFlags by Delegates.lazy {
24943596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        val fs = FlagSet(BitSet(), model.getFlagBucketCount());
25043596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        Arrays.fill(fs.buckets, -1)
25143596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        fs.setDynamic(true)
25243596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        model.localizeFlag(fs, "mDirtyFlags")
25343596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        fs
254d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
255d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
25643596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    val dynamics by Delegates.lazy { model.getExprMap().values().filter { it.isDynamic() } }
257dea555cf42dc3583604699c8c018d22681f56166George Mount    val className = layoutBinder.getImplementationName()
258d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
259dea555cf42dc3583604699c8c018d22681f56166George Mount    val baseClassName = "${layoutBinder.getClassName()}"
260d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
2617551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar    val includedBinders by Delegates.lazy {
2627551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar        layoutBinder.getBindingTargets().filter { it.isBinder() }
2637551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar    }
2647551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar
26543596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    val variables by Delegates.lazy {
26643596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        model.getExprMap().values().filterIsInstance(javaClass<IdentifierExpr>()).filter { it.isVariable() }
26743596c2b2997e40b709627419732100d78a62ff0Yigit Boyar    }
268d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
2695bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    val usedVariables by Delegates.lazy {
2705bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        variables.filter {it.isUsed()}
2715bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    }
272d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
27396e1c821dd446d1ed78f8ae61131550588f60a24George Mount    public fun write(minSdk : kotlin.Int) : String  {
2745bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        layoutBinder.resolveWhichExpressionsAreUsed()
27534a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        calculateIndices();
2765bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        return kcode("package ${layoutBinder.getPackage()};") {
277a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            nl("import ${layoutBinder.getModulePackage()}.R;")
278a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            nl("import ${layoutBinder.getModulePackage()}.BR;")
2795bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("import android.view.View;")
280dea555cf42dc3583604699c8c018d22681f56166George Mount            val classDeclaration : String
281dea555cf42dc3583604699c8c018d22681f56166George Mount            if (layoutBinder.hasVariations()) {
282dea555cf42dc3583604699c8c018d22681f56166George Mount                classDeclaration = "${className} extends ${baseClassName}"
283dea555cf42dc3583604699c8c018d22681f56166George Mount            } else {
284dea555cf42dc3583604699c8c018d22681f56166George Mount                classDeclaration = "${className} extends android.databinding.ViewDataBinding"
285dea555cf42dc3583604699c8c018d22681f56166George Mount            }
286dea555cf42dc3583604699c8c018d22681f56166George Mount            nl("public class ${classDeclaration} {") {
2874c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab(declareIncludeViews())
2885bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareViews())
2895bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareVariables())
29096e1c821dd446d1ed78f8ae61131550588f60a24George Mount                tab(declareConstructor(minSdk))
2915bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareInvalidateAll())
2925bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareLog())
2935bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareSetVariable())
2945bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(variableSettersAndGetters())
2955bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(onFieldChange())
2965bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
2974c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab(executePendingBindings())
2985bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar
2995bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab(declareDirtyFlags())
300dea555cf42dc3583604699c8c018d22681f56166George Mount                if (!layoutBinder.hasVariations()) {
301dea555cf42dc3583604699c8c018d22681f56166George Mount                    tab(declareFactories())
302dea555cf42dc3583604699c8c018d22681f56166George Mount                }
3035bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            }
3045bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("}")
3055bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            tab(flagMapping())
3065bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            tab("//end")
3075bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        }.generate()
3085bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar    }
30934a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount    fun calculateIndices() : Unit {
31096e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val taggedViews = layoutBinder.getBindingTargets().filter{
31196e1c821dd446d1ed78f8ae61131550588f60a24George Mount            it.isUsed() && it.getTag() != null && !it.isBinder()
31234a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        }
31396e1c821dd446d1ed78f8ae61131550588f60a24George Mount        taggedViews.forEach {
31496e1c821dd446d1ed78f8ae61131550588f60a24George Mount            indices.put(it, indexFromTag(it.getTag()))
31596e1c821dd446d1ed78f8ae61131550588f60a24George Mount        }
31696e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val indexStart = maxIndex() + 1
31796e1c821dd446d1ed78f8ae61131550588f60a24George Mount        layoutBinder.getBindingTargets().filter{
31896e1c821dd446d1ed78f8ae61131550588f60a24George Mount            it.isUsed() && !taggedViews.contains(it)
31996e1c821dd446d1ed78f8ae61131550588f60a24George Mount        }.withIndex().forEach {
32096e1c821dd446d1ed78f8ae61131550588f60a24George Mount            indices.put(it.value, it.index + indexStart)
32134a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        }
32234a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount    }
3234c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount    fun declareIncludeViews() = kcode("") {
32496e1c821dd446d1ed78f8ae61131550588f60a24George Mount        nl("private static final android.databinding.ViewDataBinding.IncludedLayoutIndex[][] sIncludes;")
3254c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount        nl("private static final android.util.SparseIntArray sViewsWithIds;")
3264c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount        nl("static {") {
3274c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            val hasBinders = layoutBinder.getBindingTargets().firstOrNull{ it.isUsed() && it.isBinder()} != null
3284c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            if (!hasBinders) {
3294c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab("sIncludes = null;")
33000da715547ee7d5d38a3b8576090ca427a94daa5George Mount            } else {
33196e1c821dd446d1ed78f8ae61131550588f60a24George Mount                val numBindings = layoutBinder.getBindingTargets().filter{ it.isUsed() }.count()
33296e1c821dd446d1ed78f8ae61131550588f60a24George Mount                tab("sIncludes = new android.databinding.ViewDataBinding.IncludedLayoutIndex[${numBindings}][];")
33396e1c821dd446d1ed78f8ae61131550588f60a24George Mount                val includeMap = HashMap<BindingTarget, ArrayList<BindingTarget>>()
33496e1c821dd446d1ed78f8ae61131550588f60a24George Mount                layoutBinder.getBindingTargets().filter{ it.isUsed() && it.isBinder() }.forEach {
33596e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    val includeTag = it.getTag();
33696e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    val parent = layoutBinder.getBindingTargets().firstOrNull {
33796e1c821dd446d1ed78f8ae61131550588f60a24George Mount                        it.isUsed() && !it.isBinder() && includeTag.equals(it.getTag())
33896e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    }
33996e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    if (parent == null) {
34096e1c821dd446d1ed78f8ae61131550588f60a24George Mount                        throw IllegalStateException("Could not find parent of include file")
34196e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    }
34296e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    var list = includeMap.get(parent)
34396e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    if (list == null) {
34496e1c821dd446d1ed78f8ae61131550588f60a24George Mount                        list = ArrayList<BindingTarget>()
34596e1c821dd446d1ed78f8ae61131550588f60a24George Mount                        includeMap.put(parent, list)
34696e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    }
34796e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    list.add(it)
3484c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                }
34996e1c821dd446d1ed78f8ae61131550588f60a24George Mount
35096e1c821dd446d1ed78f8ae61131550588f60a24George Mount                includeMap.keySet().forEach {
35196e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    val index = indices.get(it)
35296e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    tab("sIncludes[${index}] = new android.databinding.ViewDataBinding.IncludedLayoutIndex[] {") {
35396e1c821dd446d1ed78f8ae61131550588f60a24George Mount                        includeMap.get(it).forEach {
35496e1c821dd446d1ed78f8ae61131550588f60a24George Mount                            val bindingIndex = indices.get(it)
35596e1c821dd446d1ed78f8ae61131550588f60a24George Mount                            val layoutName = it.getIncludedLayout()
35696e1c821dd446d1ed78f8ae61131550588f60a24George Mount                            tab("new android.databinding.ViewDataBinding.IncludedLayoutIndex(\"${layoutName}\", ${bindingIndex}, R.layout.${layoutName}),")
35796e1c821dd446d1ed78f8ae61131550588f60a24George Mount                        }
35896e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    }
35996e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    tab("};")
36096e1c821dd446d1ed78f8ae61131550588f60a24George Mount                }
36196e1c821dd446d1ed78f8ae61131550588f60a24George Mount            }
36296e1c821dd446d1ed78f8ae61131550588f60a24George Mount            val viewsWithIds = layoutBinder.getBindingTargets().filter {
36396e1c821dd446d1ed78f8ae61131550588f60a24George Mount                it.isUsed() && !it.isBinder() && (!it.supportsTag() || (it.getId() != null && it.getTag() == null))
36400da715547ee7d5d38a3b8576090ca427a94daa5George Mount            }
36596e1c821dd446d1ed78f8ae61131550588f60a24George Mount            if (viewsWithIds.isEmpty()) {
3664c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab("sViewsWithIds = null;")
36700da715547ee7d5d38a3b8576090ca427a94daa5George Mount            } else {
3684c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab("sViewsWithIds = new android.util.SparseIntArray();")
36996e1c821dd446d1ed78f8ae61131550588f60a24George Mount                viewsWithIds.forEach {
37034a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                    tab("sViewsWithIds.put(${it.androidId}, ${indices.get(it)});")
3714c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                }
37200da715547ee7d5d38a3b8576090ca427a94daa5George Mount            }
3734c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount        }
3744c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount        nl("}")
3754c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount    }
37696e1c821dd446d1ed78f8ae61131550588f60a24George Mount
37796e1c821dd446d1ed78f8ae61131550588f60a24George Mount    fun maxIndex() : kotlin.Int {
37896e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val maxIndex = indices.values().max()
37996e1c821dd446d1ed78f8ae61131550588f60a24George Mount        if (maxIndex == null) {
38096e1c821dd446d1ed78f8ae61131550588f60a24George Mount            return -1
38196e1c821dd446d1ed78f8ae61131550588f60a24George Mount        } else {
38296e1c821dd446d1ed78f8ae61131550588f60a24George Mount            return maxIndex
38396e1c821dd446d1ed78f8ae61131550588f60a24George Mount        }
38496e1c821dd446d1ed78f8ae61131550588f60a24George Mount    }
38596e1c821dd446d1ed78f8ae61131550588f60a24George Mount
38696e1c821dd446d1ed78f8ae61131550588f60a24George Mount    fun declareConstructor(minSdk : kotlin.Int) = kcode("") {
38796e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val bindingCount = maxIndex() + 1
38896e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val parameterType : String
38996e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val superParam : String
39096e1c821dd446d1ed78f8ae61131550588f60a24George Mount        if (layoutBinder.isMerge()) {
39196e1c821dd446d1ed78f8ae61131550588f60a24George Mount            parameterType = "View[]"
39296e1c821dd446d1ed78f8ae61131550588f60a24George Mount            superParam = "root[0]"
39396e1c821dd446d1ed78f8ae61131550588f60a24George Mount        } else {
39496e1c821dd446d1ed78f8ae61131550588f60a24George Mount            parameterType = "View"
39596e1c821dd446d1ed78f8ae61131550588f60a24George Mount            superParam = "root"
39696e1c821dd446d1ed78f8ae61131550588f60a24George Mount        }
39796e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val rootTagsSupported = minSdk >= 14
398dea555cf42dc3583604699c8c018d22681f56166George Mount        if (layoutBinder.hasVariations()) {
399dea555cf42dc3583604699c8c018d22681f56166George Mount            nl("")
40096e1c821dd446d1ed78f8ae61131550588f60a24George Mount            nl("public ${className}(${parameterType} root) {") {
40196e1c821dd446d1ed78f8ae61131550588f60a24George Mount                tab("this(${superParam}, mapBindings(root, ${bindingCount}, sIncludes, sViewsWithIds));")
402dea555cf42dc3583604699c8c018d22681f56166George Mount            }
403dea555cf42dc3583604699c8c018d22681f56166George Mount            nl("}")
40496e1c821dd446d1ed78f8ae61131550588f60a24George Mount            nl("private ${className}(${parameterType} root, Object[] bindings) {") {
40596e1c821dd446d1ed78f8ae61131550588f60a24George Mount                tab("super(${superParam}, ${model.getObservables().size()}") {
40696e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    layoutBinder.getSortedTargets().filter { it.getId() != null }.forEach {
407dea555cf42dc3583604699c8c018d22681f56166George Mount                        tab(", ${fieldConversion(it)}")
40834a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                    }
409dea555cf42dc3583604699c8c018d22681f56166George Mount                    tab(");")
41034a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                }
41134a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            }
412dea555cf42dc3583604699c8c018d22681f56166George Mount        } else {
41396e1c821dd446d1ed78f8ae61131550588f60a24George Mount            nl("public ${baseClassName}(${parameterType} root) {") {
41496e1c821dd446d1ed78f8ae61131550588f60a24George Mount                tab("super(${superParam}, ${model.getObservables().size()});")
41596e1c821dd446d1ed78f8ae61131550588f60a24George Mount                tab("final Object[] bindings = mapBindings(root, ${bindingCount}, sIncludes, sViewsWithIds);")
416dea555cf42dc3583604699c8c018d22681f56166George Mount            }
417dea555cf42dc3583604699c8c018d22681f56166George Mount        }
41896e1c821dd446d1ed78f8ae61131550588f60a24George Mount        tab("setRootTag(root);")
41996e1c821dd446d1ed78f8ae61131550588f60a24George Mount        val taggedViews = layoutBinder.getSortedTargets().filter{it.isUsed()}
420dea555cf42dc3583604699c8c018d22681f56166George Mount        taggedViews.forEach {
421dea555cf42dc3583604699c8c018d22681f56166George Mount            if (!layoutBinder.hasVariations() || it.getId() == null) {
422dea555cf42dc3583604699c8c018d22681f56166George Mount                tab("this.${it.fieldName} = ${fieldConversion(it)};")
423dea555cf42dc3583604699c8c018d22681f56166George Mount            }
424dea555cf42dc3583604699c8c018d22681f56166George Mount            if (!it.isBinder()) {
425de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                if (it.getResolvedType() != null && it.getResolvedType().extendsViewStub()) {
426de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                    tab("this.${it.fieldName}.setContainingBinding(this);")
427de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                }
42896e1c821dd446d1ed78f8ae61131550588f60a24George Mount                if (it.supportsTag() && it.getTag() != null &&
4297ff60c24c6de7ba0c674fe65a82ad4a88dab2e5dGeorge Mount                        (rootTagsSupported || it.getTag().startsWith("binding_"))) {
430dea555cf42dc3583604699c8c018d22681f56166George Mount                    val originalTag = it.getOriginalTag();
431dea555cf42dc3583604699c8c018d22681f56166George Mount                    var tagValue = "null"
432dea555cf42dc3583604699c8c018d22681f56166George Mount                    if (originalTag != null) {
433dea555cf42dc3583604699c8c018d22681f56166George Mount                        tagValue = "\"${originalTag}\""
434dea555cf42dc3583604699c8c018d22681f56166George Mount                        if (originalTag.startsWith("@")) {
435dea555cf42dc3583604699c8c018d22681f56166George Mount                            var packageName = layoutBinder.getModulePackage()
436dea555cf42dc3583604699c8c018d22681f56166George Mount                            if (originalTag.startsWith("@android:")) {
437dea555cf42dc3583604699c8c018d22681f56166George Mount                                packageName = "android"
43800da715547ee7d5d38a3b8576090ca427a94daa5George Mount                            }
439dea555cf42dc3583604699c8c018d22681f56166George Mount                            val slashIndex = originalTag.indexOf('/')
440dea555cf42dc3583604699c8c018d22681f56166George Mount                            val resourceId = originalTag.substring(slashIndex + 1)
441dea555cf42dc3583604699c8c018d22681f56166George Mount                            tagValue = "root.getResources().getString(${packageName}.R.string.${resourceId})"
44200da715547ee7d5d38a3b8576090ca427a94daa5George Mount                        }
44300da715547ee7d5d38a3b8576090ca427a94daa5George Mount                    }
444dea555cf42dc3583604699c8c018d22681f56166George Mount                    tab("this.${it.fieldName}.setTag(${tagValue});")
4457551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar                }
446d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
447d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
448dea555cf42dc3583604699c8c018d22681f56166George Mount        tab("invalidateAll();");
4490fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("}")
450d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
451d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
452dea555cf42dc3583604699c8c018d22681f56166George Mount    fun fieldConversion(target : BindingTarget) : String {
453dea555cf42dc3583604699c8c018d22681f56166George Mount        if (!target.isUsed()) {
454dea555cf42dc3583604699c8c018d22681f56166George Mount            return "null"
455dea555cf42dc3583604699c8c018d22681f56166George Mount        } else {
45696e1c821dd446d1ed78f8ae61131550588f60a24George Mount            val index = indices.get(target)
457dea555cf42dc3583604699c8c018d22681f56166George Mount            if (index == null) {
45896e1c821dd446d1ed78f8ae61131550588f60a24George Mount                throw IllegalStateException("Unknown binding target")
459dea555cf42dc3583604699c8c018d22681f56166George Mount            }
46096e1c821dd446d1ed78f8ae61131550588f60a24George Mount            val variableName = "bindings[${index}]"
461dea555cf42dc3583604699c8c018d22681f56166George Mount            return target.superConversion(variableName)
462dea555cf42dc3583604699c8c018d22681f56166George Mount        }
463dea555cf42dc3583604699c8c018d22681f56166George Mount    }
464dea555cf42dc3583604699c8c018d22681f56166George Mount
465d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareInvalidateAll() = kcode("") {
4667551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar        nl("@Override")
4677551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar        nl("public void invalidateAll() {") {
468019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            val fs = FlagSet(layoutBinder.getModel().getInvalidateAnyBitSet(),
469019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                    layoutBinder.getModel().getFlagBucketCount());
4701c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar            tab("synchronized(this) {") {
4711c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                for (i in (0..(mDirtyFlags.buckets.size() - 1))) {
4721c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                    tab("${mDirtyFlags.localValue(i)} = ${fs.localValue(i)};")
4731c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                }
4741c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar            } tab("}")
4755bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            includedBinders.filter{it.isUsed()}.forEach { binder ->
4767551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar                tab("${binder.fieldName}.invalidateAll();")
4777551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar            }
478d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
4790fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("}")
480d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
481d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
482d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareSetVariable() = kcode("") {
4830fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("public boolean setVariable(int variableId, Object variable) {") {
484d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("switch(variableId) {") {
4855bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                usedVariables.forEach {
48643596c2b2997e40b709627419732100d78a62ff0Yigit Boyar                    tab ("case ${it.getName().br()} :") {
487d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        tab("${it.setterName}((${it.getResolvedType().toJavaCode()}) variable);")
488d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        tab("return true;")
489d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
490d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
491d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
492d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("}")
493d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("return false;")
494d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
4950fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("}")
496d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
497d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
498d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareLog() = kcode("") {
4990fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("private void log(String msg, long i) {") {
500d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("""android.util.Log.d("BINDER", msg + ":" + Long.toHexString(i));""")
5010fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        }
5020fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("}")
503d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
504d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
505d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun variableSettersAndGetters() = kcode("") {
5065bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        variables.filterNot{it.isUsed()}.forEach {
507019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            nl("public void ${it.setterName}(${it.getResolvedType().toJavaCode()} ${it.readableName}) {") {
5085bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab("// not used, ignore")
5095bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            }
5105bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("}")
5115bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("")
5125bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("public ${it.getResolvedType().toJavaCode()} ${it.getterName}() {") {
5135bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar                tab("return ${it.getDefaultValue()};")
5145bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            }
5155bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            nl("}")
5165bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        }
5175bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        usedVariables.forEach {
51818243f6f1b7527272ef4feccdf4327d80d9f2241George Mount            if (it.getUserDefinedType() != null) {
519019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                nl("public void ${it.setterName}(${it.getResolvedType().toJavaCode()} ${it.readableName}) {") {
52018243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    if (it.isObservable()) {
521019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                        tab("updateRegistration(${it.getId()}, ${it.readableName});");
52218243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    }
523019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                    tab("this.${it.fieldName} = ${it.readableName};")
52418243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    // set dirty flags!
52518243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    val flagSet = it.invalidateFlagSet
5261c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                    tab("synchronized(this) {") {
5271c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                        mDirtyFlags.mapOr(flagSet) { suffix, index ->
5281c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                            tab("${mDirtyFlags.getLocalName()}$suffix |= ${flagSet.localValue(index)};")
5291c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                        }
5301c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                    } tab ("}")
53118243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    tab("super.requestRebind();")
532d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
53318243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                nl("}")
53418243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                nl("")
53518243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                nl("public ${it.getResolvedType().toJavaCode()} ${it.getterName}() {") {
53618243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                    tab("return ${it.fieldName};")
537d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
53818243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                nl("}")
539d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
540d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
541d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
542d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
543d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun onFieldChange() = kcode("") {
54434a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        nl("@Override")
54534a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        nl("protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {") {
5464c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            tab("switch (localFieldId) {") {
547d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                model.getObservables().forEach {
548d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    tab("case ${it.getId()} :") {
549d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        tab("return ${it.onChangeName}((${it.getResolvedType().toJavaCode()}) object, fieldId);")
550d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
551d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
552d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
553d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("}")
554d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tab("return false;")
555d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
55634a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        nl("}")
55734a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount        nl("")
558d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
559d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        model.getObservables().forEach {
560019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            nl("private boolean ${it.onChangeName}(${it.getResolvedType().toJavaCode()} ${it.readableName}, int fieldId) {") {
561d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                tab("switch (fieldId) {", {
562d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    val accessedFields: List<FieldAccessExpr> = it.getParents().filterIsInstance(javaClass<FieldAccessExpr>())
563d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    accessedFields.filter { it.canBeInvalidated() }
564d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            .groupBy { it.getName() }
565d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            .forEach {
56643596c2b2997e40b709627419732100d78a62ff0Yigit Boyar                                tab("case ${it.key.br()}:") {
567d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                                    val field = it.value.first()
5681c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                                    tab("synchronized(this) {") {
5691c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                                        mDirtyFlags.mapOr(field.invalidateFlagSet) { suffix, index ->
5701c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                                            tab("${mDirtyFlags.localValue(index)} |= ${field.invalidateFlagSet.localValue(index)};")
5711c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                                        }
5721c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                                    } tab("}")
573d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                                    tab("return true;")
574d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                                }
575d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
576d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            }
57743596c2b2997e40b709627419732100d78a62ff0Yigit Boyar                    tab("case ${"".br()}:") {
578d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        val flagSet = it.invalidateFlagSet
5791c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                        tab("synchronized(this) {") {
5801c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                            mDirtyFlags.mapOr(flagSet) { suffix, index ->
5811c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                                tab("${mDirtyFlags.getLocalName()}$suffix |= ${flagSet.localValue(index)};")
5821c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                            }
5831c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                        } tab("}")
584d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        tab("return true;")
585d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
586d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
587d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                })
588d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                tab("}")
589d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                tab("return false;")
590d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
59134a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            nl("}")
59234a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            nl("")
593d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
594d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
595d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
596d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareViews() = kcode("// views") {
597dea555cf42dc3583604699c8c018d22681f56166George Mount        val oneLayout = !layoutBinder.hasVariations();
59896e1c821dd446d1ed78f8ae61131550588f60a24George Mount        layoutBinder.getSortedTargets().filter {it.isUsed() && (oneLayout || it.getId() == null)}.forEach {
599dea555cf42dc3583604699c8c018d22681f56166George Mount            val access : String
600dea555cf42dc3583604699c8c018d22681f56166George Mount            if (oneLayout && it.getId() != null) {
601dea555cf42dc3583604699c8c018d22681f56166George Mount                access = "public"
602dea555cf42dc3583604699c8c018d22681f56166George Mount            } else {
603dea555cf42dc3583604699c8c018d22681f56166George Mount                access = "private"
604dea555cf42dc3583604699c8c018d22681f56166George Mount            }
605dea555cf42dc3583604699c8c018d22681f56166George Mount            nl("${access} final ${it.interfaceType} ${it.fieldName};")
606d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
607d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
608d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
609d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareVariables() = kcode("// variables") {
6105bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar        usedVariables.forEach {
6110fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar            nl("private ${it.getResolvedType().toJavaCode()} ${it.fieldName};")
612d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
613d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
614d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
615d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun declareDirtyFlags() = kcode("// dirty flag") {
616d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        model.ext.localizedFlags.forEach { flag ->
617de38dd3ef0577d25b2d59863603abe5750d0c231George Mount            flag.notEmpty { suffix, value ->
6180fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                nl("private")
619d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                app(" ", if(flag.isDynamic()) null else "static final");
620d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar                app(" ", " ${flag.type} ${flag.getLocalName()}$suffix = ${longToBinary(value)};")
621d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
622d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
623d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
624d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
625d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun flagMapping() = kcode("/* flag mapping") {
626d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (model.getFlagMapping() != null) {
627d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            val mapping = model.getFlagMapping()
628d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (i in mapping.indices) {
629d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                tab("flag $i: ${mapping[i]}")
630d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
631d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
632d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        nl("flag mapping end*/")
633d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
634d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
6354c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount    fun executePendingBindings() = kcode("") {
6360fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("@Override")
637e725f0d81e1b07e88f819be9a82181eeeb680dbfGeorge Mount        nl("protected void executeBindings() {") {
638d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            val tmpDirtyFlags = FlagSet(mDirtyFlags.buckets)
639d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            tmpDirtyFlags.setLocalName("dirtyFlags");
640d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            for (i in (0..mDirtyFlags.buckets.size() - 1)) {
6411c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                tab("${tmpDirtyFlags.type} ${tmpDirtyFlags.localValue(i)} = 0;")
642d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
6431c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar            tab("synchronized(this) {") {
6441c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                for (i in (0..mDirtyFlags.buckets.size() - 1)) {
6451c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                    tab("${tmpDirtyFlags.localValue(i)} = ${mDirtyFlags.localValue(i)};")
6461c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                    tab("${mDirtyFlags.localValue(i)} = 0;")
6471c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar                }
6481c44adacab2c1baa937a604da136024f1e92a088Yigit Boyar            } tab("}")
649e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar            model.getPendingExpressions().filterNot {!it.canBeEvaluatedToAVariable() || it.isVariable()}.forEach {
650019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                tab("${it.getResolvedType().toJavaCode()} ${it.executePendingLocalName} = ${it.getDefaultValue()};")
651d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
652019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            Log.d {"writing executePendingBindings for $className"}
653d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            do {
65474f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar                val batch = ExprModel.filterShouldRead(model.getPendingExpressions()).toArrayList()
655019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                Log.d {"batch: $batch"}
656d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                val mJustRead = arrayListOf<Expr>()
657d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                while (!batch.none()) {
6580fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                    val readNow = batch.filter { it.shouldReadNow(mJustRead) }
659d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    if (readNow.isEmpty()) {
660d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        throw IllegalStateException("do not know what I can read. bailing out ${batch.joinToString("\n")}")
661d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
66243596c2b2997e40b709627419732100d78a62ff0Yigit Boyar                    Log.d { "new read now. batch size: ${batch.size()}, readNow size: ${readNow.size()}" }
663d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
664d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    readNow.forEach {
6650fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                        nl(readWithDependants(it, mJustRead, batch, tmpDirtyFlags))
666d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
667d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    batch.removeAll(mJustRead)
668d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
6690fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                tab("// batch finished")
670d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            } while(model.markBitsRead())
671d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
672d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            //
67396e1c821dd446d1ed78f8ae61131550588f60a24George Mount            layoutBinder.getSortedTargets().filter { it.isUsed() }
674d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    .flatMap { it.getBindings() }
675d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    .groupBy { it.getExpr() }
676d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    .forEach {
677d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        val flagSet = it.key.dirtyFlagSet
678d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        tab("if (${tmpDirtyFlags.mapOr(flagSet){ suffix, index ->
679d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            "(${tmpDirtyFlags.localValue(index)} & ${flagSet.localValue(index)}) != 0"
680d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        }.joinToString(" || ")
681d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        }) {") {
682d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            it.value.forEach { binding ->
68397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar                                tab("// api target ${binding.getMinApi()}")
68434a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                                val fieldName : String
68534a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                                if (binding.getTarget().getViewClass().
68634a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                                        equals(binding.getTarget().getInterfaceType())) {
68734a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                                    fieldName = "this.${binding.getTarget().fieldName}"
68834a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                                } else {
68934a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                                    fieldName = "((${binding.getTarget().getViewClass()}) this.${binding.getTarget().fieldName})"
69034a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                                }
691e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar                                val bindingCode = binding.toJavaCode(fieldName)
69297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar                                if (binding.getMinApi() > 1) {
6934c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                                    tab("if(getBuildSdkInt() >= ${binding.getMinApi()}) {") {
69497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar                                        tab("$bindingCode;")
69597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar                                    }
69697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar                                    tab("}")
69797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar                                } else {
69897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar                                    tab("$bindingCode;")
69997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar                                }
700d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                            }
701d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        }
702d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        tab("}")
703d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
7045bf3700759ff21696becadd4e6fcfe2c0db6cb83Yigit Boyar            includedBinders.filter{it.isUsed()}.forEach { binder ->
7054c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount                tab("${binder.fieldName}.executePendingBindings();")
7067551861a29997eac7eaf6318e4d9f1cebd8b81d6Yigit Boyar            }
70796e1c821dd446d1ed78f8ae61131550588f60a24George Mount            layoutBinder.getSortedTargets().filter{
708de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                it.isUsed() && it.getResolvedType() != null && it.getResolvedType().extendsViewStub()
709de38dd3ef0577d25b2d59863603abe5750d0c231George Mount            }.forEach {
710de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                tab("if (${it.fieldName}.getBinding() != null) {") {
711de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                    tab("${it.fieldName}.getBinding().executePendingBindings();")
712de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                }
713de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                tab("}")
714de38dd3ef0577d25b2d59863603abe5750d0c231George Mount            }
715d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
7160fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        nl("}")
717d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
718d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
719d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar    fun readWithDependants(expr : Expr, mJustRead : MutableList<Expr>, batch : MutableList<Expr>,
720d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar            tmpDirtyFlags : FlagSet, inheritedFlags : FlagSet? = null) : KCode = kcode("") {
721d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mJustRead.add(expr)
722019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        Log.d { "$className / readWithDependants: ${expr.getUniqueKey()}" }
723d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        val flagSet = expr.shouldReadFlagSet
724d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar        val needsIfWrapper = inheritedFlags == null || !flagSet.bitsEqual(inheritedFlags)
725019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        Log.d { "flag set:$flagSet . inherited flags: $inheritedFlags. need another if: $needsIfWrapper"}
726d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar        val ifClause = "if (${tmpDirtyFlags.mapOr(flagSet){ suffix, index ->
72743596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            "(${tmpDirtyFlags.localValue(index)} & ${flagSet.localValue(index)}) != 0"
72843596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        }.joinToString(" || ")
729d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar        })"
730d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar
731d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar        val readCode = kcode("") {
732e9b33bac04bb1ce1444d7f1744fcec1ecd3a57daYigit Boyar            if (expr.canBeEvaluatedToAVariable() && !expr.isVariable()) {
733d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                // it is not a variable read it.
734d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                tab("// read ${expr.getUniqueKey()}")
735d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                // create an if case for all dependencies that might be null
736d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                val nullables = expr.getDependencies().filter {
737e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount                    it.isMandatory() && it.getOther().getResolvedType().isNullable()
73874f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar                }.map { it.getOther() }
739d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (!expr.isEqualityCheck() && nullables.isNotEmpty()) {
740019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                    tab ("if ( ${nullables.map { "${it.executePendingLocalName} != null" }.joinToString(" && ")}) {") {
741019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                        tab("${expr.executePendingLocalName}").app(" = ", expr.toCode(true)).app(";")
742d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
743d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    tab("}")
744d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                } else {
745019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                    tab("${expr.executePendingLocalName}").app(" = ", expr.toCode(true)).app(";")
746d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
7477920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount                if (expr.isObservable()) {
748019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                    tab("updateRegistration(${expr.getId()}, ${expr.executePendingLocalName});")
749d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
7500fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar            }
751d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
7520fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar            // if I am the condition for an expression, set its flag
7530fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar            val conditionals = expr.getDependants().filter { !it.isConditional()
7540fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                    && it.getDependant() is TernaryExpr && (it.getDependant() as TernaryExpr).getPred() == expr }
7550fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                    .map { it.getDependant() }
7560fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar            if (conditionals.isNotEmpty()) {
7570fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                tab("// setting conditional flags")
758019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                tab("if (${expr.executePendingLocalName}) {") {
7590fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                    conditionals.forEach {
7600fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                        val set = it.getRequirementFlagSet(true)
7610fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                        mDirtyFlags.mapOr(set) { suffix , index ->
7620fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                            tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
763d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                        }
764d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    }
765d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
7660fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                tab("} else {") {
7670fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                    conditionals.forEach {
7680fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                        val set = it.getRequirementFlagSet(false)
7690fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                        mDirtyFlags.mapOr(set) { suffix , index ->
7700fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                            tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
7710fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                        }
7720fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                    }
7730fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                } tab("}")
774d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
7750fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
776d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            val chosen = expr.getDependants().filter {
777d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar                val dependant = it.getDependant()
778d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar                batch.contains(dependant) &&
779d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar                        dependant.shouldReadFlagSet.andNot(flagSet).isEmpty() &&
780d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar                        dependant.shouldReadNow(mJustRead)
781d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
782d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (chosen.isNotEmpty()) {
783d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar                val nextInheritedFlags = if (needsIfWrapper) flagSet else inheritedFlags
784d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                chosen.forEach {
785d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar                    nl(readWithDependants(it.getDependant(), mJustRead, batch, tmpDirtyFlags, nextInheritedFlags))
786d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
787d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
788d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
789d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar        if (needsIfWrapper) {
790d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar            tab(ifClause) {
791d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar                app(" {")
792d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar                nl(readCode)
793d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar            }
794d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar            tab("}")
795d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar        } else {
796d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar            nl(readCode)
797d8c8ec27ed2ec0b11fa37f476395ce27834471f0Yigit Boyar        }
798d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
79943596c2b2997e40b709627419732100d78a62ff0Yigit Boyar
800dea555cf42dc3583604699c8c018d22681f56166George Mount    fun declareFactories() = kcode("") {
80196e1c821dd446d1ed78f8ae61131550588f60a24George Mount        if (!layoutBinder.isMerge()) {
8029bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount            tab("public static ${baseClassName} inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot) {") {
8039bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount                tab("return bind(inflater.inflate(${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()}, root, true));")
804dea555cf42dc3583604699c8c018d22681f56166George Mount            }
80596e1c821dd446d1ed78f8ae61131550588f60a24George Mount            nl("}")
8069bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount            tab("public static ${baseClassName} inflate(android.view.LayoutInflater inflater) {") {
8079bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount                tab("return bind(inflater.inflate(${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()}, null, false));")
80896e1c821dd446d1ed78f8ae61131550588f60a24George Mount            }
80996e1c821dd446d1ed78f8ae61131550588f60a24George Mount            nl("}")
81096e1c821dd446d1ed78f8ae61131550588f60a24George Mount            nl("public static ${baseClassName} bind(android.view.View view) {") {
81196e1c821dd446d1ed78f8ae61131550588f60a24George Mount                tab("if (!\"${layoutBinder.getTag()}_0\".equals(view.getTag())) {") {
81296e1c821dd446d1ed78f8ae61131550588f60a24George Mount                    tab("throw new RuntimeException(\"view tag isn't correct on view\");")
81396e1c821dd446d1ed78f8ae61131550588f60a24George Mount                }
81496e1c821dd446d1ed78f8ae61131550588f60a24George Mount                tab("}")
81596e1c821dd446d1ed78f8ae61131550588f60a24George Mount                tab("return new ${baseClassName}(view);")
81696e1c821dd446d1ed78f8ae61131550588f60a24George Mount            }
81796e1c821dd446d1ed78f8ae61131550588f60a24George Mount            nl("}")
818dea555cf42dc3583604699c8c018d22681f56166George Mount        }
819dea555cf42dc3583604699c8c018d22681f56166George Mount    }
820dea555cf42dc3583604699c8c018d22681f56166George Mount
8214c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount    public fun writeBaseClass() : String =
82243596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        kcode("package ${layoutBinder.getPackage()};") {
823fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount            nl("import android.databinding.Bindable;")
824fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount            nl("import android.databinding.DataBindingUtil;")
825fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount            nl("import android.databinding.ViewDataBinding;")
8264c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            nl("public abstract class ${baseClassName} extends ViewDataBinding {")
82796e1c821dd446d1ed78f8ae61131550588f60a24George Mount            layoutBinder.getSortedTargets().filter{it.getId() != null}.forEach {
828de38dd3ef0577d25b2d59863603abe5750d0c231George Mount                tab("public final ${it.interfaceType} ${it.fieldName};")
82934a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            }
83034a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            nl("")
83134a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            tab("protected ${baseClassName}(android.view.View root_, int localFieldCount") {
83296e1c821dd446d1ed78f8ae61131550588f60a24George Mount                layoutBinder.getSortedTargets().filter{it.getId() != null}.forEach {
833019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                    tab(", ${it.interfaceType} ${it.constructorParamName}")
83434a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                }
83534a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            }
83634a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount            tab(") {") {
83734a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                tab("super(root_, localFieldCount);")
83896e1c821dd446d1ed78f8ae61131550588f60a24George Mount                layoutBinder.getSortedTargets().filter{it.getId() != null}.forEach {
839019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                    tab("this.${it.fieldName} = ${it.constructorParamName};")
84034a18e6a231f3b64726bd93e7e097a0d5a75995dGeorge Mount                }
8414c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            }
8424c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            tab("}")
8434c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            nl("")
84443596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            variables.forEach {
84518243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                if (it.getUserDefinedType() != null) {
846895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar                    //it.getExpandedUserDefinedType(ModelAnalyzer.getInstance());
847895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar                    val type = ModelAnalyzer.getInstance().applyImports(it.getUserDefinedType(), model.getImports())
848019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                    tab("public abstract void ${it.setterName}(${type} ${it.readableName});")
84918243f6f1b7527272ef4feccdf4327d80d9f2241George Mount                }
85043596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            }
8519bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount            tab("public static ${baseClassName} inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot) {") {
8529bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount                tab("return DataBindingUtil.<${baseClassName}>inflate(inflater, ${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()}, root, true);")
85343596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            }
8544c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            tab("}")
8559bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount            tab("public static ${baseClassName} inflate(android.view.LayoutInflater inflater) {") {
8569bdb2415487832e88a05c7bd19391b05440b468eGeorge Mount                tab("return DataBindingUtil.<${baseClassName}>inflate(inflater, ${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()}, null, false);")
8574c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            }
8584c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            tab("}")
8594c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            tab("public static ${baseClassName} bind(android.view.View view) {") {
860ed6428586a939e00d9e66314d5cf1056ad48767eGeorge Mount                tab("return (${baseClassName})bind(view, ${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()});")
8614c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            }
8624c5cc009bcbcfb19e33fb19db5ec80f83f7b3326George Mount            tab("}")
86343596c2b2997e40b709627419732100d78a62ff0Yigit Boyar            nl("}")
86443596c2b2997e40b709627419732100d78a62ff0Yigit Boyar        }.generate()
865dea555cf42dc3583604699c8c018d22681f56166George Mount}
866