1e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount/*
2e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount * Copyright (C) 2015 The Android Open Source Project
3e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount *
4e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount * Licensed under the Apache License, Version 2.0 (the "License");
5e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount * you may not use this file except in compliance with the License.
6e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount * You may obtain a copy of the License at
7e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount *
8e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount *      http://www.apache.org/licenses/LICENSE-2.0
9e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount *
10e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount * Unless required by applicable law or agreed to in writing, software
11e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount * distributed under the License is distributed on an "AS IS" BASIS,
12e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount * See the License for the specific language governing permissions and
14e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount * limitations under the License.
15e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount */
16e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mountpackage android.databinding.tool.writer;
17e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount
18e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mountimport android.databinding.tool.Binding;
19e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mountimport android.databinding.tool.BindingTarget;
20e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mountimport android.databinding.tool.LayoutBinder;
21e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mountimport android.databinding.tool.processing.ScopedException;
22e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount
23e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mountimport java.util.ArrayList;
24e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mountimport java.util.HashMap;
25e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mountimport java.util.List;
26e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mountimport java.util.Map.Entry;
27e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount
28e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mountpublic class ComponentWriter {
29e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount    private static final String INDENT = "    ";
30e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount    private final HashMap<String, ArrayList<String>> mBindingAdapters = new HashMap<>();
31e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount
32e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount    public ComponentWriter(List<LayoutBinder> binders) {
33e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        HashMap<Binding, ArrayList<String>> bindings = new HashMap<>();
34e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount
35e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        for (LayoutBinder layoutBinder : binders) {
36e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            try {
37e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                android.databinding.tool.processing.Scope.enter(layoutBinder);
38e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                for (BindingTarget target : layoutBinder.getBindingTargets()) {
39e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                    try {
40e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                        android.databinding.tool.processing.Scope.enter(target);
41e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                        for (Binding binding : target.getBindings()) {
42e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                            try {
43e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                android.databinding.tool.processing.Scope.enter(binding);
44e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                final String bindingAdapter = binding
45e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                        .getBindingAdapterInstanceClass();
46e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                if (bindingAdapter != null) {
47e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                    final String simpleName = simpleName(bindingAdapter);
48e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                    ArrayList<String> classes = mBindingAdapters.get(simpleName);
49e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                    if (classes == null) {
50e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                        classes = new ArrayList<>();
51e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                        mBindingAdapters.put(simpleName, classes);
52e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                        classes.add(bindingAdapter);
53e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                    } else if (!classes.contains(bindingAdapter)) {
54e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                        classes.add(bindingAdapter);
55e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                    }
56e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                    bindings.put(binding, classes);
57e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                }
58e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                            } catch (ScopedException ex) {
59e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                android.databinding.tool.processing.Scope.defer(ex);
60e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                            } finally{
61e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                                android.databinding.tool.processing.Scope.exit();
62e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                            }
63e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                        }
64e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                    } finally {
65e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                        android.databinding.tool.processing.Scope.exit();
66e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                    }
67e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                }
68e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            } finally {
69e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                android.databinding.tool.processing.Scope.exit();
70e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            }
71e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        }
72e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount
73e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        for (Entry<Binding, ArrayList<String>> entry : bindings.entrySet()) {
74e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            final Binding binding = entry.getKey();
75e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            final ArrayList<String> classes = entry.getValue();
76e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            final String call;
77e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            if (classes.size() == 1) {
78e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                call = "get" + simpleName(classes.get(0)) + "()";
79e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            } else {
80e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                int index = classes.indexOf(binding.getBindingAdapterInstanceClass());
81e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                call = "get" + simpleName(classes.get(index)) + (index + 1) + "()";
82e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            }
83e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            binding.setBindingAdapterCall(call);
84e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        }
85e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount    }
86e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount
87e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount    public String createComponent() {
88e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        final StringBuilder builder = new StringBuilder();
89e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        builder.append("package android.databinding;\n\n");
90e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        builder.append("public interface DataBindingComponent {\n");
91e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        for (final String simpleName : mBindingAdapters.keySet()) {
92e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            final ArrayList<String> classes = mBindingAdapters.get(simpleName);
93e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            if (classes.size() > 1) {
94e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                int index = 1;
95e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                for (String className : classes) {
96e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                    addGetter(builder, simpleName, className, index++);
97e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                }
98e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            } else {
99e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                addGetter(builder, simpleName, classes.iterator().next(), 0);
100e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            }
101e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        }
102e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        builder.append("}\n");
103e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        return builder.toString();
104e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount    }
105e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount
106e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount    private static String simpleName(String className) {
107e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        int dotIndex = className.lastIndexOf('.');
108e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        if (dotIndex < 0) {
109e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            return className;
110e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        } else {
111e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            return className.substring(dotIndex + 1);
112e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        }
113e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount    }
114e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount
115e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount    private static void addGetter(StringBuilder builder, String simpleName, String className,
116e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            int index) {
117e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        builder.append(INDENT)
118e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                .append(className)
119e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                .append(" get")
120e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount                .append(simpleName);
121e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        if (index > 0) {
122e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount            builder.append(index);
123e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        }
124e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount        builder.append("();\n");
125e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount    }
126e4cd38824a6627b9fef229c549c636e35ad63b5fGeorge Mount}
127