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