001/**
002 *
003 * Copyright 2020 Aditya Borikar, 2021 Florian Schmaus
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smackx.softwareinfo.form;
018
019import java.util.List;
020
021import org.jivesoftware.smack.util.EqualsUtil;
022import org.jivesoftware.smack.util.HashCode;
023import org.jivesoftware.smackx.formtypes.FormFieldRegistry;
024import org.jivesoftware.smackx.mediaelement.element.MediaElement;
025import org.jivesoftware.smackx.xdata.FormField;
026import org.jivesoftware.smackx.xdata.FormFieldChildElement;
027import org.jivesoftware.smackx.xdata.TextSingleFormField;
028import org.jivesoftware.smackx.xdata.form.FilledForm;
029import org.jivesoftware.smackx.xdata.form.Form;
030import org.jivesoftware.smackx.xdata.packet.DataForm;
031
032/**
033 * {@link Form} that contains the software information.
034 * <br>
035 * Instance of {@link SoftwareInfoForm} can be created using {@link Builder#build()} method.
036 * <br>
037 * To obtain an instance of {@link Builder}, use {@link SoftwareInfoForm#getBuilder()} method.
038 * <br>
039 * An example to illustrate is provided inside SoftwareInfoFormTest inside the test package.
040 */
041public final class SoftwareInfoForm extends FilledForm {
042
043    public static final String FORM_TYPE = "urn:xmpp:dataforms:softwareinfo";
044    public static final String OS = "os";
045    public static final String OS_VERSION = "os_version";
046    public static final String SOFTWARE = "software";
047    public static final String SOFTWARE_VERSION = "software_version";
048    public static final String ICON = "icon";
049
050    static {
051        FormFieldRegistry.register(FORM_TYPE, FormField.Type.text_single,
052                        OS, OS_VERSION, SOFTWARE, SOFTWARE_VERSION);
053    }
054
055    private SoftwareInfoForm(DataForm dataForm) {
056        super(dataForm);
057    }
058
059    /**
060     * Returns name of the OS used by client.
061     * <br>
062     * @return os
063     */
064    public String getOS() {
065        return readFirstValue(OS);
066    }
067
068    /**
069     * Returns version of the OS used by client.
070     * <br>
071     * @return os_version
072     */
073    public String getOSVersion() {
074        return readFirstValue(OS_VERSION);
075    }
076
077    /**
078     * Returns name of the software used by client.
079     * <br>
080     * @return software
081     */
082    public String getSoftwareName() {
083        return readFirstValue(SOFTWARE);
084    }
085
086    /**
087     * Returns version of the software used by client.
088     * <br>
089     * @return software_version
090     */
091    public String getSoftwareVersion () {
092        return readFirstValue(SOFTWARE_VERSION);
093    }
094
095    /**
096     * Returns the software icon if used by client.
097     * <br>
098     * @return {@link MediaElement} MediaElement or null
099     */
100    public MediaElement getIcon () {
101        FormField field = getField(ICON);
102        if (field == null) {
103            return null;
104        }
105        FormFieldChildElement media = field.getFormFieldChildElement(MediaElement.QNAME);
106        if (media == null) {
107            return null;
108        }
109        return (MediaElement) media;
110    }
111
112    @Override
113    public boolean equals(Object obj) {
114        return EqualsUtil.equals(this, obj, (equalsBuilder, otherObj) -> {
115            equalsBuilder.append(getDataForm().getType(), otherObj.getDataForm().getType())
116                         .append(getDataForm().getTitle(), otherObj.getDataForm().getTitle())
117                         .append(getDataForm().getReportedData(), otherObj.getDataForm().getReportedData())
118                         .append(getDataForm().getItems(), otherObj.getDataForm().getItems())
119                         .append(getDataForm().getFields(), otherObj.getDataForm().getFields())
120                         .append(getDataForm().getExtensionElements(), otherObj.getDataForm().getExtensionElements());
121        });
122    }
123
124    @Override
125    public int hashCode() {
126        HashCode.Builder builder = HashCode.builder();
127        builder.append(getDataForm().getFields());
128        builder.append(getDataForm().getItems());
129        builder.append(getDataForm().getExtensionElements());
130        return builder.build();
131    }
132
133    /**
134     * Returns a new instance of {@link Builder}.
135     * <br>
136     * @return Builder
137     */
138    public static Builder getBuilder() {
139        return new Builder();
140    }
141
142    /**
143     * Builder class for {@link SoftwareInfoForm}.
144     * <br>
145     * To obtain an instance of {@link Builder}, use {@link SoftwareInfoForm#getBuilder()} method.
146     * <br>
147     * Use appropriate setters to include information inside SoftwareInfoForms.
148     */
149    public static final class Builder {
150        DataForm.Builder dataFormBuilder;
151
152        private Builder() {
153            dataFormBuilder = DataForm.builder(DataForm.Type.result);
154            TextSingleFormField formField = FormField.buildHiddenFormType(FORM_TYPE);
155            dataFormBuilder.addField(formField);
156        }
157
158        /**
159         * This will allow to include Icon using height, width and Uri's as a
160         * {@link FormField}.
161         * <br>
162         * @param height  Height of the image
163         * @param width   Width of the image
164         * @param uriList List of URIs
165         * @return Builder
166         */
167        public Builder setIcon(int height, int width, List<MediaElement.Uri> uriList) {
168            MediaElement.Builder mediaBuilder = MediaElement.builder();
169            for (MediaElement.Uri uri : uriList) {
170                mediaBuilder.addUri(uri);
171            }
172            MediaElement mediaElement = mediaBuilder.setHeightAndWidth(height, width).build();
173            return setIcon(mediaElement);
174        }
175
176        /**
177         * This will allow to include {@link MediaElement} directly as a
178         * {@link FormField}.
179         * <br>
180         * @param mediaElement MediaElement to be included
181         * @return Builder
182         */
183        public Builder setIcon(MediaElement mediaElement) {
184            FormField.Builder<?, ?> builder = FormField.builder(ICON);
185            builder.addFormFieldChildElement(mediaElement);
186            dataFormBuilder.addField(builder.build());
187            return this;
188        }
189
190        /**
191         * Include Operating System's name as a {@link FormField}.
192         * <br>
193         * @param os Name of the OS
194         * @return Builder
195         */
196        public Builder setOS(String os) {
197            TextSingleFormField.Builder builder = FormField.builder(OS);
198            builder.setValue(os);
199            dataFormBuilder.addField(builder.build());
200            return this;
201        }
202
203        /**
204         * Include Operating System's version as a {@link FormField}.
205         * <br>
206         * @param os_version Version of OS
207         * @return Builder
208         */
209        public Builder setOSVersion(String os_version) {
210            TextSingleFormField.Builder builder = FormField.builder(OS_VERSION);
211            builder.setValue(os_version);
212            dataFormBuilder.addField(builder.build());
213            return this;
214        }
215
216        /**
217         * Include Software name as a {@link FormField}.
218         * <br>
219         * @param software Name of the software
220         * @return Builder
221         */
222        public Builder setSoftware(String software) {
223            TextSingleFormField.Builder builder = FormField.builder(SOFTWARE);
224            builder.setValue(software);
225            dataFormBuilder.addField(builder.build());
226            return this;
227        }
228
229        /**
230         * Include Software Version as a {@link FormField}.
231         * <br>
232         * @param softwareVersion Version of the Software in use
233         * @return Builder
234         */
235        public Builder setSoftwareVersion(String softwareVersion) {
236            TextSingleFormField.Builder builder = FormField.builder(SOFTWARE_VERSION);
237            builder.setValue(softwareVersion);
238            dataFormBuilder.addField(builder.build());
239            return this;
240        }
241
242        /**
243         * Include {@link DataForm} to be encapsulated under SoftwareInfoForm.
244         * <br>
245         * @param dataForm The dataform containing Software Information
246         * @return Builder
247         */
248        public Builder setDataForm(DataForm dataForm) {
249            if (dataForm.getTitle() != null || !dataForm.getItems().isEmpty()
250                    || dataForm.getReportedData() != null || !dataForm.getInstructions().isEmpty()) {
251                throw new IllegalArgumentException("Illegal Arguements for SoftwareInformation");
252            }
253            String formTypeValue = dataForm.getFormType();
254            if (formTypeValue == null) {
255                throw new IllegalArgumentException("FORM_TYPE Formfield missing");
256            }
257            if (!formTypeValue.equals(SoftwareInfoForm.FORM_TYPE)) {
258                throw new IllegalArgumentException("Malformed FORM_TYPE Formfield encountered");
259            }
260            this.dataFormBuilder = dataForm.asBuilder();
261            return this;
262        }
263
264        /**
265         * This method is called to build a {@link SoftwareInfoForm}.
266         * <br>
267         * @return Builder
268         */
269        public SoftwareInfoForm build() {
270            return new SoftwareInfoForm(dataFormBuilder.build());
271        }
272    }
273}