OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 73 | Rev 94 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.map.model;
15
 
16
import org.openconcerto.map.ui.MapViewerPanel;
17
import org.openconcerto.utils.RTInterruptedException;
18
import org.openconcerto.utils.StringUtils;
19
 
20
import java.awt.Color;
21
import java.awt.Polygon;
61 ilm 22
import java.beans.PropertyChangeEvent;
23
import java.beans.PropertyChangeListener;
17 ilm 24
import java.io.BufferedReader;
61 ilm 25
import java.io.File;
26
import java.io.FileReader;
27
import java.io.IOException;
17 ilm 28
import java.io.InputStreamReader;
29
import java.util.ArrayList;
30
import java.util.Collections;
31
import java.util.Comparator;
32
import java.util.HashMap;
33
import java.util.List;
34
import java.util.Map;
35
import java.util.logging.Logger;
36
 
37
import javax.swing.JFrame;
61 ilm 38
import javax.swing.SwingUtilities;
17 ilm 39
import javax.swing.UIManager;
40
 
41
public class Ville {
61 ilm 42
    // TODO: switch from Lambert to Mercator (see jmapprojlib SF project)
17 ilm 43
    private static Map<String, Ville> map = new HashMap<String, Ville>();
44
    private static DatabaseAccessor accessor;
61 ilm 45
    private final static List<Ville> villes = new ArrayList<Ville>(39000);
46
    private final static List<String> villesNames = new ArrayList<String>(39000);
47
    private final static List<PropertyChangeListener> listeners = new ArrayList<PropertyChangeListener>();
17 ilm 48
    private static Thread init = null;
49
    private static boolean loaded = false;
50
    private int nbMatch = 0;
51
 
52
    public synchronized static void init(final DatabaseAccessor d) {
53
 
54
        await();
55
        accessor = d;
56
        init = new Thread(new Runnable() {
57
            @Override
58
            public void run() {
59
                synchronized (Ville.class) {
60
                    parseFile();
61
                    final List<Ville> l = d.read();
62
                    for (final Ville ville : l) {
63
                        addVilleSilently(ville);
64
                    }
65
                    init = null;
66
                    Ville.class.notifyAll();
67
                }
68
 
69
            }
70
        });
71
        init.setPriority(Thread.MIN_PRIORITY);
72
        init.setName("Ville asynchronous loader");
73
        init.start();
74
 
75
    }
76
 
61 ilm 77
    private static void parseFile() {
78
        parseFile(null);
79
    }
80
 
81
    private static synchronized void parseFile(File mapDir) {
17 ilm 82
        if (loaded) {
83
            throw new IllegalStateException("Data already loaded");
84
        }
85
        long t1 = System.nanoTime();
86
        try {
61 ilm 87
            InputStreamReader fReader = null;
88
            if (mapDir != null && mapDir.exists() && mapDir.list().length > 0) {
89
                File[] files = mapDir.listFiles();
90
                for (int i = 0; i < files.length; i++) {
91
                    final File file = files[i];
92
                    fReader = new FileReader(file);
93
                    parse(fReader);
94
                    fReader.close();
95
                }
17 ilm 96
 
61 ilm 97
            } else {
98
                fReader = new InputStreamReader(Ville.class.getResourceAsStream("villes.txt"), "UTF8");
99
                parse(fReader);
100
                fReader.close();
101
 
17 ilm 102
            }
103
 
104
        } catch (final Exception e) {
105
            e.printStackTrace();
106
        }
107
        long t2 = System.nanoTime();
108
        Logger.getLogger("map").config("parseFile took " + ((t2 - t1) / 1000000) + " ms");
109
        Collections.sort(villesNames);
110
        Region.parseFile();
111
        loaded = true;
112
    }
113
 
61 ilm 114
    private static void parse(InputStreamReader fReader) throws IOException {
115
        final BufferedReader bufReader = new BufferedReader(fReader, 4 * 1024 * 1024);
116
        String n = bufReader.readLine();
117
 
118
        while (n != null) {
119
            long pop = parsePositiveLong(bufReader.readLine());
120
            long x = parsePositiveLong(bufReader.readLine());
121
            long y = parsePositiveLong(bufReader.readLine());
122
            String cp = bufReader.readLine();
123
            final Ville v = new Ville(n, pop, x, y, cp);
124
            if (v.xLambert > 0) {
125
                addVilleSilently(v);
126
            }
127
            n = bufReader.readLine();
128
        }
129
        bufReader.close();
130
    }
131
 
17 ilm 132
    private static final void parseLine(final String line) {
133
 
134
        final List<String> strs = StringUtils.fastSplit(line, ';');
135
        final Ville v = new Ville(strs.get(3), parsePositiveLong(strs.get(4)), parsePositiveLong(strs.get(8)), parsePositiveLong(strs.get(9)), strs.get(2));
136
        if (strs.size() > 10) {
137
            v.setMinimumZoom(parsePositiveLong(strs.get(10)));
138
        }
139
        if (v.xLambert > 0) {
140
            addVilleSilently(v);
141
            // System.out.println(v);
142
        }
143
 
144
    }
145
 
146
    private static synchronized void addVilleSilently(final Ville v) {
147
        villes.add(v);
148
        final String villeEtCode = v.getVilleEtCode();
149
        villesNames.add(villeEtCode);
150
        map.put(villeEtCode, v);
151
    }
152
 
153
    public static synchronized void addVille(final Ville v) {
61 ilm 154
        final String villeEtCode = v.getVilleEtCode();
155
        if (map.containsKey(villeEtCode)) {
156
            return;
157
        }
17 ilm 158
        addVilleSilently(v);
159
        accessor.store(v);
61 ilm 160
        fireListModified();
17 ilm 161
    }
162
 
25 ilm 163
    public static synchronized void removeVille(final Ville v) {
83 ilm 164
        if (v != null) {
165
            villes.remove(v);
166
            final String villeEtCode = v.getVilleEtCode();
167
            villesNames.remove(villeEtCode);
168
            map.remove(villeEtCode);
25 ilm 169
 
83 ilm 170
            accessor.delete(v);
171
            fireListModified();
172
        }
25 ilm 173
    }
174
 
17 ilm 175
    // ** getter
176
 
177
    private static final synchronized void await() {
178
        if (init != null) {
179
            try {
180
                Ville.class.wait();
181
            } catch (InterruptedException e) {
182
                throw new RTInterruptedException(e);
183
            }
184
        }
185
    }
186
 
61 ilm 187
    public static synchronized List<Ville> getVilles() {
17 ilm 188
        await();
189
        return villes;
190
    }
191
 
61 ilm 192
    public static synchronized List<String> getVillesNames() {
17 ilm 193
        await();
194
        return villesNames;
195
    }
196
 
197
    public static synchronized Ville getVilleFromVilleEtCode(final String s) {
198
        await();
199
        return map.get(s);
200
    }
201
 
202
    public static synchronized Ville getVilleContaining(String string) {
203
        string = string.trim().toLowerCase();
204
        final List<Ville> l = getVilles();
205
        final int size = l.size();
206
        for (int i = 0; i < size; i++) {
207
            final Ville v = l.get(i);
208
            if (v.getName().toLowerCase().indexOf(string) >= 0) {
209
                return v;
210
            }
211
        }
212
        return null;
213
    }
214
 
215
    public static synchronized List<Ville> getVillesContaining(String string) {
216
        string = string.trim().toLowerCase();
217
        List<Ville> list = new ArrayList<Ville>();
218
        final List<Ville> l = getVilles();
219
        final int size = l.size();
220
        for (int i = 0; i < size; i++) {
221
            final Ville v = l.get(i);
222
            if (v.getName().toLowerCase().indexOf(string) >= 0) {
223
                list.add(v);
224
            }
225
        }
226
        return list;
227
    }
228
 
73 ilm 229
    public static synchronized Ville getVilleContaining(String string, String codepostal) {
230
        if (codepostal.length() < 0 && string.length() <= 2) {
17 ilm 231
            return null;
232
        }
233
 
234
        List<Ville> l = getVillesFromCode(codepostal);
235
        if (l.size() == 0) {
236
            return null;
237
        }
238
        if (l.size() == 1) {
239
            return l.get(0);
240
        }
241
        string = string.trim().toLowerCase();
242
 
243
        final int size = l.size();
244
        for (int i = 0; i < size; i++) {
245
            final Ville v = l.get(i);
246
            if (v.getName().toLowerCase().indexOf(string) >= 0) {
247
                return v;
248
            }
249
        }
250
 
251
        return null;
252
    }
253
 
73 ilm 254
    private static List<Ville> getVillesFromCode(String cp) {
255
 
17 ilm 256
        List<Ville> list = new ArrayList<Ville>();
257
        final List<Ville> l = getVilles();
258
        final int size = l.size();
259
        for (int i = 0; i < size; i++) {
260
            final Ville v = l.get(i);
73 ilm 261
            if (v.getCodepostal().toLowerCase().indexOf(cp) >= 0) {
17 ilm 262
                list.add(v);
263
            }
264
        }
265
        return list;
266
    }
267
 
268
    /**
269
     * Return the cities.
270
     *
271
     * @param sel the selection.
272
     * @return the cities, or <code>null</code> si l'integralité des villes ou si la selection
273
     *         comporte moins de 3 points.
274
     */
275
    public synchronized static List<Ville> getVilleIn(final MapPointSelection sel) {
276
        ArrayList<Ville> r = null;
277
        if (sel == null) {
278
            return null;
279
        }
280
        if (sel.size() > 2) {
281
            r = new ArrayList<Ville>();
282
            final Polygon p = new Polygon();
283
 
284
            for (int i = 0; i < sel.size(); i++) {
285
                final MapPoint mapPoint = sel.get(i);
286
                final long x = mapPoint.getX();
287
                final long y = mapPoint.getY();
288
 
289
                p.addPoint((int) x, (int) y);
290
            }
291
            final long minX = sel.getMinX();
292
            final long maxX = sel.getMaxX();
293
            final long minY = sel.getMinY();
294
            final long maxY = sel.getMaxY();
295
            final List<Ville> allVilles = Ville.getVilles();
296
            // don't use for loop it generates an iterator which uses 25% of the time for this
297
            // method
298
            final int stop = allVilles.size();
299
            for (int i = 0; i < stop; i++) {
300
                final Ville v = allVilles.get(i);
301
                // both get() took another 25%
302
                final long x = v.getXLambert();
303
                if (x > maxX)
304
                    continue;
305
                if (x < minX)
306
                    continue;
307
                final long y = v.getYLambert();
308
                if (y > maxY)
309
                    continue;
310
                if (y < minY)
311
                    continue;
312
                if (!p.contains(x, y))
313
                    continue;
314
                r.add(v);
315
                // System.out.println("match:" + v);
316
            }
317
        }
318
        return r;
319
    }
320
 
321
    public static long parsePositiveLong(String str) {
322
        str = str.trim();
323
 
324
        long value = 0;
325
        final int stop = str.length();
326
 
327
        for (int i = 0; i < stop; i++) {
328
            final char c = str.charAt(i);
329
 
330
            if (c == '.') {
331
                break;
332
            }
333
 
334
            value *= 10;
335
            value += (c - '0');
336
 
337
        }
338
 
339
        // System.out.println("str" + str + "->" + value);
340
        return value;
341
    }
342
 
343
    public static synchronized long getMinXLambert() {
344
        final List<Ville> l = getVilles();
345
        if (l.size() > 0) {
346
            long min = l.get(0).xLambert;
347
            for (int i = 0; i < l.size(); i++) {
348
                final Ville v = l.get(i);
349
 
350
                if (v.xLambert < min) {
351
                    min = v.xLambert;
352
                }
353
 
354
            }
355
            return min;
356
        } else {
357
            return 0;
358
        }
359
 
360
    }
361
 
362
    static synchronized long getMaxXLambert() {
363
        final List<Ville> l = getVilles();
364
        if (l.size() > 0) {
365
            long max = l.get(0).xLambert;
366
            for (int i = 0; i < l.size(); i++) {
367
                final Ville v = l.get(i);
368
                if (v.xLambert > max) {
369
                    max = v.xLambert;
370
                }
371
            }
372
            return max;
373
        } else {
374
            return 0;
375
        }
376
    }
377
 
378
    public static synchronized long getMinYLambert() {
379
        final List<Ville> l = getVilles();
380
        long min = l.get(0).yLambert;
381
        for (int i = 0; i < l.size(); i++) {
382
            final Ville v = l.get(i);
383
            if (v.yLambert < min) {
384
                min = v.yLambert;
385
            }
386
        }
387
        return min;
388
    }
389
 
390
    static synchronized long getMaxYLambert() {
391
        final List<Ville> l = getVilles();
392
        long max = l.get(0).yLambert;
393
        for (int i = 0; i < l.size(); i++) {
394
            final Ville v = l.get(i);
395
            if (v.yLambert > max) {
396
                max = v.yLambert;
397
            }
398
        }
399
        return max;
400
    }
401
 
402
    // *** instance
61 ilm 403
    // Abbeville:WGS84 (GPS): 50.105467,1.8368330000000697 (N 50° 6' 19.68'',E 1° 50' 12.6'')
404
    // L93: X:616 353,359 Y:7 001 496,893
405
    // NTF: L. II étendue X: 563 846,221 Y: 2 567 930,242
17 ilm 406
    // 800001;Abbeville;0.409874955;0.031997697;80132;23787;900
407
    // --> 4098749550 , 0319976970 // dix chiffres apres la virgules
408
    private final String name;
409
 
410
    private final String codepostal;
411
 
412
    private final long xLambert;
413
 
414
    private final long yLambert;
415
 
416
    long population;
417
 
25 ilm 418
    //
17 ilm 419
    private long minimumZoom;
420
 
421
    private Color color = null;
422
 
423
    public String getCodepostal() {
424
        return this.codepostal;
425
    }
426
 
427
    public long getPopulation() {
428
        return this.population;
429
    }
430
 
431
    public long getXLambert() {
432
        return this.xLambert;
433
    }
434
 
435
    public long getYLambert() {
436
        return this.yLambert;
437
    }
438
 
439
    public String getName() {
440
        return this.name;
441
    }
442
 
443
    public String getVilleEtCode() {
444
        return this.name + " (" + this.codepostal + ")";
445
    }
446
 
447
    public Ville(final String name, final long population, final long xLambert, final long yLambert, String codepostal) {
448
        this.name = name;
449
        this.population = population;
450
        this.codepostal = codepostal;
451
        this.xLambert = xLambert;
452
        this.yLambert = yLambert;
453
    }
454
 
455
    @Override
456
    public String toString() {
73 ilm 457
        return this.name + " (" + this.codepostal + ")";
17 ilm 458
    }
459
 
460
    public Color getColor() {
461
        return this.color;
462
    }
463
 
464
    public void setColor(final Color color) {
465
        this.color = color;
466
    }
467
 
468
    private void setMinimumZoom(final long l) {
469
        this.minimumZoom = l;
470
 
471
    }
472
 
473
    public long getMinimumZoom() {
474
        return this.minimumZoom;
475
    }
476
 
477
    public void setNbMatch(int nb) {
478
        this.nbMatch = nb;
479
    }
480
 
481
    public int getNbMatch() {
482
        return this.nbMatch;
483
    }
484
 
485
    /**
486
     * @param args
487
     */
488
    public static void main(final String[] args) {
489
        try {
490
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
491
            final long t1 = System.nanoTime();
492
 
493
            Ville.parseFile();
494
 
495
            // Thread.sleep(10*1000);
496
 
497
            final long t2 = System.nanoTime();
498
            System.out.println("Parsing: " + (t2 - t1) / 1000000 + " ms");
499
            System.out.println("MinXLambert:" + getMinXLambert() + ",MinYLambert" + getMinYLambert());
500
            System.out.println("MaxXLambert:" + getMaxXLambert() + ",MinXLambert" + getMaxYLambert());
501
            System.out.println("DeltaX:" + (getMaxXLambert() - getMinXLambert()));
502
            System.out.println("DeltaY:" + (getMaxYLambert() - getMinYLambert()));
503
            final long t3 = System.nanoTime();
504
            System.out.println("Min: " + (t3 - t1) / 1000000 + " ms");
61 ilm 505
            SwingUtilities.invokeLater(new Runnable() {
17 ilm 506
 
61 ilm 507
                @Override
508
                public void run() {
509
                    final JFrame f = new JFrame();
510
                    f.setContentPane(new MapViewerPanel());
511
                    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
512
                    f.setSize(1000, 600);
513
                    f.setVisible(true);
514
                }
515
            });
516
 
17 ilm 517
        } catch (final Exception e) {
518
            e.printStackTrace();
519
        }
520
 
521
    }
522
 
523
    public static synchronized void sortByPopulation() {
524
        sortByPopulation(villes);
525
 
526
    }
527
 
528
    public static synchronized void sortByPopulation(List<Ville> list) {
529
        // Classe de la plus grande ville a la plus petite
530
        Collections.sort(list, new Comparator<Ville>() {
531
            @Override
532
            public int compare(Ville v1, Ville v2) {
533
                return (int) (v2.getPopulation() - v1.getPopulation());
534
            }
535
 
536
        });
537
 
538
    }
61 ilm 539
 
540
    public static void addListener(PropertyChangeListener listener) {
541
        if (!listeners.contains(listener)) {
542
            listeners.add(listener);
543
        }
544
    }
545
 
546
    public static void removeListener(PropertyChangeListener listener) {
547
        listeners.remove(listener);
548
    }
549
 
550
    private static void fireListModified() {
551
        for (PropertyChangeListener l : listeners) {
552
            l.propertyChange(new PropertyChangeEvent(Ville.class, "list", null, null));
553
        }
554
    }
555
 
17 ilm 556
}