1/**
2 * $RCSfile$
3 * $Revision$
4 * $Date$
5 *
6 * Copyright 2003-2007 Jive Software.
7 *
8 * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *     http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21package org.jivesoftware.smackx;
22
23import org.jivesoftware.smack.packet.Packet;
24import org.jivesoftware.smack.packet.PacketExtension;
25import org.jivesoftware.smackx.packet.DataForm;
26
27import java.util.ArrayList;
28import java.util.Collections;
29import java.util.Iterator;
30import java.util.List;
31
32/**
33 * Represents a set of data results returned as part of a search. The report is structured
34 * in columns and rows.
35 *
36 * @author Gaston Dombiak
37 */
38public class ReportedData {
39
40    private List<Column> columns = new ArrayList<Column>();
41    private List<Row> rows = new ArrayList<Row>();
42    private String title = "";
43
44    /**
45     * Returns a new ReportedData if the packet is used for reporting data and includes an
46     * extension that matches the elementName and namespace "x","jabber:x:data".
47     *
48     * @param packet the packet used for reporting data.
49     */
50    public static ReportedData getReportedDataFrom(Packet packet) {
51        // Check if the packet includes the DataForm extension
52        PacketExtension packetExtension = packet.getExtension("x","jabber:x:data");
53        if (packetExtension != null) {
54            // Check if the existing DataForm is a result of a search
55            DataForm dataForm = (DataForm) packetExtension;
56            if (dataForm.getReportedData() != null)
57                return new ReportedData(dataForm);
58        }
59        // Otherwise return null
60        return null;
61    }
62
63
64    /**
65     * Creates a new ReportedData based on the returned dataForm from a search
66     *(namespace "jabber:iq:search").
67     *
68     * @param dataForm the dataForm returned from a search (namespace "jabber:iq:search").
69     */
70    private ReportedData(DataForm dataForm) {
71        // Add the columns to the report based on the reported data fields
72        for (Iterator fields = dataForm.getReportedData().getFields(); fields.hasNext();) {
73            FormField field = (FormField)fields.next();
74            columns.add(new Column(field.getLabel(), field.getVariable(), field.getType()));
75        }
76
77        // Add the rows to the report based on the form's items
78        for (Iterator items = dataForm.getItems(); items.hasNext();) {
79            DataForm.Item item = (DataForm.Item)items.next();
80            List<Field> fieldList = new ArrayList<Field>(columns.size());
81            FormField field;
82            for (Iterator fields = item.getFields(); fields.hasNext();) {
83                field = (FormField) fields.next();
84                // The field is created with all the values of the data form's field
85                List<String> values = new ArrayList<String>();
86                for (Iterator<String> it=field.getValues(); it.hasNext();) {
87                    values.add(it.next());
88                }
89                fieldList.add(new Field(field.getVariable(), values));
90            }
91            rows.add(new Row(fieldList));
92        }
93
94        // Set the report's title
95        this.title = dataForm.getTitle();
96    }
97
98
99    public ReportedData(){
100        // Allow for model creation of ReportedData.
101    }
102
103    /**
104     * Adds a new <code>Row</code>.
105     * @param row the new row to add.
106     */
107    public void addRow(Row row){
108        rows.add(row);
109    }
110
111    /**
112     * Adds a new <code>Column</code>
113     * @param column the column to add.
114     */
115    public void addColumn(Column column){
116        columns.add(column);
117    }
118
119
120    /**
121     * Returns an Iterator for the rows returned from a search.
122     *
123     * @return an Iterator for the rows returned from a search.
124     */
125    public Iterator<Row> getRows() {
126        return Collections.unmodifiableList(new ArrayList<Row>(rows)).iterator();
127    }
128
129    /**
130     * Returns an Iterator for the columns returned from a search.
131     *
132     * @return an Iterator for the columns returned from a search.
133     */
134    public Iterator<Column> getColumns() {
135        return Collections.unmodifiableList(new ArrayList<Column>(columns)).iterator();
136    }
137
138
139    /**
140     * Returns the report's title. It is similar to the title on a web page or an X
141     * window.
142     *
143     * @return title of the report.
144     */
145    public String getTitle() {
146        return title;
147    }
148
149    /**
150     *
151     * Represents the columns definition of the reported data.
152     *
153     * @author Gaston Dombiak
154     */
155    public static class Column {
156        private String label;
157        private String variable;
158        private String type;
159
160        /**
161         * Creates a new column with the specified definition.
162         *
163         * @param label the columns's label.
164         * @param variable the variable name of the column.
165         * @param type the format for the returned data.
166         */
167        public Column(String label, String variable, String type) {
168            this.label = label;
169            this.variable = variable;
170            this.type = type;
171        }
172
173        /**
174         * Returns the column's label.
175         *
176         * @return label of the column.
177         */
178        public String getLabel() {
179            return label;
180        }
181
182
183        /**
184         * Returns the column's data format. Valid formats are:
185         *
186         * <ul>
187         *  <li>text-single -> single line or word of text
188         *  <li>text-private -> instead of showing the user what they typed, you show ***** to
189         * protect it
190         *  <li>text-multi -> multiple lines of text entry
191         *  <li>list-single -> given a list of choices, pick one
192         *  <li>list-multi -> given a list of choices, pick one or more
193         *  <li>boolean -> 0 or 1, true or false, yes or no. Default value is 0
194         *  <li>fixed -> fixed for putting in text to show sections, or just advertise your web
195         * site in the middle of the form
196         *  <li>hidden -> is not given to the user at all, but returned with the questionnaire
197         *  <li>jid-single -> Jabber ID - choosing a JID from your roster, and entering one based
198         * on the rules for a JID.
199         *  <li>jid-multi -> multiple entries for JIDs
200         * </ul>
201         *
202         * @return format for the returned data.
203         */
204        public String getType() {
205            return type;
206        }
207
208
209        /**
210         * Returns the variable name that the column is showing.
211         *
212         * @return the variable name of the column.
213         */
214        public String getVariable() {
215            return variable;
216        }
217
218
219    }
220
221    public static class Row {
222        private List<Field> fields = new ArrayList<Field>();
223
224        public Row(List<Field> fields) {
225            this.fields = fields;
226        }
227
228        /**
229         * Returns the values of the field whose variable matches the requested variable.
230         *
231         * @param variable the variable to match.
232         * @return the values of the field whose variable matches the requested variable.
233         */
234        public Iterator getValues(String variable) {
235            for(Iterator<Field> it=getFields();it.hasNext();) {
236                Field field = it.next();
237                if (variable.equalsIgnoreCase(field.getVariable())) {
238                    return field.getValues();
239                }
240            }
241            return null;
242        }
243
244        /**
245         * Returns the fields that define the data that goes with the item.
246         *
247         * @return the fields that define the data that goes with the item.
248         */
249        private Iterator<Field> getFields() {
250            return Collections.unmodifiableList(new ArrayList<Field>(fields)).iterator();
251        }
252    }
253
254    public static class Field {
255        private String variable;
256        private List<String> values;
257
258        public Field(String variable, List<String> values) {
259            this.variable = variable;
260            this.values = values;
261        }
262
263        /**
264         * Returns the variable name that the field represents.
265         *
266         * @return the variable name of the field.
267         */
268        public String getVariable() {
269            return variable;
270        }
271
272        /**
273         * Returns an iterator on the values reported as part of the search.
274         *
275         * @return the returned values of the search.
276         */
277        public Iterator<String> getValues() {
278            return Collections.unmodifiableList(values).iterator();
279        }
280    }
281}
282