1<?php
2
3use dokuwiki\Extension\SyntaxPlugin;
4use dokuwiki\HTTP\DokuHTTPClient;
5
6/**
7 * DokuWiki Plugin pegel (Syntax Component)
8 *
9 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
10 * @author Andreas Gohr <dokuwiki@cosmocode.de>
11 */
12class syntax_plugin_pegel extends SyntaxPlugin
13{
14    public const API_URL = 'https://www.pegelonline.wsv.de/webservices/rest-api/v2';
15
16    protected $apiResults = [];
17
18    /** @inheritDoc */
19    public function getType()
20    {
21        return 'substition';
22    }
23
24    /** @inheritDoc */
25    public function getPType()
26    {
27        return 'normal';
28    }
29
30    /** @inheritDoc */
31    public function getSort()
32    {
33        return 155;
34    }
35
36    /** @inheritDoc */
37    public function connectTo($mode)
38    {
39        $this->Lexer->addSpecialPattern('<pegel .*?>', $mode, 'plugin_pegel');
40    }
41
42    /** @inheritDoc */
43    public function handle($match, $state, $pos, Doku_Handler $handler)
44    {
45        $match = substr($match, 7, -1);
46        [$uuid, $type] = sexplode(' ', $match, 2);
47        $uuid = trim($uuid);
48        $type = trim($type);
49        if (!$type) $type = 'v';
50
51        return [
52            'uuid' => $uuid,
53            'type' => $type,
54        ];
55    }
56
57    /** @inheritDoc */
58    public function render($mode, Doku_Renderer $renderer, $data)
59    {
60        if ($mode === 'metadata') {
61            return false;
62        }
63        // for everything else we simply use cdata()
64
65        try {
66            $pegel = $this->callAPI($data['uuid']);
67
68            $station = $pegel[0]['stations'][0];
69            $current = $station['timeseries'][0];
70
71            switch ($data['type']) {
72                case 'v':
73                    $text = $current['currentMeasurement']['value'] . $current['unit'];
74                    break;
75                case 'dt':
76                    $text = (new DateTime($current['currentMeasurement']['timestamp']))->format($this->getConf('dt'));
77                    break;
78                case 't':
79                    $text = (new DateTime($current['currentMeasurement']['timestamp']))->format($this->getConf('t'));
80                    break;
81                case 'd':
82                    $text = (new DateTime($current['currentMeasurement']['timestamp']))->format($this->getConf('d'));
83                    break;
84                default:
85                    $text = $station[$data['type']] ?? 'unknown type';
86            }
87        } catch (Exception $e) {
88            $text = 'Error: ' . $e->getMessage();
89        }
90
91        $renderer->cdata($text);
92        return true;
93    }
94
95    /**
96     * Fetch the data from the API
97     *
98     * @param string $uuid
99     * @return mixed
100     * @throws Exception
101     */
102    protected function callAPI($uuid)
103    {
104        if (isset($this->apiResults[$uuid])) return $this->apiResults[$uuid]; // only one call per request
105
106        $url = self::API_URL . '/waters.json?' . http_build_query(
107                [
108                    'stations' => $uuid,
109                    'includeTimeseries' => 'true',
110                    'includeCurrentMeasurement' => 'true',
111                    'includeStations' => 'true',
112                ],
113                '', '&'
114            );
115
116
117        $http = new DokuHTTPClient();
118        $ok = $http->sendRequest($url);
119        if ($ok === false) {
120            return throw new Exception('API request failed ' . $http->error, $http->status);
121        }
122
123        $data = json_decode($http->resp_body, true);
124        $this->apiResults[$uuid] = $data;
125        return $data;
126    }
127}
128