001package arcommon.progress;
002
003import java.awt.event.ActionEvent;
004import java.awt.event.ActionListener;
005import java.util.ArrayList;
006import java.util.Iterator;
007
008import arcommon.MyTimer;
009
010public class ProgressThreadData {
011    
012    public static int updateInterval = 10;
013    
014    private static ArrayList<ProgressThreadData> progressThreadDataList;
015    
016    public static void addProgressActionListenerForCurrentThread(ProgressActionListener pprogressActionListener) {
017        ProgressThreadData progressThreadData = findProgressThreadData(true);
018        progressThreadData.addProgressActionListener(pprogressActionListener);
019    }
020
021    public static void addProgressActionListener(Thread thread, ProgressActionListener pprogressActionListener) {
022        ProgressThreadData progressThreadData = findProgressThreadData(thread, true);
023        progressThreadData.addProgressActionListener(pprogressActionListener);
024    }
025
026    public static ProgressState createProgressState() {
027        ProgressThreadData progressThreadData = findProgressThreadData(false);
028        if (progressThreadData == null) {
029            return null;
030        }
031        
032        progressThreadData.checkIfThereShouldBeNotified();
033        return progressThreadData.createProgressStateLocal();
034    }
035    
036    public static void disposeProgressState(ProgressState progressState) {
037        if (progressState == null) {
038            return ;
039        }
040        
041        ProgressThreadData progressThreadData = findProgressThreadData(false);
042        if (progressThreadData == null) {
043            return ;
044        }
045        
046        progressThreadData.disposeProgressStateLocal(progressState);
047        progressThreadData.checkIfThereShouldBeNotified();
048    }
049    
050    public static void removeAllProgressStates() {
051        ProgressThreadData progressThreadData = findProgressThreadData(false);
052        if (progressThreadData == null) {
053            return ;
054        }
055        
056        if (progressThreadData.progressStates == null) {
057            return ;
058        }
059        
060        Iterator<ProgressState> i = new ArrayList<ProgressState>(progressThreadData.progressStates).iterator();
061        while (i.hasNext()) {
062            ProgressState progressState = i.next();
063            progressThreadData.disposeProgressStateLocal(progressState);
064        }
065    }
066    
067    public static ProgressThreadData getCurrentProgressThreadData() {
068        return findProgressThreadData(true);
069    }
070    
071    public static ProgressThreadData getProgressThreadData(Thread thread) {
072        return findProgressThreadData(thread, true);
073    }
074    
075    private static ProgressThreadData findProgressThreadData(boolean create) {
076        return findProgressThreadData(Thread.currentThread(), create);
077    }
078    
079    private static ProgressThreadData findProgressThreadData(Thread forThread, boolean create) {
080        if (progressThreadDataList == null) {
081            if (!create) {
082                return null;
083            }
084            
085            progressThreadDataList = new ArrayList<ProgressThreadData>();
086        }
087        
088        synchronized (progressThreadDataList) {
089            Iterator<ProgressThreadData> i = progressThreadDataList.iterator();
090            while (i.hasNext()) {
091                ProgressThreadData progressThreadData = i.next();
092                if (progressThreadData.thread == forThread) {
093                    return progressThreadData;
094                }
095            }
096            
097            if (!create) {
098                return null;
099            }
100            
101            ProgressThreadData progressThreadData = new ProgressThreadData(forThread);
102            progressThreadDataList.add(progressThreadData);
103            return progressThreadData;
104        }
105    }
106
107    public static void dispose() {
108        if (progressThreadDataList == null) {
109            return ;
110        }
111        
112        synchronized (progressThreadDataList) {
113            Iterator<ProgressThreadData> i = progressThreadDataList.iterator();
114            while (i.hasNext()) {
115                ProgressThreadData progressThreadData = i.next();
116                if (progressThreadData.timerActionListener != null) {
117                    MyTimer.removeActionListener(progressThreadData.timerActionListener);
118                }
119            }
120        }
121    }
122
123    private Thread thread;
124    
125    private ArrayList<ProgressActionListener> progressActionListeners;
126    private ArrayList<ProgressState> progressStates;
127    private Object data;
128    private ActionListener timerActionListener;
129
130    private String progressStateString;
131
132    public ProgressThreadData(Thread pthread) {
133        thread = pthread;
134    }
135
136    public Thread getThread() {
137        return thread;
138    }
139    
140    public ProgressState createProgressStateLocal() {
141        if (progressStates == null) {
142            progressStates = new ArrayList<ProgressState>();
143        }
144
145        synchronized (progressStates) {
146            if (progressStates.size() == 0) {
147                if (timerActionListener == null) {
148                    timerActionListener = new ActionListener() {
149                        public void actionPerformed(ActionEvent e) {
150                            synchronized (progressStates) {
151                                for (ProgressState progressState : progressStates) {
152                                    progressState.incNotifyCounter();
153                                }
154                            }
155                        }
156                    };
157                }
158                MyTimer.addActionListener(1, timerActionListener);
159            }
160            
161            ProgressState progressState = new ProgressState(this);
162            progressStates.add(progressState);
163            return progressState;
164        }
165    }
166    
167    public void checkIfThereShouldBeNotified() {
168        if (progressStates == null) {
169            return ;
170        }
171        
172        boolean notify = false;
173        synchronized (progressStates) {
174            for (ProgressState progressState : progressStates) {
175                int notifyCounter = progressState.getNotifyCounter();
176                if (notifyCounter >= updateInterval) {
177                    notify = true;
178                    break;
179                }
180            }
181        }
182        
183        if (notify) {
184            progressStateString = calculateProgressStateString();
185            
186            fireProgressActionListener();
187
188            // Placed after fireProgressActionListener because calculateProgressStateString() depends on progressState.notifyCounter.
189            synchronized (progressStates) {
190                for (ProgressState progressState : progressStates) {
191                    progressState.resetNotifyCounter();
192                }
193            }
194        }
195    }
196    
197    public void disposeProgressStateLocal(ProgressState progressState) {
198        if (progressStates == null) {
199            return ;
200        }
201        
202        synchronized (progressStates) {
203            progressStates.remove(progressState);
204            if (progressStates.size() == 0) {
205                MyTimer.removeActionListener(timerActionListener);
206            }
207        }
208    }
209
210    public String getProgressStateString() {
211        return progressStateString;
212    }
213    
214    private String calculateProgressStateString() {
215        if (progressStates == null) {
216            return "";
217        }
218        
219        synchronized (progressStates) {
220            Iterator<ProgressState> i = new ArrayList<ProgressState>(progressStates).iterator();
221            if (!i.hasNext()) {
222                return "";
223            }
224            String progressStatesToString = progressStatesToString(i);
225            if (progressStatesToString.length() == 0) {
226                System.out.println("asd");
227            }
228            return progressStatesToString;
229        }
230    }
231    
232    private String progressStatesToString(Iterator<ProgressState> i) {
233        ProgressState progressState = i.next();
234        int notifyCounter = progressState.getNotifyCounter();
235        if (notifyCounter < updateInterval) {
236            // Only notify on slow enough progressStates.
237            return "";
238        }
239        
240        String result = progressState.toString();
241        if (i.hasNext()) {
242            String progressStatesToString = progressStatesToString(i);
243            if (progressStatesToString.length() > 0) {
244                result = result + " (" + progressStatesToString + ")";
245            }
246        }
247        
248        return result;
249    }
250    
251    public Object getData() {
252        return data;
253    }
254
255    public void setData(Object pdata) {
256        data = pdata;
257    }
258    
259    public void addProgressActionListener(ProgressActionListener pprogressActionListener) {
260        if (progressActionListeners == null) {
261            progressActionListeners = new ArrayList<ProgressActionListener>();
262        }
263        progressActionListeners.add(pprogressActionListener);
264    }
265
266    public void removeProgressActionListener(ProgressActionListener pprogressActionListener) {
267        if (progressActionListeners == null) {
268            return ;
269        }
270        progressActionListeners.remove(pprogressActionListener);
271        if (progressActionListeners.size() == 0) {
272            progressActionListeners = null;
273        }
274    }
275
276    public void fireProgressActionListener() {
277        if (progressActionListeners == null) {
278            return ;
279        }
280        
281        ArrayList<ProgressActionListener> sendTo = new ArrayList<ProgressActionListener>();
282        synchronized (progressActionListeners) {
283            sendTo.addAll(progressActionListeners);
284        }
285        
286        ProgressAction progressAction = new ProgressAction(this);
287        for (int i = 0; i < sendTo.size(); i++) {
288            ProgressActionListener progressActionListener = sendTo.get(i);
289            progressActionListener.progressChanged(progressAction);
290        }
291    }
292}