001package biweekly.io.scribe.property;
002
003import java.util.ArrayList;
004import java.util.List;
005
006import biweekly.ICalDataType;
007import biweekly.io.ParseContext;
008import biweekly.io.WriteContext;
009import biweekly.io.json.JCalValue;
010import biweekly.io.xml.XCalElement;
011import biweekly.parameter.ICalParameters;
012import biweekly.property.ListProperty;
013
014/*
015 Copyright (c) 2013-2015, Michael Angstadt
016 All rights reserved.
017
018 Redistribution and use in source and binary forms, with or without
019 modification, are permitted provided that the following conditions are met: 
020
021 1. Redistributions of source code must retain the above copyright notice, this
022 list of conditions and the following disclaimer. 
023 2. Redistributions in binary form must reproduce the above copyright notice,
024 this list of conditions and the following disclaimer in the documentation
025 and/or other materials provided with the distribution. 
026
027 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
028 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
029 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
030 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
031 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
032 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
033 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
034 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
035 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
036 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
037 */
038
039/**
040 * Marshals properties that contain a list of values.
041 * @param <T> the property class
042 * @param <V> the value class
043 * @author Michael Angstadt
044 */
045public abstract class ListPropertyScribe<T extends ListProperty<V>, V> extends ICalPropertyScribe<T> {
046        public ListPropertyScribe(Class<T> clazz, String propertyName) {
047                this(clazz, propertyName, ICalDataType.TEXT);
048        }
049
050        public ListPropertyScribe(Class<T> clazz, String propertyName, ICalDataType dataType) {
051                super(clazz, propertyName, dataType);
052        }
053
054        @Override
055        protected String _writeText(final T property, WriteContext context) {
056                List<V> values = property.getValues();
057                List<String> valuesStr = new ArrayList<String>(values.size());
058                for (V value : values) {
059                        String valueStr = writeValue(property, value, context);
060                        valuesStr.add(valueStr);
061                }
062
063                switch (context.getVersion()) {
064                case V1_0:
065                        Object[] valuesArray = valuesStr.toArray(new String[0]);
066                        return structured(valuesArray);
067                default:
068                        return list(valuesStr);
069                }
070        }
071
072        @Override
073        protected T _parseText(String value, ICalDataType dataType, ICalParameters parameters, ParseContext context) {
074                List<String> values;
075                switch (context.getVersion()) {
076                case V1_0:
077                        values = new ArrayList<String>();
078                        if (value.length() > 0) {
079                                SemiStructuredIterator it = semistructured(value);
080                                while (it.hasNext()) {
081                                        values.add(it.next());
082                                }
083                        }
084                        break;
085
086                default:
087                        values = list(value);
088                }
089
090                return parse(values, dataType, parameters, context);
091        }
092
093        @Override
094        protected void _writeXml(T property, XCalElement element, WriteContext context) {
095                for (V value : property.getValues()) {
096                        String valueStr = writeValue(property, value, null);
097                        element.append(dataType(property, null), valueStr);
098                }
099        }
100
101        @Override
102        protected T _parseXml(XCalElement element, ICalParameters parameters, ParseContext context) {
103                ICalDataType dataType = defaultDataType(context.getVersion());
104                List<String> values = element.all(dataType);
105                if (!values.isEmpty()) {
106                        return parse(values, dataType, parameters, context);
107                }
108
109                throw missingXmlElements(dataType);
110        }
111
112        @Override
113        protected JCalValue _writeJson(T property, WriteContext context) {
114                List<V> values = property.getValues();
115                if (!values.isEmpty()) {
116                        return JCalValue.multi(property.getValues());
117                }
118
119                return JCalValue.single("");
120        }
121
122        @Override
123        protected T _parseJson(JCalValue value, ICalDataType dataType, ICalParameters parameters, ParseContext context) {
124                return parse(value.asMulti(), dataType, parameters, context);
125        }
126
127        private T parse(List<String> valueStrs, ICalDataType dataType, ICalParameters parameters, ParseContext context) {
128                T property = newInstance(dataType, parameters);
129
130                for (String valueStr : valueStrs) {
131                        V value = readValue(property, valueStr, dataType, parameters, context);
132                        property.addValue(value);
133                }
134
135                return property;
136        }
137
138        protected abstract T newInstance(ICalDataType dataType, ICalParameters parameters);
139
140        protected abstract String writeValue(T property, V value, WriteContext context);
141
142        protected abstract V readValue(T property, String value, ICalDataType dataType, ICalParameters parameters, ParseContext context);
143}