001package ezvcard.io.scribe;
002
003import java.util.List;
004
005import com.github.mangstadt.vinnie.io.VObjectPropertyValues;
006
007import ezvcard.VCard;
008import ezvcard.VCardDataType;
009import ezvcard.VCardVersion;
010import ezvcard.io.ParseContext;
011import ezvcard.io.html.HCardElement;
012import ezvcard.io.json.JCardValue;
013import ezvcard.io.text.WriteContext;
014import ezvcard.io.xml.XCardElement;
015import ezvcard.parameter.VCardParameters;
016import ezvcard.property.Telephone;
017import ezvcard.util.TelUri;
018
019/*
020 Copyright (c) 2012-2023, Michael Angstadt
021 All rights reserved.
022
023 Redistribution and use in source and binary forms, with or without
024 modification, are permitted provided that the following conditions are met: 
025
026 1. Redistributions of source code must retain the above copyright notice, this
027 list of conditions and the following disclaimer. 
028 2. Redistributions in binary form must reproduce the above copyright notice,
029 this list of conditions and the following disclaimer in the documentation
030 and/or other materials provided with the distribution. 
031
032 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
033 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
034 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
035 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
036 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
037 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
038 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
039 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
040 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
041 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
042 */
043
044/**
045 * Marshals {@link Telephone} properties.
046 * @author Michael Angstadt
047 */
048public class TelephoneScribe extends VCardPropertyScribe<Telephone> {
049        public TelephoneScribe() {
050                super(Telephone.class, "TEL");
051        }
052
053        @Override
054        protected VCardDataType _defaultDataType(VCardVersion version) {
055                return VCardDataType.TEXT;
056        }
057
058        @Override
059        protected VCardDataType _dataType(Telephone property, VCardVersion version) {
060                if (version == VCardVersion.V4_0) {
061                        if (property.getText() != null) {
062                                return VCardDataType.TEXT;
063                        }
064                        if (property.getUri() != null) {
065                                return VCardDataType.URI;
066                        }
067                }
068
069                return VCardDataType.TEXT;
070        }
071
072        @Override
073        protected void _prepareParameters(Telephone property, VCardParameters copy, VCardVersion version, VCard vcard) {
074                handlePrefParam(property, copy, version, vcard);
075        }
076
077        @Override
078        protected String _writeText(Telephone property, WriteContext context) {
079                String text = property.getText();
080                if (text != null) {
081                        return escape(text, context);
082                }
083
084                TelUri uri = property.getUri();
085                if (uri != null) {
086                        if (context.getVersion() == VCardVersion.V4_0) {
087                                return uri.toString();
088                        }
089
090                        String ext = uri.getExtension();
091                        String value = (ext == null) ? uri.getNumber() : uri.getNumber() + " x" + ext;
092                        return escape(value, context);
093                }
094
095                return "";
096        }
097
098        @Override
099        protected Telephone _parseText(String value, VCardDataType dataType, VCardParameters parameters, ParseContext context) {
100                value = VObjectPropertyValues.unescape(value);
101                return parse(value, dataType, context);
102        }
103
104        @Override
105        protected void _writeXml(Telephone property, XCardElement parent) {
106                String text = property.getText();
107                if (text != null) {
108                        parent.append(VCardDataType.TEXT, text);
109                        return;
110                }
111
112                TelUri uri = property.getUri();
113                if (uri != null) {
114                        parent.append(VCardDataType.URI, uri.toString());
115                        return;
116                }
117
118                parent.append(VCardDataType.TEXT, "");
119        }
120
121        @Override
122        protected Telephone _parseXml(XCardElement element, VCardParameters parameters, ParseContext context) {
123                String text = element.first(VCardDataType.TEXT);
124                if (text != null) {
125                        return new Telephone(text);
126                }
127
128                String uri = element.first(VCardDataType.URI);
129                if (uri != null) {
130                        try {
131                                return new Telephone(TelUri.parse(uri));
132                        } catch (IllegalArgumentException e) {
133                                context.addWarning(18);
134                                return new Telephone(uri);
135                        }
136                }
137
138                throw missingXmlElements(VCardDataType.TEXT, VCardDataType.URI);
139        }
140
141        @Override
142        protected Telephone _parseHtml(HCardElement element, ParseContext context) {
143                Telephone property;
144                String href = element.attr("href");
145                try {
146                        property = new Telephone(TelUri.parse(href));
147                } catch (IllegalArgumentException e) {
148                        //not a tel URI
149                        property = new Telephone(element.value());
150                }
151
152                List<String> types = element.types();
153                property.getParameters().putAll(VCardParameters.TYPE, types);
154
155                return property;
156        }
157
158        @Override
159        protected JCardValue _writeJson(Telephone property) {
160                String text = property.getText();
161                if (text != null) {
162                        return JCardValue.single(text);
163                }
164
165                TelUri uri = property.getUri();
166                if (uri != null) {
167                        return JCardValue.single(uri.toString());
168                }
169
170                return JCardValue.single("");
171        }
172
173        @Override
174        protected Telephone _parseJson(JCardValue value, VCardDataType dataType, VCardParameters parameters, ParseContext context) {
175                String valueStr = value.asSingle();
176                return parse(valueStr, dataType, context);
177        }
178
179        private Telephone parse(String value, VCardDataType dataType, ParseContext context) {
180                try {
181                        return new Telephone(TelUri.parse(value));
182                } catch (IllegalArgumentException e) {
183                        if (dataType == VCardDataType.URI) {
184                                context.addWarning(18);
185                        }
186                }
187
188                return new Telephone(value);
189        }
190}