1 /**
2  * Copyright (C) 2010-2014 IBM Corporation and Others. All Rights Reserved.
3  */
4 package org.unicode.cldr.web;
5 
6 import java.util.Comparator;
7 import java.util.Deque;
8 import java.util.LinkedList;
9 import java.util.Set;
10 import java.util.TreeSet;
11 
12 import org.unicode.cldr.util.StackTracker;
13 
14 import com.ibm.icu.dev.util.ElapsedTimer;
15 import com.ibm.icu.text.NumberFormat;
16 
17 /**
18  * @author srl
19  *
20  */
21 public class SurveyProgressManager implements CLDRProgressIndicator {
22     private static final boolean DEBUG_PROGRESS = true;
23     private Deque<SurveyProgressTask> tasks = new LinkedList<>();
24 
25     private class SurveyProgressTask implements CLDRProgressIndicator.CLDRProgressTask {
26         boolean dead = false;
27         int progressMax = 0; // "an operation is in progress"
28         int progressCount = 0;
29         String progressSub = null;
30         long taskTime = System.currentTimeMillis();
31         long subTaskTime = taskTime;
32         String progressWhat = null;
33 
SurveyProgressTask(String what, int max)34         public SurveyProgressTask(String what, int max) {
35             this.progressMax = max;
36             this.progressWhat = what;
37             this.progressCount = 0;
38         }
39 
40         @Override
close()41         public void close() {
42             if (tasks.isEmpty() || !tasks.contains(this)) {
43                 SurveyLog.warnOnce("State Error: Closing an already-closed CLDRProgressIndicator at stack " + StackTracker.currentStack());
44             } else {
45                 tasks.remove(this); // remove from deque
46             }
47             if (DEBUG_PROGRESS && SurveyMain.isUnofficial())
48                 System.err.println("Progress (" + progressWhat + ") DONE - "
49                     + ElapsedTimer.elapsedTime(taskTime, System.currentTimeMillis()) + " @" + SurveyMain.uptime);
50             dead = true;
51         }
52 
53         @Override
update(int count)54         public void update(int count) {
55             progressCount = count;
56             subTaskTime = System.currentTimeMillis();
57             if (SurveyMain.isUnofficial()) System.err.println("Progress (" + progressWhat + ") on #" + progressCount + " @" + SurveyMain.uptime);
58         }
59 
60         @Override
update(int count, String what)61         public void update(int count, String what) {
62             progressCount = count;
63             progressSub = what;
64             subTaskTime = System.currentTimeMillis();
65             // if(SurveyMain.isUnofficial()) System.err.println("Progress (" + progressWhat + ") on " + progressSub + " #"+progressCount  + " @" + SurveyMain.uptime);
66         }
67 
68         /**
69          * Update the sub-progress without moving the count
70          *
71          * @param what
72          */
73         @Override
update(String what)74         public void update(String what) {
75             progressSub = what;
76             if (progressMax < 0) {
77                 progressCount++;
78             }
79             subTaskTime = System.currentTimeMillis();
80             if (SurveyMain.isUnofficial()) System.err.println("Progress (" + progressWhat + ") on " + what + " @" + SurveyMain.uptime);
81         }
82 
83         @Override
startTime()84         public long startTime() {
85             return taskTime;
86         }
87 
88         /**
89          * What's the most recent time that anything happened?
90          *
91          * @return
92          */
recentTime()93         public long recentTime() {
94             if (subTaskTime > taskTime) {
95                 return subTaskTime;
96             } else {
97                 return taskTime;
98             }
99         }
100 
101         NumberFormat pctFmt = NumberFormat.getPercentInstance();
102 
103         @Override
toString()104         public String toString() {
105             if (dead)
106                 return "";
107             StringBuffer buf = new StringBuffer();
108             long now = System.currentTimeMillis();
109 
110             double max = progressMax;
111 
112             buf.append("<b>" + progressWhat + "</b>");
113             if ((now - taskTime) > 5000) {
114                 buf.append(" <span class='elapsedtime'>" + ElapsedTimer.elapsedTime(taskTime, now) + "</span>");
115             }
116 
117             double cur = progressCount;
118 
119             appendProgressBar(buf, cur, max);
120 
121             if (progressMax >= 0) { // only show the actual number if >0
122                 buf.append(progressCount + " of " + progressMax + " &mdash; ");
123             }
124             if (max > 0) {
125                 double pct = (cur / max);
126                 buf.append(pctFmt.format(pct));
127             } else if (progressCount > 0) {
128                 buf.append("(#" + progressCount + ")");
129             }
130             if (progressSub != null) {
131                 buf.append("<br/>" + progressSub);
132             }
133             if ((subTaskTime > taskTime) && ((now - subTaskTime) > 5000)) {
134                 buf.append(" <span class='elapsedtime'>" + ElapsedTimer.elapsedTime(subTaskTime, now) + "</span>");
135             }
136             return buf.toString();
137         }
138     }
139 
140     /*
141      * (non-Javadoc)
142      *
143      * @see
144      * org.unicode.cldr.web.CLDRProgressIndicator#openProgress(java.lang.String)
145      */
146     @Override
openProgress(String what)147     public CLDRProgressTask openProgress(String what) {
148         return openProgress(what, -100);
149     }
150 
openConsoleProgress(final String what0)151     public static CLDRProgressTask openConsoleProgress(final String what0) {
152         return new CLDRProgressTask() {
153             ElapsedTimer et = new ElapsedTimer("Progress " + what0);
154             long startTime = System.currentTimeMillis();
155 
156             @Override
157             public void close() {
158                 System.out.println(et + ":  close");
159             }
160 
161             @Override
162             public void update(int count) {
163                 System.out.println(et + ":  Update #" + count);
164             }
165 
166             @Override
167             public void update(int count, String what) {
168                 System.out.println(et + ":  Update " + what + " #" + count);
169             }
170 
171             @Override
172             public void update(String what) {
173                 System.out.println(et + ":  Update " + what);
174             }
175 
176             @Override
177             public long startTime() {
178                 return startTime;
179             }
180 
181         };
182     }
183 
184     /*
185      * (non-Javadoc)
186      *
187      * @see
188      * org.unicode.cldr.web.CLDRProgressIndicator#openProgress(java.lang.String,
189      * int)
190      */
191     @Override
openProgress(String what, int max)192     public CLDRProgressTask openProgress(String what, int max) {
193         SurveyProgressTask t = new SurveyProgressTask(what, max);
194         tasks.addLast(t);
195         if (SurveyMain.isUnofficial() && DEBUG_PROGRESS)
196             System.err.println("Progress (" + what + ") BEGIN");
197         return t;
198     }
199 
getProgress()200     public String getProgress() {
201         // make a list of non-dead tasks, sorted by age
202         Set<SurveyProgressTask> orderedTasks = new TreeSet<>(new Comparator<SurveyProgressTask>() {
203 
204             @Override
205             public int compare(SurveyProgressTask arg0, SurveyProgressTask arg1) {
206                 return (int) (arg1.recentTime() - arg0.recentTime());
207             }
208         });
209         for (SurveyProgressTask t : tasks) {
210             if (t != null && !t.dead)
211                 orderedTasks.add(t);
212         }
213 
214         StringBuffer buf = new StringBuffer();
215         buf.append("<table id='progress-list' border=0 class='progress-list"
216             + (orderedTasks.isEmpty() ? " progress-idle" : " progress-busy") + "'><tr>");
217         buf.append("<th>");
218         if (orderedTasks.isEmpty()) {
219             buf.append("<span id='busy0' onclick='document.getElementById(\"progress\").className=\"popout\";'><!-- idle -->\u00BB</span>");
220         } else {
221             buf.append("<span id='busy0' onclick='document.getElementById(\"progress\").className=\"popout\";'><!-- busy -->\u00BB</span>");
222         }
223         buf.append("<span id='busy1' onclick='document.getElementById(\"progress\").className=\"\";'><!-- hide -->\u00AB</span>"
224             + "</th>");
225         for (SurveyProgressTask t : orderedTasks) {
226             buf.append("<td>");
227             buf.append(t.toString());
228             buf.append("</td>");
229         }
230         if (buf.length() > 0) {
231             buf.append("</tr></table>");
232         }
233         return buf.toString();
234     }
235 
appendProgressBar(StringBuffer buf, double cur, double max)236     public static StringBuffer appendProgressBar(StringBuffer buf, double cur, double max) {
237         if (max > 0) {
238             if (cur > max) {
239                 cur = max;
240             }
241             if (cur < 0) {
242                 cur = 0;
243             }
244 
245             double barWid = (cur / max) * SurveyMain.PROGRESS_WID;
246 
247             int barX = (int) barWid;
248             int remainX = SurveyMain.PROGRESS_WID - barX;
249 
250             buf.append("<table class='stprogress' border=0 ><tr height='12'>");
251             if (barX > 0) {
252                 buf.append("<td class='bar' width='" + barX + "' >");
253                 buf.append("</td>");
254             }
255             if (remainX > 0) {
256                 buf.append("<td class='remain' width='" + remainX + "'>");
257                 buf.append("</td>");
258             }
259             buf.append("</table>");
260         }
261         return buf;
262     }
263 
264 }
265