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        block("class $className") {
24            nl("final static int TARGET_MIN_SDK = $minSdk;")
25            nl("")
26            block("public $className()") {
27            }
28            nl("")
29            block("public android.databinding.ViewDataBinding getDataBinder(android.databinding.DataBindingComponent bindingComponent, android.view.View view, int layoutId)") {
30                block("switch(layoutId)") {
31                    layoutBinders.groupBy{it.layoutname }.forEach {
32                        val firstVal = it.value[0]
33                        tab("case ${firstVal.modulePackage}.R.layout.${firstVal.layoutname}:") {
34                            if (it.value.size == 1) {
35                                if (firstVal.isMerge) {
36                                    tab("return new ${firstVal.`package`}.${firstVal.implementationName}(bindingComponent, new android.view.View[]{view});")
37                                } else {
38                                    tab("return ${firstVal.`package`}.${firstVal.implementationName}.bind(view, bindingComponent);")
39                                }
40                            } else {
41                                // we should check the tag to decide which layout we need to inflate
42                                block("") {
43                                    tab("final Object tag = view.getTag();")
44                                    tab("if(tag == null) throw new java.lang.RuntimeException(\"view must have a tag\");")
45                                    it.value.forEach {
46                                        block("if (\"${it.tag}_0\".equals(tag))") {
47                                            if (it.isMerge) {
48                                                tab("return new ${it.`package`}.${it.implementationName}(bindingComponent, new android.view.View[]{view});")
49                                            } else {
50                                                tab("return new ${it.`package`}.${it.implementationName}(bindingComponent, view);")
51                                            }
52                                        }
53                                    }
54                                    tab("throw new java.lang.IllegalArgumentException(\"The tag for ${firstVal.layoutname} is invalid. Received: \" + tag);");
55                                }
56                            }
57
58                        }
59                    }
60                }
61                nl("return null;")
62            }
63            block("android.databinding.ViewDataBinding getDataBinder(android.databinding.DataBindingComponent bindingComponent, android.view.View[] views, int layoutId)") {
64                block("switch(layoutId)") {
65                    layoutBinders.filter{it.isMerge }.groupBy{it.layoutname }.forEach {
66                        val firstVal = it.value[0]
67                        block("case ${firstVal.modulePackage}.R.layout.${firstVal.layoutname}:") {
68                            if (it.value.size == 1) {
69                                tab("return new ${firstVal.`package`}.${firstVal.implementationName}(bindingComponent, views);")
70                            } else {
71                                // we should check the tag to decide which layout we need to inflate
72                                nl("final Object tag = views[0].getTag();")
73                                nl("if(tag == null) throw new java.lang.RuntimeException(\"view must have a tag\");")
74                                it.value.forEach {
75                                    block("if (\"${it.tag}_0\".equals(tag))") {
76                                        nl("return new ${it.`package`}.${it.implementationName}(bindingComponent, views);")
77                                    }
78                                }
79                            }
80                        }
81                    }
82                }
83                nl("return null;")
84            }
85
86            block("int getLayoutId(String tag)") {
87                block("if (tag == null)") {
88                    nl("return 0;");
89                }
90                // String.hashCode is well defined in the API so we can rely on it being the same on the device and the host machine
91                nl("final int code = tag.hashCode();");
92                block("switch(code)") {
93                    layoutBinders.groupBy {"${it.tag}_0".hashCode()}.forEach {
94                        block("case ${it.key}:") {
95                            it.value.forEach {
96                                block("if(tag.equals(\"${it.tag}_0\"))") {
97                                    nl("return ${it.modulePackage}.R.layout.${it.layoutname};")
98                                }
99                            }
100                            nl("break;")
101                        }
102
103                    }
104                }
105                nl("return 0;")
106            }
107
108            block("String convertBrIdToString(int id)") {
109                block("if (id < 0 || id >= InnerBrLookup.sKeys.length)") {
110                    nl("return null;")
111                }
112                nl("return InnerBrLookup.sKeys[id];")
113            }
114
115            block("private static class InnerBrLookup") {
116                nl("static String[] sKeys = new String[]{") {
117                    tab("\"_all\"")
118                    brWriter.indexedProps.forEach {
119                        tab(",\"${it.value}\"")
120                    }
121                }.app("};")
122            }
123        }
124    }.generate()
125}