1/*
2 * Copyright (C) 2009 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 */
16package android.pim.vcard;
17
18import android.content.ContentValues;
19import android.pim.vcard.VCardEntry;
20import android.util.Log;
21
22import java.util.ArrayList;
23import java.util.Arrays;
24import java.util.HashSet;
25import java.util.List;
26import java.util.Set;
27
28/**
29 * Previously used in main vCard handling code but now exists only for testing.
30 *
31 * Especially useful for testing parser code (VCardParser), since all properties can be
32 * checked via this class unlike {@link VCardEntry}, which only emits the result of
33 * interpretation of the content of each vCard. We cannot know whether vCard parser or
34 * ContactStruct is wrong withouth this class.
35 */
36public class PropertyNode {
37    public String propName;
38    public String propValue;
39    public List<String> propValue_vector;
40
41    /** Store value as byte[],after decode.
42     * Used when propValue is encoded by something like BASE64, QUOTED-PRINTABLE, etc.
43     */
44    public byte[] propValue_bytes;
45
46    /** param store: key=paramType, value=paramValue
47     * Note that currently PropertyNode class does not support multiple param-values
48     * defined in vCard 3.0 (See also RFC 2426). multiple-values are stored as
49     * one String value like "A,B", not ["A", "B"]...
50     * TODO: fix this.
51     */
52    public ContentValues paramMap;
53
54    /** Only for TYPE=??? param store. */
55    public Set<String> paramMap_TYPE;
56
57    /** Store group values. Used only in VCard. */
58    public Set<String> propGroupSet;
59
60    public PropertyNode() {
61        propName = "";
62        propValue = "";
63        propValue_vector = new ArrayList<String>();
64        paramMap = new ContentValues();
65        paramMap_TYPE = new HashSet<String>();
66        propGroupSet = new HashSet<String>();
67    }
68
69    public PropertyNode(
70            String propName, String propValue, List<String> propValue_vector,
71            byte[] propValue_bytes, ContentValues paramMap, Set<String> paramMap_TYPE,
72            Set<String> propGroupSet) {
73        if (propName != null) {
74            this.propName = propName;
75        } else {
76            this.propName = "";
77        }
78        if (propValue != null) {
79            this.propValue = propValue;
80        } else {
81            this.propValue = "";
82        }
83        if (propValue_vector != null) {
84            this.propValue_vector = propValue_vector;
85        } else {
86            this.propValue_vector = new ArrayList<String>();
87        }
88        this.propValue_bytes = propValue_bytes;
89        if (paramMap != null) {
90            this.paramMap = paramMap;
91        } else {
92            this.paramMap = new ContentValues();
93        }
94        if (paramMap_TYPE != null) {
95            this.paramMap_TYPE = paramMap_TYPE;
96        } else {
97            this.paramMap_TYPE = new HashSet<String>();
98        }
99        if (propGroupSet != null) {
100            this.propGroupSet = propGroupSet;
101        } else {
102            this.propGroupSet = new HashSet<String>();
103        }
104    }
105
106    @Override
107    public int hashCode() {
108        // vCard may contain more than one same line in one entry, while HashSet or any other
109        // library which utilize hashCode() does not honor that, so intentionally throw an
110        // Exception.
111        throw new UnsupportedOperationException(
112                "PropertyNode does not provide hashCode() implementation intentionally.");
113    }
114
115    @Override
116    public boolean equals(Object obj) {
117        if (!(obj instanceof PropertyNode)) {
118            return false;
119        }
120
121        PropertyNode node = (PropertyNode)obj;
122
123        if (propName == null || !propName.equals(node.propName)) {
124            return false;
125        } else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) {
126            return false;
127        } else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) {
128            return false;
129        } else if (!propGroupSet.equals(node.propGroupSet)) {
130            return false;
131        }
132
133        if (propValue_bytes != null && Arrays.equals(propValue_bytes, node.propValue_bytes)) {
134            return true;
135        } else {
136            if (!propValue.equals(node.propValue)) {
137                return false;
138            }
139
140            // The value in propValue_vector is not decoded even if it should be
141            // decoded by BASE64 or QUOTED-PRINTABLE. When the size of propValue_vector
142            // is 1, the encoded value is stored in propValue, so we do not have to
143            // check it.
144            return (propValue_vector.equals(node.propValue_vector) ||
145                    propValue_vector.size() == 1 ||
146                    node.propValue_vector.size() == 1);
147        }
148    }
149
150    @Override
151    public String toString() {
152        StringBuilder builder = new StringBuilder();
153        builder.append("propName: ");
154        builder.append(propName);
155        builder.append(", paramMap: ");
156        builder.append(paramMap.toString());
157        builder.append(", paramMap_TYPE: [");
158        boolean first = true;
159        for (String elem : paramMap_TYPE) {
160            if (first) {
161                first = false;
162            } else {
163                builder.append(", ");
164            }
165            builder.append('"');
166            builder.append(elem);
167            builder.append('"');
168        }
169        builder.append("]");
170        if (!propGroupSet.isEmpty()) {
171            builder.append(", propGroupSet: [");
172            first = true;
173            for (String elem : propGroupSet) {
174                if (first) {
175                    first = false;
176                } else {
177                    builder.append(", ");
178                }
179                builder.append('"');
180                builder.append(elem);
181                builder.append('"');
182            }
183            builder.append("]");
184        }
185        if (propValue_vector != null && propValue_vector.size() > 1) {
186            builder.append(", propValue_vector size: ");
187            builder.append(propValue_vector.size());
188        }
189        if (propValue_bytes != null) {
190            builder.append(", propValue_bytes size: ");
191            builder.append(propValue_bytes.length);
192        }
193        builder.append(", propValue: \"");
194        builder.append(propValue);
195        builder.append("\"");
196        return builder.toString();
197    }
198}
199