~jstys-z/helioviewer.org/client5

« back to all changes in this revision

Viewing changes to api/src/Database/ImgIndex.php

  • Committer: Keith Hughitt
  • Date: 2012-06-04 17:27:01 UTC
  • Revision ID: keith.hughitt@nasa.gov-20120604172701-eo2sj3ylxh4bik4l
Added support for reconnecting to MySQL if the connection fails when querying the db to determine which files are new

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
3
/**
 
4
 * ImgIndex Class definition
 
5
 *
 
6
 * PHP version 5
 
7
 *
 
8
 * @category Database
 
9
 * @package  Helioviewer
 
10
 * @author   Keith Hughitt <keith.hughitt@nasa.gov>
 
11
 * @author   Patrick Schmiedel <patrick.schmiedel@gmx.net>
 
12
 * @license  http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
 
13
 * @link     http://launchpad.net/helioviewer.org
 
14
 */
 
15
/**
 
16
 * Provides methods for interacting with a JPEG 2000 archive.
 
17
 *
 
18
 * @category Database
 
19
 * @package  Helioviewer
 
20
 * @author   Keith Hughitt <keith.hughitt@nasa.gov>
 
21
 * @author   Patrick Schmiedel <patrick.schmiedel@gmx.net>
 
22
 * @license  http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
 
23
 * @link     http://launchpad.net/helioviewer.org
 
24
 */
 
25
class Database_ImgIndex
 
26
{
 
27
    private $_dbConnection;
 
28
 
 
29
    /**
 
30
     * Creates an ImgIndex instance
 
31
     *
 
32
     * @return void
 
33
     */
 
34
    public function __construct()
 
35
    {
 
36
        include_once 'DbConnection.php';
 
37
        $this->_dbConnection = new Database_DbConnection();
 
38
    }
 
39
    
 
40
    /**
 
41
     * Adds a new screenshot entry to the database and returns its identifier
 
42
     * 
 
43
     * @return int identifier for the screenshot
 
44
     */
 
45
    public function insertScreenshot($date, $scale, $roi, $watermark, $layers, $bitmask, $numLayers)
 
46
    {
 
47
        include_once 'src/Helper/DateTimeConversions.php';
 
48
        
 
49
        // Add to screenshots table and get an id
 
50
        $sql = sprintf("INSERT INTO screenshots VALUES(NULL, NULL, '%s', %f, PolygonFromText('%s'), %b, '%s', %d, %d);", 
 
51
            isoDateToMySQL($date),
 
52
            $scale,
 
53
            $roi,
 
54
            $watermark,
 
55
            $layers,
 
56
            bindec($bitmask),
 
57
            $numLayers
 
58
        );
 
59
        
 
60
        $this->_dbConnection->query($sql);
 
61
        
 
62
        return $this->_dbConnection->getInsertId();
 
63
    }
 
64
    
 
65
    /**
 
66
     * Returns a single movie entry
 
67
     * 
 
68
     * @return string The movie information
 
69
     */
 
70
    public function getMovieInformation($id)
 
71
    {
 
72
        $sql = "SELECT *, AsText(regionOfInterest) as roi FROM movies " .
 
73
               "LEFT JOIN movieFormats ON movies.id = movieFormats.movieId " . 
 
74
               "WHERE movies.id=$id AND movieFormats.format='mp4'";
 
75
        return mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
 
76
    }
 
77
 
 
78
    /**
 
79
     * Updates movie entry with new information
 
80
     * 
 
81
     * @return void
 
82
     */
 
83
    public function storeMovieProperties($id, $startDate, $endDate, $numFrames, $frameRate, $length, $width, $height)
 
84
    {
 
85
        // Update movies table
 
86
        $sql = sprintf(
 
87
           "UPDATE movies 
 
88
             SET startDate='%s', endDate='%s', numFrames=%f, frameRate=%f, movieLength=%f, width=%d, height=%d
 
89
             WHERE id=%d",
 
90
           $startDate, $endDate, $numFrames, $frameRate, $length, $width, $height, $id
 
91
        );
 
92
        $this->_dbConnection->query($sql);
 
93
    }
 
94
    
 
95
    /**
 
96
     * Updated movie entry to include processing start and end times
 
97
     */
 
98
    public function finishedBuildingMovieFrames($id, $buildTimeStart, $buildTimeEnd)
 
99
    {
 
100
        $sql = "UPDATE movies SET buildTimeStart='$buildTimeStart', buildTimeEnd='$buildTimeEnd' WHERE id=$id";
 
101
        $this->_dbConnection->query($sql);
 
102
    }
 
103
    
 
104
    /**
 
105
     * Updates movie entry and marks it as "processing"
 
106
     * 
 
107
     * @param $id       int     Movie identifier
 
108
     * @param $format   string  Format being processed
 
109
     * 
 
110
     * @return void
 
111
     */
 
112
    public function markMovieAsProcessing($id, $format)
 
113
    {
 
114
        $sql = "UPDATE movieFormats SET status=1 WHERE movieId=$id AND format='$format'";
 
115
        $this->_dbConnection->query($sql);
 
116
    }
 
117
    
 
118
    /**
 
119
     * Updates movie entry and marks it as being "finished"
 
120
     * 
 
121
     * @param $id       int     Movie identifier
 
122
     * @param $format   string  Format being processed
 
123
     * @param $procTime int     Number of seconds it took to encode the movie
 
124
     */
 
125
    public function markMovieAsFinished($id, $format, $procTime)
 
126
    {
 
127
        $sql = "UPDATE movieFormats SET status=2, procTime=$procTime " . 
 
128
               "WHERE movieId=$id AND format='$format'";
 
129
        $this->_dbConnection->query($sql);
 
130
    }
 
131
    
 
132
    /**
 
133
     * Updates movie entry and marks it as being "finished"
 
134
     */
 
135
    public function markMovieAsInvalid($id)
 
136
    {
 
137
        $this->_dbConnection->query("UPDATE movieFormats SET status=3, procTime=NULL WHERE movieId=$id");
 
138
    }
 
139
    
 
140
    /**
 
141
     * Returns the information associated with the screenshot with the specified id
 
142
     * 
 
143
     * @param $id
 
144
     */
 
145
    public function getScreenshot($id)
 
146
    {
 
147
        $sql = "SELECT * FROM screenshots WHERE id=$id";
 
148
        return mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
 
149
    }
 
150
 
 
151
    /**
 
152
     * Takes an image filepath and returns some useful image information
 
153
     */
 
154
    public function getImageInformation($id) {
 
155
        $sql = "SELECT * FROM images WHERE id=$id;";
 
156
        
 
157
        // Basic image info
 
158
        $image = mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
 
159
        $image['sourceId'] = (int) $image['sourceId'];
 
160
        
 
161
        // Image header
 
162
        $file = HV_JP2_DIR . $image["filepath"] . "/" .$image["filename"];
 
163
        $xmlBox = $this->extractJP2MetaInfo($file);
 
164
        
 
165
        // Datasource info
 
166
        $datasource = $this->getDatasourceInformationFromSourceId($image['sourceId']);
 
167
        
 
168
        return array_merge($image, $xmlBox, $datasource);
 
169
    }
 
170
 
 
171
    /**
 
172
     * Finds the closest available image to the requested one, and returns information from
 
173
     * database and XML box.
 
174
     *
 
175
     * @param string $date     A UTC date string of the form "2003-10-05T00:00:00Z."
 
176
     * @param int    $sourceId An identifier specifying the image type or source requested.
 
177
     *
 
178
     * @return array Information about the image match including it's location, time, scale, and dimensions.
 
179
     */
 
180
    public function getClosestImage($date, $sourceId)
 
181
    {
 
182
        $img      = $this->getImageFromDatabase($date, $sourceId);
 
183
        $filename = HV_JP2_DIR . $img["filepath"] . "/" .$img["filename"];
 
184
        $xmlBox   = $this->extractJP2MetaInfo($filename);
 
185
 
 
186
        return array_merge($img, $xmlBox);
 
187
    }
 
188
 
 
189
    /**
 
190
     * Queries database and finds the best matching image.
 
191
     *
 
192
     * @param string $date     A UTC date string of the form "2003-10-05T00:00:00Z."
 
193
     * @param int    $sourceId An identifier specifying the image type or source requested.
 
194
     *
 
195
     * @return array Array including the image id, filepath, filename, date, and sourceId.
 
196
     */
 
197
    public function getImageFromDatabase($date, $sourceId)
 
198
    {
 
199
        include_once 'src/Helper/DateTimeConversions.php';
 
200
 
 
201
        $datestr = isoDateToMySQL($date);
 
202
 
 
203
        $sql = sprintf(
 
204
            "( SELECT id, filepath, filename, date 
 
205
              FROM images 
 
206
              WHERE
 
207
                sourceId = %d AND 
 
208
                date < '%s'
 
209
              ORDER BY date DESC LIMIT 1 )
 
210
            UNION ALL
 
211
            ( SELECT id, filepath, filename, date
 
212
              FROM images
 
213
              WHERE
 
214
                sourceId = %d AND
 
215
                date >= '%s'
 
216
              ORDER BY date ASC LIMIT 1 )
 
217
            ORDER BY ABS(TIMESTAMPDIFF(MICROSECOND, date, '%s')
 
218
            ) LIMIT 1;",
 
219
            $sourceId, $datestr, $sourceId, $datestr, $datestr
 
220
        );
 
221
        
 
222
        // Query database
 
223
        $result = mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
 
224
 
 
225
        // Make sure match was found
 
226
        if (is_null($result)) {
 
227
            $source = $this->_getDataSourceName($sourceId);
 
228
            throw new Exception("No images of the requested type ($source) are currently available.");
 
229
        }
 
230
        
 
231
        // Cast id to integer
 
232
        $result['id'] = (int) $result['id'];
 
233
 
 
234
        return $result;
 
235
    }
 
236
    
 
237
    /**
 
238
     * Queries the database and returns the closest image match before or equal to the date specified 
 
239
     *
 
240
     * @param string $date     A UTC date string of the form "2003-10-05T00:00:00Z."
 
241
     * @param int    $sourceId An identifier specifying the image type or source requested.
 
242
     *
 
243
     * @return array Array including the image id, filepath, filename, date, and sourceId.
 
244
     */
 
245
    public function getClosestImageBeforeDate($date, $sourceId)
 
246
    {
 
247
        include_once 'src/Helper/DateTimeConversions.php';
 
248
 
 
249
        $datestr = isoDateToMySQL($date);
 
250
 
 
251
        // Search database
 
252
        $sql = sprintf("SELECT filepath, filename, date FROM images WHERE sourceId = %d AND date <= '%s' ORDER BY date DESC LIMIT 1;", $sourceId, $datestr);
 
253
        $img = mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
 
254
 
 
255
        // Make sure match was founds
 
256
        if (is_null($img)) {
 
257
            $source = $this->_getDataSourceName($sourceId);
 
258
            throw new Exception("No $source images are available on or before $date.");
 
259
        }
 
260
 
 
261
        return $img;
 
262
    }
 
263
    
 
264
    /**
 
265
     * Queries the database and returns the closest image match after or equal to the date specified 
 
266
     *
 
267
     * @param string $date     A UTC date string of the form "2003-10-05T00:00:00Z."
 
268
     * @param int    $sourceId An identifier specifying the image type or source requested.
 
269
     *
 
270
     * @return array Array including the image id, filepath, filename, date, and sourceId.
 
271
     */
 
272
    public function getClosestImageAfterDate ($date, $sourceId)
 
273
    {
 
274
        include_once 'src/Helper/DateTimeConversions.php';
 
275
 
 
276
        $datestr = isoDateToMySQL($date);
 
277
 
 
278
        // Search database
 
279
        $sql = sprintf("SELECT filepath, filename, date FROM images WHERE sourceId = %d AND date >= '%s' ORDER BY date ASC LIMIT 1;", $sourceId, $datestr);
 
280
        $img = mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
 
281
 
 
282
        // Make sure match was found
 
283
        if (is_null($img)) {
 
284
            $source = $this->_getDataSourceName($sourceId);
 
285
            throw new Exception("No $source images are available on or after $date.");
 
286
        }
 
287
 
 
288
        return $img;
 
289
    }
 
290
    
 
291
    /**
 
292
     * Gets the human-readable name associated with the specified source id
 
293
     *
 
294
     * @param int $sourceId An identifier specifying the image type or source requested.
 
295
     * 
 
296
     * @return string Name of the data source associated with specified id
 
297
     */
 
298
    private function _getDataSourceName ($sourceId)
 
299
    {
 
300
        $sql = "SELECT name FROM datasources WHERE id=$sourceId";
 
301
        $result = mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
 
302
        return $result["name"];
 
303
    }
 
304
 
 
305
    /**
 
306
     * Returns the number of images in the database for a given source and time range
 
307
     *
 
308
     * @param datetime $start    Query start time
 
309
     * @param datetime $end      Query end time
 
310
     * @param int      $sourceId The sourceId to query
 
311
     *
 
312
     * @return int The number of images in the database within the specified constraints
 
313
     */
 
314
    public function getImageCount($start, $end, $sourceId)
 
315
    {
 
316
        include_once 'src/Helper/DateTimeConversions.php';
 
317
        $startDate = isoDateToMySQL($start);
 
318
        $endDate   = isoDateToMySQL($end);
 
319
        
 
320
        $sql = "SELECT COUNT(*) FROM images WHERE sourceId=$sourceId AND date BETWEEN '$startDate' AND '$endDate'";
 
321
        
 
322
        $result = mysqli_fetch_array($this->_dbConnection->query($sql));
 
323
        return (int) $result[0];
 
324
    }
 
325
 
 
326
    /**
 
327
     * Returns an array containing all images for a given source and time range
 
328
     *
 
329
     * @param datetime $start    Query start time
 
330
     * @param datetime $end      Query end time
 
331
     * @param int      $sourceId The sourceId to query
 
332
     *
 
333
     * @return int The number of images in the database within the specified constraints
 
334
     */
 
335
    public function getImageRange($start, $end, $sourceId)
 
336
    {
 
337
        include_once 'src/Helper/DateTimeConversions.php';
 
338
        $startDate = isoDateToMySQL($start);
 
339
        $endDate   = isoDateToMySQL($end);
 
340
 
 
341
        $images = array();
 
342
        $sql = "SELECT * FROM images 
 
343
                WHERE sourceId=$sourceId AND date BETWEEN '$startDate' AND '$endDate' ORDER BY date ASC";
 
344
 
 
345
        $result = $this->_dbConnection->query($sql);
 
346
 
 
347
        while ($image = $result->fetch_array(MYSQL_ASSOC)) {
 
348
            array_push($images, $image);
 
349
        }
 
350
        return $images;
 
351
    }
 
352
 
 
353
    /**
 
354
     * Extract necessary meta-information from an image
 
355
     *
 
356
     * @param string $img Location of a JP2 image.
 
357
     *
 
358
     * @return array A subset of the information stored in the jp2 header
 
359
     */
 
360
    public function extractJP2MetaInfo ($img)
 
361
    {
 
362
        include_once "src/Image/JPEG2000/JP2ImageXMLBox.php";
 
363
 
 
364
        try {
 
365
            $xmlBox = new Image_JPEG2000_JP2ImageXMLBox($img);
 
366
 
 
367
            $dimensions = $xmlBox->getImageDimensions();
 
368
            $center     = $xmlBox->getSunCenter();
 
369
            $imageScale = (float) $xmlBox->getImagePlateScale();
 
370
            $dsun       = (float) $xmlBox->getDSun();
 
371
            
 
372
            // Normalize image scale
 
373
            $imageScale = $imageScale * ($dsun / HV_CONSTANT_AU);
 
374
 
 
375
            $meta = array(
 
376
                "scale"      => $imageScale,
 
377
                "width"      => (int) $dimensions[0],
 
378
                "height"     => (int) $dimensions[1],
 
379
                "sunCenterX" => (float) $center[0],
 
380
                "sunCenterY" => (float) $center[1]
 
381
            );
 
382
        } catch (Exception $e) {
 
383
            throw new Exception(sprintf("Unable to process XML Header for %s: %s", $img, $e->getMessage()));
 
384
        }
 
385
 
 
386
        return $meta;
 
387
    }
 
388
 
 
389
    /**
 
390
     * Takes in a source id and returns the corresponding 
 
391
     * observatory, instrument, detector, measurement, and
 
392
     * layeringOrder information.
 
393
     * 
 
394
     * @param {int} $id Source Id
 
395
     * 
 
396
     * @return {Array} $result_array  Contains values for 
 
397
     * "observatory", "instrument", "detector", "measurement", 
 
398
     * and "layeringOrder"
 
399
     */
 
400
    public function getDatasourceInformationFromSourceId ($id)
 
401
    {
 
402
        $sql = sprintf(
 
403
            "SELECT
 
404
                observatories.name AS observatory,
 
405
                instruments.name AS instrument,
 
406
                detectors.name AS detector,
 
407
                measurements.name AS measurement,
 
408
                datasources.name AS name,
 
409
                datasources.layeringOrder AS layeringOrder
 
410
            FROM datasources
 
411
                LEFT JOIN observatories ON datasources.observatoryId = observatories.id
 
412
                LEFT JOIN instruments ON datasources.instrumentId = instruments.id
 
413
                LEFT JOIN detectors ON datasources.detectorId = detectors.id
 
414
                LEFT JOIN measurements ON datasources.measurementId = measurements.id
 
415
            WHERE
 
416
                datasources.id='%s'",
 
417
            mysqli_real_escape_string($this->_dbConnection->link, $id)
 
418
        );
 
419
 
 
420
        $result = $this->_dbConnection->query($sql);
 
421
        $result_array = mysqli_fetch_array($result, MYSQL_ASSOC);
 
422
 
 
423
        return $result_array;           
 
424
    }
 
425
 
 
426
    /**
 
427
     * Returns the source Id, name, and layering order associated with a data source specified by 
 
428
     * it's observatory, instrument, detector and measurement.
 
429
     * 
 
430
     * @param string $obs  Observatory
 
431
     * @param string $inst Instrument
 
432
     * @param string $det  Detector
 
433
     * @param string $meas Measurement
 
434
     * 
 
435
     * @return array Datasource id and layering order
 
436
     */
 
437
    public function getDatasourceInformationFromNames($obs, $inst, $det, $meas)
 
438
    {
 
439
        $sql = sprintf(
 
440
            "SELECT
 
441
                datasources.id AS id,
 
442
                datasources.name AS name,
 
443
                datasources.layeringOrder AS layeringOrder
 
444
            FROM datasources
 
445
                LEFT JOIN observatories ON datasources.observatoryId = observatories.id
 
446
                LEFT JOIN instruments ON datasources.instrumentId = instruments.id
 
447
                LEFT JOIN detectors ON datasources.detectorId = detectors.id
 
448
                LEFT JOIN measurements ON datasources.measurementId = measurements.id
 
449
            WHERE
 
450
                observatories.name='%s' AND
 
451
                instruments.name='%s' AND
 
452
                detectors.name='%s' AND
 
453
                measurements.name='%s';",
 
454
            mysqli_real_escape_string($this->_dbConnection->link, $obs),
 
455
            mysqli_real_escape_string($this->_dbConnection->link, $inst),
 
456
            mysqli_real_escape_string($this->_dbConnection->link, $det),
 
457
            mysqli_real_escape_string($this->_dbConnection->link, $meas)
 
458
        );
 
459
        $result = $this->_dbConnection->query($sql);
 
460
        $result_array = mysqli_fetch_array($result, MYSQL_ASSOC);
 
461
 
 
462
        return $result_array;
 
463
    }
 
464
    
 
465
    /**
 
466
     * Returns the sourceId for a given set of parameters.
 
467
     *
 
468
     * @param string $obs  Observatory
 
469
     * @param string $inst Instrument
 
470
     * @param string $det  Detector
 
471
     * @param string $meas Measurement
 
472
     *
 
473
     * @return int The matched sourceId.
 
474
     */
 
475
    public function getSourceId ($obs, $inst, $det, $meas)
 
476
    {
 
477
        $sql = sprintf(
 
478
            "SELECT
 
479
                datasources.id
 
480
            FROM datasources
 
481
                LEFT JOIN observatories ON datasources.observatoryId = observatories.id
 
482
                LEFT JOIN instruments ON datasources.instrumentId = instruments.id
 
483
                LEFT JOIN detectors ON datasources.detectorId = detectors.id
 
484
                LEFT JOIN measurements ON datasources.measurementId = measurements.id
 
485
            WHERE
 
486
                observatories.name='%s' AND
 
487
                instruments.name='%s' AND
 
488
                detectors.name='%s' AND
 
489
                measurements.name='%s';",
 
490
            mysqli_real_escape_string($this->_dbConnection->link, $obs),
 
491
            mysqli_real_escape_string($this->_dbConnection->link, $inst),
 
492
            mysqli_real_escape_string($this->_dbConnection->link, $det),
 
493
            mysqli_real_escape_string($this->_dbConnection->link, $meas)
 
494
        );
 
495
        $result = $this->_dbConnection->query($sql);
 
496
        $result_array = mysqli_fetch_array($result, MYSQL_ASSOC);
 
497
 
 
498
        return (int) ($result_array["id"]);
 
499
    }
 
500
    
 
501
    /**
 
502
     * Returns the oldest image for a given datasource
 
503
     */
 
504
    public function getOldestImage($sourceId)
 
505
    {
 
506
        $sql = "SELECT date FROM images WHERE sourceId=$sourceId ORDER BY date ASC LIMIT 1";
 
507
        $result = mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);           
 
508
        return $result['date'];
 
509
    }
 
510
    
 
511
    /**
 
512
     * Returns the newest image for a given datasource
 
513
     */
 
514
    public function getNewestImage($sourceId)
 
515
    {
 
516
        $sql = "SELECT date FROM images WHERE sourceId=$sourceId ORDER BY date DESC LIMIT 1";
 
517
        $result = mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);        
 
518
        return $result['date'];
 
519
    }
 
520
    
 
521
    /**
 
522
     * Returns a list of datasources sorted by instrument
 
523
     * 
 
524
     * @return array A list of datasources sorted by instrument
 
525
     */
 
526
    public function getDataSourcesByInstrument ()
 
527
    {
 
528
        // 2011/05/24: Hiding TRACE for now
 
529
        $result = $this->_dbConnection->query("SELECT * FROM instruments WHERE name != 'TRACE' ORDER BY name");
 
530
        
 
531
        $instruments = array();
 
532
 
 
533
        while($instrument = mysqli_fetch_assoc($result)) {
 
534
            $instruments[$instrument['name']] = array();
 
535
            $sql = sprintf("SELECT * FROM datasources WHERE instrumentId=%d ORDER BY name", $instrument['id']);
 
536
            $datasources = $this->_dbConnection->query($sql);
 
537
            while($ds = mysqli_fetch_assoc($datasources)) {
 
538
                array_push($instruments[$instrument['name']], $ds);
 
539
            }
 
540
        }
 
541
        
 
542
        return $instruments;
 
543
    }
 
544
 
 
545
    /**
 
546
     * Returns a list of the known data sources
 
547
     * 
 
548
     * @param bool $verbose If set to true an alternative data structure is returned that includes meta-information
 
549
     *                      at each level of the tree, and adds units to numeric measurement names
 
550
     *
 
551
     * @return array A tree representation of the known data sources
 
552
     */
 
553
    public function getDataSources ($verbose)
 
554
    {
 
555
        $fields = array("instrument", "detector", "measurement");
 
556
        
 
557
        $sql = "SELECT
 
558
                    datasources.name as nickname,
 
559
                    datasources.id as id,
 
560
                    datasources.enabled as enabled,
 
561
                    datasources.layeringOrder as layeringOrder,
 
562
                    measurements.units as measurement_units,
 
563
                    observatories.name as observatory_name,
 
564
                    observatories.description as observatory_description, ";
 
565
 
 
566
        foreach ($fields as $field) {
 
567
            $sql .= sprintf("%ss.name as %s_name, %ss.description as %s_description,", $field, $field, $field, $field);
 
568
        }
 
569
     
 
570
        $sql = substr($sql, 0, -1) . " " . 
 
571
            "FROM datasources
 
572
                LEFT JOIN observatories ON datasources.observatoryId = observatories.id
 
573
                LEFT JOIN instruments ON datasources.instrumentId = instruments.id
 
574
                LEFT JOIN detectors ON datasources.detectorId = detectors.id
 
575
                LEFT JOIN measurements ON datasources.measurementId = measurements.id;";
 
576
                
 
577
        // 2011/06/10 Temporarily hiding STEREO from verbose output (used by
 
578
        // JHelioviewer.) Will remove when JHelioviewer adds support.
 
579
        
 
580
        // 2012/05/26 Same thing with SWAP
 
581
        if ($verbose) {
 
582
            $sql = substr($sql, 0, -1) . " " . 'WHERE observatories.name NOT IN ("STEREO_A", "STEREO_B", "PROBA2");';
 
583
        }
 
584
        
 
585
        // Use UTF-8 for responses
 
586
        $this->_dbConnection->setEncoding('utf8');
 
587
 
 
588
        // Fetch available data-sources
 
589
        $result = $this->_dbConnection->query($sql);
 
590
 
 
591
        $sources = array();
 
592
 
 
593
        while ($row = $result->fetch_array(MYSQL_ASSOC)) {
 
594
            array_push($sources, $row);
 
595
        }
 
596
 
 
597
        // Convert results into a more easily traversable tree structure
 
598
        $tree = array();
 
599
 
 
600
        foreach ($sources as $source) {
 
601
            
 
602
            $enabled = (bool) $source["enabled"];
 
603
 
 
604
            // Only include if data is available for the specified source
 
605
            if (!$enabled) {
 
606
                continue;
 
607
            }
 
608
             
 
609
            // Image parameters
 
610
            $id       = (int) ($source["id"]);
 
611
            $obs      = $source["observatory_name"];
 
612
            $inst     = $source["instrument_name"];
 
613
            $det      = $source["detector_name"];
 
614
            $meas     = $source["measurement_name"];
 
615
            $nickname = $source["nickname"];
 
616
            $order    = (int) ($source["layeringOrder"]);
 
617
            
 
618
            // Availability
 
619
            $oldest = $this->getOldestImage($id);
 
620
            $newest = $this->getNewestImage($id);
 
621
 
 
622
            // Build tree
 
623
            if (!$verbose) {
 
624
                // Normal
 
625
                if (!isset($tree[$obs])) {
 
626
                    $tree[$obs] = array();
 
627
                }
 
628
                if (!isset($tree[$obs][$inst])) {
 
629
                    $tree[$obs][$inst] = array();
 
630
                }
 
631
                if (!isset($tree[$obs][$inst][$det])) {
 
632
                    $tree[$obs][$inst][$det] = array();
 
633
                }
 
634
                $tree[$obs][$inst][$det][$meas] = array(
 
635
                    "sourceId"      => $id,
 
636
                    "nickname"      => $nickname,
 
637
                    "layeringOrder" => $order,
 
638
                    "start"         => $oldest,
 
639
                    "end"           => $newest
 
640
                );
 
641
            } else {
 
642
                // Alternative measurement descriptors
 
643
                if (preg_match("/^\d*$/", $meas)) {
 
644
                    // \u205f = \xE2\x81\x9F = MEDIUM MATHEMATICAL SPACE
 
645
                    $measurementName = $meas . "\xE2\x81\x9F" . $source["measurement_units"];
 
646
                } else {
 
647
                    $measurementName = ucwords(str_replace("-", " ", $meas));
 
648
                }
 
649
               
 
650
             
 
651
                // Verbose
 
652
                if (!isset($tree[$obs])) {
 
653
                    $tree[$obs] = array(
 
654
                        "name"        => $obs,
 
655
                        "description" => $source["observatory_description"],
 
656
                        "children" => array()
 
657
                    );
 
658
                }
 
659
                if (!isset($tree[$obs]["children"][$inst])) {
 
660
                    $tree[$obs]["children"][$inst] = array(
 
661
                        "name"        => $inst,
 
662
                        "description" => $source["instrument_description"],
 
663
                        "children"   => array()
 
664
                    );
 
665
                }
 
666
                if (!isset($tree[$obs]["children"][$inst]["children"][$det])) {
 
667
                    $tree[$obs]["children"][$inst]["children"][$det] = array(
 
668
                        "name"        => $det,
 
669
                        "description" => $source["detector_description"],
 
670
                        "children" => array()
 
671
                    );
 
672
                }
 
673
                $tree[$obs]["children"][$inst]["children"][$det]["children"][$meas] = array(
 
674
                    "name"          => $measurementName,
 
675
                    "description"   => $source["measurement_description"],
 
676
                    "nickname"      => $nickname,
 
677
                    "sourceId"      => $id,
 
678
                    "layeringOrder" => $order,
 
679
                    "start"         => $oldest,
 
680
                    "end"           => $newest
 
681
                );
 
682
            }
 
683
        }
 
684
        
 
685
        // Set defaults for verbose mode
 
686
        if ($verbose) {
 
687
            $tree["SDO"]["default"] = true;
 
688
            $tree["SDO"]["children"]["AIA"]["default"] = true;
 
689
            $tree["SDO"]["children"]["AIA"]["children"]["AIA"]["default"] = true;
 
690
            $tree["SDO"]["children"]["AIA"]["children"]["AIA"]["children"]["171"]["default"] = true;
 
691
        }
 
692
 
 
693
        return $tree;
 
694
    }
 
695
 
 
696
    /**
 
697
     * Finds the closest match for a requested image and returns it's location
 
698
     *
 
699
     * @param string $date     A UTC date string of the form "2003-10-05T00:00:00Z."
 
700
     * @param int    $sourceId An identifier specifying the image type or source requested.
 
701
     *
 
702
     * @return string Local filepath for the JP2 image.
 
703
     *
 
704
     */
 
705
    public function getJP2FilePath($date, $sourceId)
 
706
    {
 
707
        $img = $this->getImageFromDatabase($date, $sourceId);
 
708
        return $img["filepath"] . "/" . $img["filename"];
 
709
    }
 
710
    
 
711
    /**
 
712
     * Returns the filepath for the image with the specified id
 
713
     * 
 
714
     * @param int $id Image id
 
715
     * 
 
716
     * @return string Local filepath for the JP2 image
 
717
     */
 
718
    public function getJP2FilePathFromId($id)
 
719
    {
 
720
        $sql = "SELECT concat(filepath, '/', filename) FROM images WHERE id=$id";
 
721
        $row = mysqli_fetch_array($this->_dbConnection->query($sql));
 
722
        return array_pop($row);
 
723
    }
 
724
}
 
725
?>