1 //  Copyright 2011-2012 IBM Corporation and Others. All rights reserved.
2 
3 package org.unicode.cldr.web;
4 
5 import java.util.Collection;
6 import java.util.Comparator;
7 import java.util.LinkedList;
8 import java.util.List;
9 import java.util.Set;
10 import java.util.TreeSet;
11 import java.util.Vector;
12 
13 import org.unicode.cldr.web.DataSection.DataRow;
14 import org.unicode.cldr.web.Partition.Membership;
15 
16 /**
17  * This class represents a mode of sorting: i.e., by code, etc.
18  *
19  * @author srl
20  *
21  */
22 
23 public abstract class SortMode {
24 
25     static String getSortMode(WebContext ctx, String prefix) {
26         String sortMode = null;
27         sortMode = ctx.pref(SurveyMain.PREF_SORTMODE, SurveyMain.PREF_SORTMODE_DEFAULT);
28         return sortMode;
29     }
30 
31     public static String getSortMode(WebContext ctx, DataSection section) {
32         return getSortMode(ctx, section.xpathPrefix);
33     }
34 
35     public static SortMode getInstance(String mode) {
36         if (mode.equals(CodeSortMode.name)) {
37             return new CodeSortMode();
38         } else if (mode.equals(CalendarSortMode.name)) {
39             return new CalendarSortMode();
40         } else if (mode.equals(MetazoneSortMode.name)) {
41             return new MetazoneSortMode();
42         } else if (mode.equals(InterestSort.name)) {
43             return new InterestSort();
44         } else if (mode.equals(NameSort.name)) {
45             return new NameSort();
46         } else if (mode.equals(PathHeaderSort.name)) {
47             return new PathHeaderSort();
48         } else {
49             return new CodeSortMode();
50         }
51     }
52 
53     public static List<String> getSortModesFor(String xpath) {
54         List<String> list = new LinkedList<>();
55         if (xpath.contains("/calendars")) {
56             list.add(CalendarSortMode.name);
57         } else if (xpath.contains("zone")) {
58             list.add(MetazoneSortMode.name);
59         } else {
60             list.add(CodeSortMode.name);
61         }
62         if (false) { // hide others
63             list.add(NameSort.name);
64             list.add(InterestSort.name);
65         }
66         return list;
67     }
68 
69     /**
70      * For subclasses
71      *
72      * @param p
73      * @param memberships
74      * @return
75      */
76     protected static final int categorizeDataRow(DataRow p, Partition.Membership[] memberships) {
77         int rv = -1;
78         for (int i = 0; (rv == -1) && (i < memberships.length); i++) {
79             if (memberships[i].isMember(p)) {
80                 rv = i;
81             }
82         }
83         return rv;
84     }
85 
86     /**
87      * Name of this mode.
88      *
89      * @return
90      */
91     abstract String getName();
92 
93     abstract String getDisplayName();
94 
95     /**
96      *
97      * @return
98      */
99     abstract Partition.Membership[] memberships();
100 
101     /**
102      *
103      * @return
104      */
105     abstract Comparator<DataRow> createComparator();
106 
107     public String getDisplayName(DataRow p) {
108         if (p == null) {
109             return "(null)";
110         } else if (p.getDisplayName() != null) {
111             return p.getDisplayName();
112         } else {
113             return p.prettyPath;
114         }
115     }
116 
117     enum SortKeyType {
118         SORTKEY_INTEREST, SORTKEY_CALENDAR, SORTKEY_METAZONE
119     }
120 
121     public static final int[] reserveForSort() {
122         int[] x = new int[SortKeyType.values().length];
123         for (int i = 0; i < x.length; i++) {
124             x[i] = -1;
125         }
126         return x;
127     }
128 
129     protected static int compareMembers(DataRow p1, DataRow p2, Membership[] memberships, int ourKey) {
130         if (p1.reservedForSort[ourKey] == -1) {
131             p1.reservedForSort[ourKey] = categorizeDataRow(p1, memberships);
132         }
133         if (p2.reservedForSort[ourKey] == -1) {
134             p2.reservedForSort[ourKey] = categorizeDataRow(p2, memberships);
135         }
136 
137         if (p1.reservedForSort[ourKey] < p2.reservedForSort[ourKey]) {
138             return -1;
139         } else if (p1.reservedForSort[ourKey] > p2.reservedForSort[ourKey]) {
140             return 1;
141         } else {
142             return 0;
143         }
144     }
145 
146     public Partition[] createPartitions(DataRow[] rows) {
147         return createPartitions(memberships(), rows);
148     }
149 
150     /**
151      * Create partitions based on the membership in the rows
152      *
153      * @param memberships
154      * @param rows
155      * @return
156      */
157     protected Partition[] createPartitions(Membership[] memberships, DataRow[] rows) {
158         Vector<Partition> v = new Vector<>();
159         if (memberships != null) { // something with partitions
160             Partition testPartitions[] = createPartitions(memberships);
161 
162             // find the starts
163             int lastGood = 0;
164             for (int i = 0; i < rows.length; i++) {
165                 DataRow p = rows[i];
166 
167                 for (int j = lastGood; j < testPartitions.length; j++) {
168                     if (testPartitions[j].pm.isMember(p)) {
169                         if (j > lastGood) {
170                             lastGood = j;
171                         }
172                         if (testPartitions[j].start == -1) {
173                             testPartitions[j].start = i;
174                         }
175                         break; // sit here until we fail membership
176                     }
177 
178                     if (testPartitions[j].start != -1) {
179                         testPartitions[j].limit = i;
180                     }
181                 }
182             }
183             // catch the last item
184             if ((testPartitions[lastGood].start != -1) && (testPartitions[lastGood].limit == -1)) {
185                 testPartitions[lastGood].limit = rows.length; // limit = off the
186                 // end.
187             }
188 
189             for (int j = 0; j < testPartitions.length; j++) {
190                 if (testPartitions[j].start != -1) {
191                     if (testPartitions[j].start != 0 && v.isEmpty()) {
192                         // v.add(new
193                         // Partition("Other",0,testPartitions[j].start));
194                     }
195                     v.add(testPartitions[j]);
196                 }
197             }
198         } else {
199             // default partition - e'erthing.
200             v.add(new Partition(null, 0, rows.length));
201         }
202         return v.toArray(new Partition[0]); // fold it up
203     }
204 
205     /**
206      * Create empty partitions
207      *
208      * @param memberships
209      * @return
210      */
211     public static Partition[] createPartitions(Membership[] memberships) {
212         if (memberships == null) {
213             Partition empty[] = new Partition[1];
214             empty[0] = new Partition(null, 0, 0);
215             return empty;
216         }
217         Partition testPartitions[] = new Partition[memberships.length];
218         for (int i = 0; i < memberships.length; i++) {
219             testPartitions[i] = new Partition(memberships[i]);
220         }
221         return testPartitions;
222     }
223 
224     public DataSection.DisplaySet createDisplaySet(XPathMatcher matcher, Collection<DataRow> values) {
225         DataRow rows[] = createSortedList(createComparator(), matcher, values);
226         return new DataSection.DisplaySet(rows, this, createPartitions(rows));
227     }
228 
229     protected DataRow[] createSortedList(Comparator<DataRow> comparator, XPathMatcher matcher, Collection<DataRow> rows) {
230         // partitions = sortMode.createPartitions(rows);
231         // DisplaySet aDisplaySet = new DisplaySet(createSortedList(sortMode,
232         // matcher,rowsHash.values()), sortMode);
233         Set<DataRow> newSet;
234 
235         newSet = new TreeSet<>(comparator);
236 
237         if (matcher == null) {
238             newSet.addAll(rows); // sort it
239         } else {
240             for (Object o : rows) {
241                 DataRow p = (DataRow) o;
242 
243                 // /*srl*/ /*if(p.type.indexOf("Australia")!=-1)*/ {
244                 // System.err.println("xp: "+p.xpathSuffix+":"+p.type+"- match: "+(matcher.matcher(p.type).matches()));
245                 // }
246 
247                 if (!matcher.matches(p.getXpath(), p.getXpathId())) {
248                     if (false)
249                         System.err.println("not match: " + p.xpathId + " / " + p.getXpath());
250                     continue;
251 
252                 } else {
253                     newSet.add(p);
254                 }
255             }
256         }
257         String matchName = "(*)";
258         if (matcher != null) {
259             matchName = matcher.getName();
260         }
261         if (SurveyMain.isUnofficial())
262             System.err.println("Loaded " + newSet.size() + " from " + matchName + " - base xpath (" + rows.size() + ")  = "
263                 + getName());
264         return newSet.toArray(new DataRow[newSet.size()]);
265     }
266 }
267