1 <?php
  2 /**
  3  * DokuWiki Plugin terramystica (Syntax Component)
  4  *
  5  * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
  6  * @author  Oguz Han Asnaz <wiki@lostgeek.de>
  7  */
  8 
  9 // must be run within Dokuwiki
 10 if (!defined('DOKU_INC')) die();
 11 
 12 class syntax_plugin_terramystica_ranking extends DokuWiki_Syntax_Plugin {
 13     private $fgcolors = array(
 14         'red' => '#000',
 15         'green' => '#000',
 16         'yellow' => '#000',
 17         'blue' => '#000',
 18         'black' => '#c0c0c0',
 19         'white' => '#000',
 20         'gray' => '#000',
 21         'brown' => '#000',
 22         'ice' => '#000',
 23         'volcano' => '#000',
 24         'player' => '#000'
 25     );
 26 
 27     private $bgcolors = array(
 28         'red' => '#f08080',
 29         'green' => '#80f080',
 30         'yellow' => '#f0f080',
 31         'blue' => '#60c0f0',
 32         'black' => '#404040',
 33         'white' => '#ffffff',
 34         'gray' => '#c0c0c0',
 35         'brown' => '#b08040',
 36         'ice' => '#e0f0ff',
 37         'volcano' => '#f0c060',
 38         'player' => '#404040'
 39     );
 40     /**
 41      * @return string Syntax mode type
 42      */
 43     public function getType() {
 44         return 'substition';
 45     }
 46     /**
 47      * @return string Paragraph type
 48      */
 49     public function getPType() {
 50         return 'block';
 51     }
 52     /**
 53      * @return int Sort order - Low numbers go before high numbers
 54      */
 55     public function getSort() {
 56         return 1;
 57     }
 58 
 59     /**
 60      * Connect lookup pattern to lexer.
 61      *
 62      * @param string $mode Parser mode
 63      */
 64     public function connectTo($mode) {
 65         $this->Lexer->addSpecialPattern('<TMranking.*?>',$mode,'plugin_terramystica_ranking');
 66     }
 67 
 68     public function postConnect() {
 69     }
 70 
 71     /**
 72      * Handle matches of the terramystica syntax
 73      *
 74      * @param string $match The match of the syntax
 75      * @param int    $state The state of the handler
 76      * @param int    $pos The position in the document
 77      * @param Doku_Handler    $handler The handler
 78      * @return array Data for the renderer
 79      */
 80     public function handle($match, $state, $pos, &$handler){
 81         if($state != DOKU_LEXER_SPECIAL) return array(2,3);
 82 
 83         return array($match, 3);
 84     }
 85 
 86     /**
 87      * Render xhtml output or metadata
 88      *
 89      * @param string         $mode      Renderer mode (supported modes: xhtml)
 90      * @param Doku_Renderer  $renderer  The renderer
 91      * @param array          $data      The data from the handler() function
 92      * @return bool If rendering was successful.
 93      */
 94     public function render($mode, &$renderer, $data) {
 95         if($mode != 'xhtml') return false;
 96         $games = explode(" ", substr($data[0], 11, -1));
 97 
 98         $standing = array();
 99 
100         $code = "";
101 
102         foreach ($games as $game) {
103 
104             $jsonData = $this->loadGame($game);
105             list($finished, $gameRanking) = $this->parseGame($jsonData);
106             $playerN = count($gameRanking);
107 
108         curl_setopt($curlSession, CURLOPT_URL, 'http://terra.snellman.net/app/view-game/?game='.$name);
109             $code .= '^  [[http://terra.snellman.net/game/'.$renderer->_xmlEntities($game).'|'.$renderer->_xmlEntities($game).']] ';
110             if(!$finished)
111                 $code .= '(running)';
112             $code .= '  ^^^'.PHP_EOL;
113 
114             $points = array(0, 0, 1, 3, 6);
115             $i = 0;
116 
117             while( $i < $playerN ) {
118                 $j = $i;
119                 while( $j < $playerN ) {
120                     if( $gameRanking[$j]["VP"] == $gameRanking[$i]["VP"] )
121                         $j++;
122                     else
123                         break;
124                 }
125                 $place = $i+1;
126                 $p = 0;
127                 for($k = 0; $k < $j-$i; $k++)
128                     $p += array_pop($points)/($j-$i);
129 
130                 while($i < $j) {
131                     $name = $gameRanking[$i]["name"];
132                     $faction = $gameRanking[$i]["faction"];
133 
134                     $standing[$name]["points"] += $p;
135                     if($standing[$name]["placings"] == NULL) $standing[$name]["placings"] = array();
136                     array_push($standing[$name]["placings"], $place);
137 
138                     $factionColor = $jsonData["factions"][$faction]["color"];
139                     $fgC = $this->fgcolors[$factionColor];
140                     $bgC = $this->bgcolors[$factionColor];
141                     $code .= '| '.$gameRanking[$i]["name"].' | <color '.$fgC.'/'.$bgC.'>'.$gameRanking[$i]["faction"].'</color> | '.$gameRanking[$i]["VP"].' |'.PHP_EOL;
142 
143                     $standing[$name]["factions"] .= '<color '.$fgC.'/'.$bgC.'>'.strtoupper(substr($faction, 0, 1)).'</color>';
144 
145                     $i++;
146                 }
147             }
148 
149         }
150         $code .= PHP_EOL;
151         $code .= '^  Endresultat aus '.sizeof($games).' Spielen  ^^^^^^^^^'.PHP_EOL;
152         $code .= '^  Platz  ^  Name  ^  Völker  ^  Platzierungen  ^^^^^  Punkte  ^'.PHP_EOL;
153         $code .= '^ ::: ^ ::: ^ ::: ^  1.  ^  2.  ^  3.  ^  4.  ^  5.  ^ ::: ^'.PHP_EOL;
154 
155         arsort($standing);
156 
157         $i = 1;
158         foreach( $standing as $name => $v ) {
159             $p = array_count_values($v["placings"]);
160             $placings = $p[1].' | '.$p[2].' | '.$p[3].' | '.$p[4].' | '.$p[5];
161 
162             $code .= '| '.$i++.'.  | '.$name.' | '.$v["factions"].'  | '.$placings.'  | '.$v["points"].'  |'.PHP_EOL;
163         }
164 
165 
166         $code = p_render('xhtml',p_get_instructions($code),$info);
167         $renderer->doc .= $code;
168 
169         return true;
170     }
171 
172 
173     private function loadGame($name) {
174         $cachedGames = p_get_metadata('tmranking', 'cachedgames');
175         list($finished, $lastLoaded) = $cachedGames[$name];
176 
177         if($finished || time() - $lastLoaded < 10*60) { // Todo: Settings for Cache time
178             $jsonData = json_decode(file_get_contents($DOKU_INC.'data/terramystica/'.$name),true);
179             return $jsonData;
180         }
181 
182         $curlSession = curl_init();
183         curl_setopt($curlSession, CURLOPT_URL, 'http://terra.snellman.net/app/view-game/?game='.$name);
184         //curl_setopt($curlSession, CURLOPT_URL, 'http://localhost/'.$name);
185         curl_setopt($curlSession, CURLOPT_BINARYTRANSFER, true);
186         curl_setopt($curlSession, CURLOPT_RETURNTRANSFER, true);
187 
188         $jsonData = json_decode(curl_exec($curlSession), true);
189         curl_close($curlSession);
190 
191         $cachedGames[$name] = array($jsonData["metadata"]["finished"], time());
192 
193         p_set_metadata('tmranking', array('cachedgames'=>$cachedGames));
194 
195         if(!is_dir($DOKU_INC.'data/terramystica'))
196             mkdir($DOKU_INC.'data/terramystica');
197         file_put_contents($DOKU_INC.'data/terramystica/'.$name, json_encode($jsonData));
198 
199         return $jsonData;
200     }
201 
202     private function parseGame($data) {
203         $ranking = array();
204 
205         // Read JSON
206         $finished = $data["metadata"]["finished"];
207 
208         foreach($data["factions"] as $k=>$v) {
209             $vp = 0;
210             if($finished)
211                 $vp = $v["VP"];
212             else
213                 $vp = $v["vp_projection"]["total"];
214             array_push($ranking, array("name"=>$v["username"], "faction"=>$k, "VP"=>$vp));
215         }
216 
217         // Sort by VP
218         usort($ranking, function($a, $b){return $a["VP"]<$b["VP"];} );
219 
220         return array($finished, $ranking);
221     }
222 }
223 
224 // vim:ts=4:sw=4:et: