OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 142 | 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
 
19
import java.awt.Color;
20
import java.awt.Polygon;
61 ilm 21
import java.beans.PropertyChangeEvent;
22
import java.beans.PropertyChangeListener;
17 ilm 23
import java.io.BufferedReader;
61 ilm 24
import java.io.File;
25
import java.io.FileReader;
26
import java.io.IOException;
17 ilm 27
import java.io.InputStreamReader;
28
import java.util.ArrayList;
29
import java.util.Collections;
30
import java.util.Comparator;
31
import java.util.HashMap;
32
import java.util.List;
33
import java.util.Map;
34
import java.util.logging.Logger;
35
 
36
import javax.swing.JFrame;
61 ilm 37
import javax.swing.SwingUtilities;
17 ilm 38
import javax.swing.UIManager;
39
 
40
public class Ville {
61 ilm 41
    // TODO: switch from Lambert to Mercator (see jmapprojlib SF project)
156 ilm 42
    private static Map<String, Ville> map = new HashMap<>();
17 ilm 43
    private static DatabaseAccessor accessor;
156 ilm 44
    private static final List<Ville> villes = new ArrayList<>(39000);
45
    private static final List<String> villesNames = new ArrayList<>(39000);
46
    private static final List<PropertyChangeListener> listeners = new ArrayList<>();
17 ilm 47
    private static Thread init = null;
48
    private static boolean loaded = false;
49
    private int nbMatch = 0;
50
 
156 ilm 51
    public static synchronized void init(final DatabaseAccessor d, final boolean loadFromFile) {
17 ilm 52
        await();
53
        accessor = d;
54
        init = new Thread(new Runnable() {
55
            @Override
56
            public void run() {
57
                synchronized (Ville.class) {
94 ilm 58
                    if (loadFromFile) {
59
                        parseFile();
60
                    }
17 ilm 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 synchronized void addVilleSilently(final Ville v) {
133
        villes.add(v);
134
        final String villeEtCode = v.getVilleEtCode();
135
        villesNames.add(villeEtCode);
136
        map.put(villeEtCode, v);
137
    }
138
 
139
    public static synchronized void addVille(final Ville v) {
61 ilm 140
        final String villeEtCode = v.getVilleEtCode();
141
        if (map.containsKey(villeEtCode)) {
142
            return;
143
        }
17 ilm 144
        addVilleSilently(v);
145
        accessor.store(v);
61 ilm 146
        fireListModified();
17 ilm 147
    }
148
 
25 ilm 149
    public static synchronized void removeVille(final Ville v) {
83 ilm 150
        if (v != null) {
151
            villes.remove(v);
152
            final String villeEtCode = v.getVilleEtCode();
153
            villesNames.remove(villeEtCode);
154
            map.remove(villeEtCode);
25 ilm 155
 
83 ilm 156
            accessor.delete(v);
157
            fireListModified();
158
        }
25 ilm 159
    }
160
 
17 ilm 161
    // ** getter
162
 
163
    private static final synchronized void await() {
164
        if (init != null) {
165
            try {
166
                Ville.class.wait();
167
            } catch (InterruptedException e) {
168
                throw new RTInterruptedException(e);
169
            }
170
        }
171
    }
172
 
61 ilm 173
    public static synchronized List<Ville> getVilles() {
17 ilm 174
        await();
175
        return villes;
176
    }
177
 
61 ilm 178
    public static synchronized List<String> getVillesNames() {
17 ilm 179
        await();
180
        return villesNames;
181
    }
182
 
183
    public static synchronized Ville getVilleFromVilleEtCode(final String s) {
184
        await();
185
        return map.get(s);
186
    }
187
 
188
    public static synchronized Ville getVilleContaining(String string) {
189
        string = string.trim().toLowerCase();
190
        final List<Ville> l = getVilles();
191
        final int size = l.size();
192
        for (int i = 0; i < size; i++) {
193
            final Ville v = l.get(i);
194
            if (v.getName().toLowerCase().indexOf(string) >= 0) {
195
                return v;
196
            }
197
        }
198
        return null;
199
    }
200
 
201
    public static synchronized List<Ville> getVillesContaining(String string) {
202
        string = string.trim().toLowerCase();
156 ilm 203
        List<Ville> list = new ArrayList<>();
17 ilm 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
                list.add(v);
210
            }
211
        }
212
        return list;
213
    }
214
 
73 ilm 215
    public static synchronized Ville getVilleContaining(String string, String codepostal) {
142 ilm 216
        if (codepostal.length() == 0 && string.length() <= 2) {
17 ilm 217
            return null;
218
        }
219
 
220
        List<Ville> l = getVillesFromCode(codepostal);
156 ilm 221
        if (l.isEmpty()) {
17 ilm 222
            return null;
223
        }
224
        if (l.size() == 1) {
225
            return l.get(0);
226
        }
227
        string = string.trim().toLowerCase();
228
 
229
        final int size = l.size();
230
        for (int i = 0; i < size; i++) {
231
            final Ville v = l.get(i);
232
            if (v.getName().toLowerCase().indexOf(string) >= 0) {
233
                return v;
234
            }
235
        }
236
 
237
        return null;
238
    }
239
 
73 ilm 240
    private static List<Ville> getVillesFromCode(String cp) {
156 ilm 241
        final List<Ville> list = new ArrayList<>();
17 ilm 242
        final List<Ville> l = getVilles();
243
        final int size = l.size();
244
        for (int i = 0; i < size; i++) {
245
            final Ville v = l.get(i);
73 ilm 246
            if (v.getCodepostal().toLowerCase().indexOf(cp) >= 0) {
17 ilm 247
                list.add(v);
248
            }
249
        }
250
        return list;
251
    }
252
 
253
    /**
254
     * Return the cities.
255
     *
256
     * @param sel the selection.
257
     * @return the cities, or <code>null</code> si l'integralité des villes ou si la selection
258
     *         comporte moins de 3 points.
259
     */
156 ilm 260
    public static synchronized List<Ville> getVilleIn(final MapPointSelection sel) {
17 ilm 261
        if (sel == null) {
262
            return null;
263
        }
156 ilm 264
        ArrayList<Ville> r = null;
17 ilm 265
        if (sel.size() > 2) {
156 ilm 266
            r = new ArrayList<>();
17 ilm 267
            final Polygon p = new Polygon();
268
 
269
            for (int i = 0; i < sel.size(); i++) {
270
                final MapPoint mapPoint = sel.get(i);
271
                final long x = mapPoint.getX();
272
                final long y = mapPoint.getY();
273
 
274
                p.addPoint((int) x, (int) y);
275
            }
276
            final long minX = sel.getMinX();
277
            final long maxX = sel.getMaxX();
278
            final long minY = sel.getMinY();
279
            final long maxY = sel.getMaxY();
280
            final List<Ville> allVilles = Ville.getVilles();
281
            // don't use for loop it generates an iterator which uses 25% of the time for this
282
            // method
283
            final int stop = allVilles.size();
284
            for (int i = 0; i < stop; i++) {
285
                final Ville v = allVilles.get(i);
286
                // both get() took another 25%
287
                final long x = v.getXLambert();
288
                if (x > maxX)
289
                    continue;
290
                if (x < minX)
291
                    continue;
292
                final long y = v.getYLambert();
293
                if (y > maxY)
294
                    continue;
295
                if (y < minY)
296
                    continue;
297
                if (!p.contains(x, y))
298
                    continue;
299
                r.add(v);
300
            }
301
        }
302
        return r;
303
    }
304
 
305
    public static long parsePositiveLong(String str) {
306
        str = str.trim();
307
        long value = 0;
308
        final int stop = str.length();
309
        for (int i = 0; i < stop; i++) {
310
            final char c = str.charAt(i);
311
            if (c == '.') {
312
                break;
313
            }
314
            value *= 10;
315
            value += (c - '0');
316
 
317
        }
318
        return value;
319
    }
320
 
321
    public static synchronized long getMinXLambert() {
322
        final List<Ville> l = getVilles();
156 ilm 323
        if (l.isEmpty()) {
17 ilm 324
            return 0;
325
        }
156 ilm 326
        long min = l.get(0).xLambert;
327
        for (int i = 0; i < l.size(); i++) {
328
            final Ville v = l.get(i);
329
            if (v.xLambert < min) {
330
                min = v.xLambert;
331
            }
332
        }
333
        return min;
17 ilm 334
    }
335
 
336
    static synchronized long getMaxXLambert() {
337
        final List<Ville> l = getVilles();
156 ilm 338
        if (l.isEmpty()) {
17 ilm 339
            return 0;
340
        }
156 ilm 341
        long max = l.get(0).xLambert;
342
        for (int i = 0; i < l.size(); i++) {
343
            final Ville v = l.get(i);
344
            if (v.xLambert > max) {
345
                max = v.xLambert;
346
            }
347
        }
348
        return max;
17 ilm 349
    }
350
 
351
    public static synchronized long getMinYLambert() {
352
        final List<Ville> l = getVilles();
156 ilm 353
        if (l.isEmpty()) {
354
            return 0;
355
        }
17 ilm 356
        long min = l.get(0).yLambert;
357
        for (int i = 0; i < l.size(); i++) {
358
            final Ville v = l.get(i);
359
            if (v.yLambert < min) {
360
                min = v.yLambert;
361
            }
362
        }
363
        return min;
364
    }
365
 
366
    static synchronized long getMaxYLambert() {
367
        final List<Ville> l = getVilles();
156 ilm 368
        if (l.isEmpty()) {
369
            return 0;
370
        }
17 ilm 371
        long max = l.get(0).yLambert;
372
        for (int i = 0; i < l.size(); i++) {
373
            final Ville v = l.get(i);
374
            if (v.yLambert > max) {
375
                max = v.yLambert;
376
            }
377
        }
378
        return max;
379
    }
380
 
381
    // *** instance
61 ilm 382
    // Abbeville:WGS84 (GPS): 50.105467,1.8368330000000697 (N 50° 6' 19.68'',E 1° 50' 12.6'')
383
    // L93: X:616 353,359 Y:7 001 496,893
384
    // NTF: L. II étendue X: 563 846,221 Y: 2 567 930,242
17 ilm 385
    // 800001;Abbeville;0.409874955;0.031997697;80132;23787;900
386
    // --> 4098749550 , 0319976970 // dix chiffres apres la virgules
387
    private final String name;
388
 
389
    private final String codepostal;
390
 
391
    private final long xLambert;
392
 
393
    private final long yLambert;
394
 
395
    long population;
396
 
397
    private Color color = null;
398
 
399
    public String getCodepostal() {
400
        return this.codepostal;
401
    }
402
 
403
    public long getPopulation() {
404
        return this.population;
405
    }
406
 
407
    public long getXLambert() {
408
        return this.xLambert;
409
    }
410
 
411
    public long getYLambert() {
412
        return this.yLambert;
413
    }
414
 
415
    public String getName() {
416
        return this.name;
417
    }
418
 
419
    public String getVilleEtCode() {
420
        return this.name + " (" + this.codepostal + ")";
421
    }
422
 
423
    public Ville(final String name, final long population, final long xLambert, final long yLambert, String codepostal) {
424
        this.name = name;
425
        this.population = population;
426
        this.codepostal = codepostal;
427
        this.xLambert = xLambert;
428
        this.yLambert = yLambert;
429
    }
430
 
431
    @Override
432
    public String toString() {
73 ilm 433
        return this.name + " (" + this.codepostal + ")";
17 ilm 434
    }
435
 
436
    public Color getColor() {
437
        return this.color;
438
    }
439
 
440
    public void setColor(final Color color) {
441
        this.color = color;
442
    }
443
 
444
    public void setNbMatch(int nb) {
445
        this.nbMatch = nb;
446
    }
447
 
448
    public int getNbMatch() {
449
        return this.nbMatch;
450
    }
451
 
452
    /**
453
     * @param args
454
     */
455
    public static void main(final String[] args) {
456
        try {
457
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
458
            final long t1 = System.nanoTime();
459
 
460
            Ville.parseFile();
461
 
462
            final long t2 = System.nanoTime();
463
            System.out.println("Parsing: " + (t2 - t1) / 1000000 + " ms");
464
            System.out.println("MinXLambert:" + getMinXLambert() + ",MinYLambert" + getMinYLambert());
465
            System.out.println("MaxXLambert:" + getMaxXLambert() + ",MinXLambert" + getMaxYLambert());
466
            System.out.println("DeltaX:" + (getMaxXLambert() - getMinXLambert()));
467
            System.out.println("DeltaY:" + (getMaxYLambert() - getMinYLambert()));
468
            final long t3 = System.nanoTime();
469
            System.out.println("Min: " + (t3 - t1) / 1000000 + " ms");
61 ilm 470
            SwingUtilities.invokeLater(new Runnable() {
17 ilm 471
 
61 ilm 472
                @Override
473
                public void run() {
474
                    final JFrame f = new JFrame();
475
                    f.setContentPane(new MapViewerPanel());
476
                    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
477
                    f.setSize(1000, 600);
478
                    f.setVisible(true);
479
                }
480
            });
481
 
17 ilm 482
        } catch (final Exception e) {
483
            e.printStackTrace();
484
        }
485
 
486
    }
487
 
488
    public static synchronized void sortByPopulation() {
489
        sortByPopulation(villes);
490
 
491
    }
492
 
493
    public static synchronized void sortByPopulation(List<Ville> list) {
494
        // Classe de la plus grande ville a la plus petite
495
        Collections.sort(list, new Comparator<Ville>() {
496
            @Override
497
            public int compare(Ville v1, Ville v2) {
498
                return (int) (v2.getPopulation() - v1.getPopulation());
499
            }
500
 
501
        });
502
 
503
    }
61 ilm 504
 
505
    public static void addListener(PropertyChangeListener listener) {
506
        if (!listeners.contains(listener)) {
507
            listeners.add(listener);
508
        }
509
    }
510
 
511
    public static void removeListener(PropertyChangeListener listener) {
512
        listeners.remove(listener);
513
    }
514
 
515
    private static void fireListModified() {
516
        for (PropertyChangeListener l : listeners) {
517
            l.propertyChange(new PropertyChangeEvent(Ville.class, "list", null, null));
518
        }
519
    }
520
 
17 ilm 521
}