1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.constraintlayout.core.dsl;
18 
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 
22 public class Ref {
23     private String mId;
24     private float mWeight = Float.NaN;
25     private float mPreMargin = Float.NaN;
26     private float mPostMargin = Float.NaN;
27 
Ref(String id)28     Ref(String id) {
29         mId = id;
30     }
31 
Ref(String id, float weight)32     Ref(String id, float weight) {
33         mId = id;
34         mWeight = weight;
35     }
36 
Ref(String id, float weight, float preMargin)37     Ref(String id, float weight, float preMargin) {
38         mId = id;
39         mWeight = weight;
40         mPreMargin = preMargin;
41     }
42 
Ref(String id, float weight, float preMargin, float postMargin)43     Ref(String id, float weight, float preMargin, float postMargin) {
44         mId = id;
45         mWeight = weight;
46         mPreMargin = preMargin;
47         mPostMargin = postMargin;
48     }
49 
50     /**
51      * Get the Id of the reference
52      *
53      * @return the Id of the reference
54      */
getId()55     public String getId() {
56         return mId;
57     }
58 
59     /**
60      * Set the Id of the reference
61      *
62      * @param id
63      */
setId(String id)64     public void setId(String id) {
65         mId = id;
66     }
67 
68     /**
69      * Get the weight of the reference
70      *
71      * @return the weight of the reference
72      */
getWeight()73     public float getWeight() {
74         return mWeight;
75     }
76 
77     /**
78      * Set the weight of the reference
79      *
80      * @param weight
81      */
setWeight(float weight)82     public void setWeight(float weight) {
83         mWeight = weight;
84     }
85 
86     /**
87      * Get the preMargin of the reference
88      *
89      * @return the preMargin of the reference
90      */
getPreMargin()91     public float getPreMargin() {
92         return mPreMargin;
93     }
94 
95     /**
96      * Set the preMargin of the reference
97      *
98      * @param preMargin
99      */
setPreMargin(float preMargin)100     public void setPreMargin(float preMargin) {
101         mPreMargin = preMargin;
102     }
103 
104     /**
105      * Get the postMargin of the reference
106      *
107      * @return the preMargin of the reference
108      */
getPostMargin()109     public float getPostMargin() {
110         return mPostMargin;
111     }
112 
113     /**
114      * Set the postMargin of the reference
115      *
116      * @param postMargin
117      */
setPostMargin(float postMargin)118     public void setPostMargin(float postMargin) {
119         mPostMargin = postMargin;
120     }
121 
122     /**
123      * Try to parse an object into a float number
124      *
125      * @param obj object to be parsed
126      * @return a number
127      */
parseFloat(Object obj)128     static public float parseFloat(Object obj) {
129         float val = Float.NaN;
130         try {
131             val = Float.parseFloat(obj.toString());
132         } catch (Exception e) {
133             // ignore
134         }
135         return val;
136     }
137 
parseStringToRef(String str)138     static public Ref parseStringToRef(String str) {
139         String[] values = str.replaceAll("[\\[\\]\\']", "").split(",");
140         if (values.length == 0) {
141             return null;
142         }
143         Object[] arr = new Object[4];
144         for (int i = 0; i < values.length; i++) {
145             if (i >= 4) {
146                 break;
147             }
148             arr[i] = values[i];
149         }
150         return new Ref(arr[0].toString().replace("'", ""), parseFloat(arr[1]),
151                 parseFloat(arr[2]), parseFloat(arr[3]));
152     }
153 
154     /**
155      * Add references in a String representation to a Ref ArrayList
156      * Used to add the Ref(s) property in the Config to references
157      *
158      * @param str references in a String representation
159      * @param refs  a Ref ArrayList
160      */
addStringToReferences(String str, ArrayList<Ref> refs)161     static public void addStringToReferences(String str, ArrayList<Ref> refs) {
162         if (str == null || str.length() == 0) {
163             return;
164         }
165 
166         Object[] arr = new Object[4];
167         StringBuilder builder = new StringBuilder();
168         int squareBrackets = 0;
169         int varCount = 0;
170         char ch;
171 
172         for (int i = 0; i < str.length(); i++) {
173             ch = str.charAt(i);
174             switch (ch) {
175                 case '[':
176                     squareBrackets++;
177                     break;
178                 case ']':
179                     if (squareBrackets > 0) {
180                         squareBrackets--;
181                         arr[varCount] = builder.toString();
182                         builder.setLength(0);
183                         if (arr[0] != null) {
184                             refs.add(new Ref(arr[0].toString(), parseFloat(arr[1]),
185                                     parseFloat(arr[2]), parseFloat(arr[3])));
186                             varCount = 0;
187                             Arrays.fill(arr, null);
188                         }
189                     }
190                     break;
191                 case ',':
192                     // deal with the first 3 values in the nested array,
193                     // the fourth value (postMargin) would be handled at case ']'
194                     if (varCount < 3) {
195                         arr[varCount++] = builder.toString();
196                         builder.setLength(0);
197                     }
198                     // squareBrackets == 1 indicate the value is not in a nested array.
199                     if (squareBrackets == 1 && arr[0] != null) {
200                         refs.add(new Ref(arr[0].toString()));
201                         varCount = 0;
202                         arr[0] = null;
203                     }
204                     break;
205                 case ' ':
206                 case '\'':
207                     break;
208                 default:
209                     builder.append(ch);
210             }
211         }
212     }
213 
214     @Override
toString()215     public String toString() {
216         if (mId == null || mId.length() == 0) {
217             return "";
218         }
219 
220         StringBuilder ret = new StringBuilder();
221         boolean isArray = false;
222         if (!Float.isNaN(mWeight) || !Float.isNaN(mPreMargin)
223                 || !Float.isNaN(mPostMargin)) {
224             isArray = true;
225         }
226         if (isArray) {
227             ret.append("[");
228         }
229         ret.append("'").append(mId).append("'");
230 
231         if (!Float.isNaN(mPostMargin)) {
232             ret.append(",").append(!Float.isNaN(mWeight) ? mWeight : 0).append(",");
233             ret.append(!Float.isNaN(mPreMargin) ? mPreMargin : 0).append(",");
234             ret.append(mPostMargin);
235         } else if (!Float.isNaN(mPreMargin)) {
236             ret.append(",").append(!Float.isNaN(mWeight) ? mWeight : 0).append(",");
237             ret.append(mPreMargin);
238         } else if (!Float.isNaN(mWeight)) {
239             ret.append(",").append(mWeight);
240         }
241 
242         if(isArray) {
243             ret.append("]");
244         }
245         ret.append(",");
246         return ret.toString();
247     }
248 }
249