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
164ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Guptaimport android.databinding.tool.util.StringUtils
17d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.BitSet
18d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
19d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarclass KCode (private val s : String? = null){
20d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
21d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private var sameLine = false
22d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
234ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Gupta    private val lineSeparator = StringUtils.LINE_SEPARATOR
24895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar
25d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    class Appendix(val glue : String, val code : KCode)
26d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
27d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private val nodes = arrayListOf<Any>()
28d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
29fda1703c88eb22e9f166d957d6bda2cd8d645b8fYigit Boyar    companion object {
30d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        private val cachedIndentations = BitSet()
31d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        private val indentCache = arrayListOf<String>()
32d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        fun indent(n: Int): String {
33d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (cachedIndentations.get(n)) {
34af146d6a8c0efcf5682d14047c06866a5548f78fYigit Boyar                return indentCache[n]
35d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
36af146d6a8c0efcf5682d14047c06866a5548f78fYigit Boyar            val s = (0..n-1).fold(""){prev, next -> "$prev    "}
37d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            cachedIndentations.set(n, true )
3859229481aec5a284d322a2ca80dff836485feb0cYigit Boyar            while (indentCache.size <= n) {
39d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                indentCache.add("");
40d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
41af146d6a8c0efcf5682d14047c06866a5548f78fYigit Boyar            indentCache[n] = s
42d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return s
43d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
44d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
45d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
46d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun isNull(kcode : KCode?) = kcode == null || (kcode.nodes.isEmpty() && (kcode.s == null || kcode.s.trim() == ""))
47d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
48d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun tab(vararg codes : KCode?) : KCode {
49d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        codes.forEach { tab(it) }
50d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return this
51d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
52d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
53d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun tab(codes : Collection<KCode?> ) : KCode {
54d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        codes.forEach { tab(it) }
55d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return this
56d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
57d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
5859229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    infix fun tab(s : String?, init : (KCode.() -> Unit)? = null) : KCode {
59d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        val c = KCode(s)
60d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (init != null) {
61d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            c.init()
62d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
63d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return tab(c)
64d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
65d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
66d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    fun tab(c : KCode?) : KCode {
675d454e5f2397a3b160f081ce123b4ca7ff0fc356Yigit Boyar        if (c == null || isNull(c)) {
68d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return this
69d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
70d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        nodes.add(c)
71d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return this
72d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
73d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
7439113ca579a3d4e1c24e204f102e6dc9b26125afTor Norbye    infix fun nl(c : KCode?) : KCode {
755d454e5f2397a3b160f081ce123b4ca7ff0fc356Yigit Boyar        if (c == null || isNull(c)) {
76d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return this
77d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
78d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        nodes.add(c)
79af146d6a8c0efcf5682d14047c06866a5548f78fYigit Boyar        c.sameLine = true
80d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return this
81d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
82d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
8339113ca579a3d4e1c24e204f102e6dc9b26125afTor Norbye    infix fun nl(s : String?, init : (KCode.() -> Unit)? = null) : KCode {
84d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        val c = KCode(s)
85d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (init != null) {
86d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            c.init()
87d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
88d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return nl(c)
89d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
90d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
91d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun app(glue : String = "", c : KCode?) : KCode {
92d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (isNull(c)) {
93d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return this
94d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
95d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        nodes.add(Appendix(glue, c!!))
96d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return this
97d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
98d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
9959229481aec5a284d322a2ca80dff836485feb0cYigit Boyar    infix fun app(s : String) : KCode {
100d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        val c = KCode(s)
101d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return app("", c)
102d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
103d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
104d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun app(glue : String = "", s : String?, init : (KCode.() -> Unit)? = null) : KCode {
105d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        val c = KCode(s)
106d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (init != null) {
107d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            c.init()
108d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
109d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return app(glue, c)
110d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
111d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
112d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
113d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun toS(n : Int, sb : StringBuilder) {
114d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        if (s != null) {
115d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            sb.append(s)
116d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
117d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        val newlineFirstNode = s != null || (nodes.isNotEmpty() && nodes.first() is Appendix)
118d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        var addedChild = false
119d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        nodes.forEach { when(it) {
120d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            is Appendix -> {
121d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                sb.append(it.glue)
122d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                it.code.toS(n, sb)
123d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
124d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            is KCode -> {
125d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                val childTab = n + (if(it.sameLine) 0 else 1)
126d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                if (addedChild || newlineFirstNode) {
127895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar                    sb.append(lineSeparator)
128d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    sb.append("${indent(childTab)}")
129d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
130d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                it.toS(childTab, sb)
131d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                addedChild = true
132d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
133d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        } }
134d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
135d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
136d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
137d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    fun generate() : String {
138d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        val sb = StringBuilder()
139d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        toS(0, sb)
140d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return sb.toString()
141d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
142d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
143d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
144d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarfun kcode(s : String?, init : (KCode.() -> Unit)? = null) : KCode {
145d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    val c = KCode(s)
146d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    if (init != null) {
147d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        c.init()
148d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
149d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    return c
1504ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Gupta}
151