1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *      http://www.apache.org/licenses/LICENSE-2.0
7 * Unless required by applicable law or agreed to in writing, software
8 * distributed under the License is distributed on an "AS IS" BASIS,
9 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 * See the License for the specific language governing permissions and
11 * limitations under the License.
12 */
13
14package android.databinding.tool.writer
15
16import android.databinding.tool.LayoutBinder
17
18class DataBinderWriter(val pkg: String, val projectPackage: String, val className: String,
19        val layoutBinders : List<LayoutBinder>, val minSdk : kotlin.Int) {
20    fun write(brWriter : BRWriter) = kcode("") {
21        nl("package $pkg;")
22        nl("import $projectPackage.BR;")
23        nl("class $className {") {
24            tab("final static int TARGET_MIN_SDK = ${minSdk};")
25            nl("")
26            tab("public $className() {") {
27            }
28            tab("}")
29            nl("")
30            tab("public android.databinding.ViewDataBinding getDataBinder(android.databinding.DataBindingComponent bindingComponent, android.view.View view, int layoutId) {") {
31                tab("switch(layoutId) {") {
32                    layoutBinders.groupBy{it.getLayoutname()}.forEach {
33                        val firstVal = it.value.get(0)
34                        tab("case ${firstVal.getModulePackage()}.R.layout.${firstVal.getLayoutname()}:") {
35                            if (it.value.size() == 1) {
36                                if (firstVal.isMerge()) {
37                                    tab("return new ${firstVal.getPackage()}.${firstVal.getImplementationName()}(bindingComponent, new android.view.View[]{view});")
38                                } else {
39                                    tab("return ${firstVal.getPackage()}.${firstVal.getImplementationName()}.bind(view, bindingComponent);")
40                                }
41                            } else {
42                                // we should check the tag to decide which layout we need to inflate
43                                tab("{") {
44                                    tab("final Object tag = view.getTag();")
45                                    tab("if(tag == null) throw new java.lang.RuntimeException(\"view must have a tag\");")
46                                    it.value.forEach {
47                                        tab("if (\"${it.getTag()}_0\".equals(tag)) {") {
48                                            if (it.isMerge()) {
49                                                tab("return new ${it.getPackage()}.${it.getImplementationName()}(bindingComponent, new android.view.View[]{view});")
50                                            } else {
51                                                tab("return new ${it.getPackage()}.${it.getImplementationName()}(bindingComponent, view);")
52                                            }
53                                        } tab("}")
54                                    }
55                                }tab("}")
56                            }
57
58                        }
59                    }
60                }
61                tab("}")
62                tab("return null;")
63            }
64            tab("}")
65
66            tab("android.databinding.ViewDataBinding getDataBinder(android.databinding.DataBindingComponent bindingComponent, android.view.View[] views, int layoutId) {") {
67                tab("switch(layoutId) {") {
68                    layoutBinders.filter{it.isMerge()}.groupBy{it.getLayoutname()}.forEach {
69                        val firstVal = it.value.get(0)
70                        tab("case ${firstVal.getModulePackage()}.R.layout.${firstVal.getLayoutname()}:") {
71                            if (it.value.size() == 1) {
72                                tab("return new ${firstVal.getPackage()}.${firstVal.getImplementationName()}(bindingComponent, views);")
73                            } else {
74                                // we should check the tag to decide which layout we need to inflate
75                                tab("{") {
76                                    tab("final Object tag = views[0].getTag();")
77                                    tab("if(tag == null) throw new java.lang.RuntimeException(\"view must have a tag\");")
78                                    it.value.forEach {
79                                        tab("if (\"${it.getTag()}_0\".equals(tag)) {") {
80                                            tab("return new ${it.getPackage()}.${it.getImplementationName()}(bindingComponent, views);")
81                                        } tab("}")
82                                    }
83                                }tab("}")
84                            }
85                        }
86                    }
87                }
88                tab("}")
89                tab("return null;")
90            }
91            tab("}")
92
93            tab("int getLayoutId(String tag) {") {
94                tab("if (tag == null) {") {
95                    tab("return 0;");
96                }
97                tab("}")
98                // String.hashCode is well defined in the API so we can rely on it being the same on the device and the host machine
99                tab("final int code = tag.hashCode();");
100                tab("switch(code) {") {
101                    layoutBinders.groupBy {"${it.getTag()}_0".hashCode()}.forEach {
102                        tab("case ${it.key}:") {
103                            it.value.forEach {
104                                tab("if(tag.equals(\"${it.getTag()}_0\"))") {
105                                    tab("return ${it.getModulePackage()}.R.layout.${it.getLayoutname()};")
106                                }
107                            }
108                            tab("break;")
109                        }
110
111                    }
112                }
113                tab("}")
114                tab("return 0;")
115            }
116            tab("}")
117
118            tab("String convertBrIdToString(int id) {") {
119                tab("if (id < 0 || id >= InnerBrLookup.sKeys.length) {") {
120                    tab("return null;")
121                } tab("}")
122                tab("return InnerBrLookup.sKeys[id];")
123            } tab("}")
124
125            tab("private static class InnerBrLookup {") {
126                tab("static String[] sKeys = new String[]{") {
127                    tab("\"_all\"")
128                    brWriter.indexedProps.forEach {
129                        tab(",\"${it.value}\"")
130                    }
131                }.app("};")
132            } tab("}")
133        }
134        nl("}")
135    }.generate()
136}