1<?php 2 3// must be run within Dokuwiki 4if (!defined('DOKU_INC')) die(); 5 6class helper_plugin_schulzevote extends DokuWiki_Plugin { 7 8 function __construct() { 9 global $ID; 10 $data = p_get_metadata($ID, 'schulzevote'); 11 $this->candys = $data['candys']; 12 $this->votes = array(); 13 $this->outdated = false; 14 if (isset($data['outdated'])) { 15 $this->outdated = $data['outdated']; 16 } 17 if (!isset($data['votes'])) { 18 // did not find any votes list ; must be an old vote 19 if (isset($data['prefer']) && isset($data['votees'])) { 20 $this->updatePoll($data); 21 } 22 } 23 else { 24 $this->votes = $data['votes']; 25 } 26 27/* Ambiguous, but B > C and D > A 28 $prefer = array( 29'A' => array('A' => 0, 'B' => 5, 'C' => 5, 'D' => 3), 30'B' => array('A' => 4, 'B' => 0, 'C' => 7, 'D' => 5), 31'C' => array('A' => 4, 'B' => 2, 'C' => 0, 'D' => 5), 32'D' => array('A' => 6, 'B' => 4, 'C' => 4, 'D' => 0), 33); 34 $this->candys = array( 35'A' => 'A', 36'B' => 'B', 37'C' => 'C', 38'D' => 'D', 39); 40*/ 41 42/* E > A > C > B > D 43 $prefer = array( 44'A' => array('A' => 0, 'B' => 20, 'C' => 26, 'D' => 30, 'E' => 22), 45'B' => array('A' => 25, 'B' => 0, 'C' => 16, 'D' => 33, 'E' => 18), 46'C' => array('A' => 19, 'B' => 29, 'C' => 0, 'D' => 17, 'E' => 24), 47'D' => array('A' => 15, 'B' => 12, 'C' => 28, 'D' => 0, 'E' => 14), 48'E' => array('A' => 23, 'B' => 27, 'C' => 21, 'D' => 31, 'E' => 0), 49); 50 $this->candys = array( 51'A' => 'A', 52'B' => 'B', 53'C' => 'C', 54'D' => 'D', 55'E' => 'E', 56); 57*/ 58 } 59 60 public $outdated; 61 62 function __destruct() { 63 global $ID; 64 p_set_metadata($ID, array('schulzevote' => array( 65 'candys' => $this->candys, 66 'votes' => $this->votes, 67 'outdated' => $this->outdated))); 68 } 69 70 // run a vote $data = array('a' => 1, 'b' => 2, 'c' => 2, 'd' => 3) 71 // user need to be logged in 72 function vote($data) { 73 global $ID; 74 if ($this->hasVoted()) 75 return false; 76 $unique_values = array(); 77 foreach ($data as $cand => $score) { 78 if ($score === 0) 79 return false; 80 if (in_array($score, $unique_values)) 81 return false; 82 $unique_values[] = $score; 83 } 84 $this->votes[] = array('user' => $_SERVER['REMOTE_USER'], 'data' => $data); 85 return true; 86 } 87 88 // recalc the winner and prefer matrix 89 function getPreferences() { 90 if (empty($this->votes)) 91 return array(); 92 $prefer = array(); 93 foreach ($this->votes as $vote) { 94 foreach ($vote['data'] as $k => $v) { 95 foreach($vote['data'] as $k2 => $v2) { 96 if ($v < $v2) { 97 ++$prefer[$k][$k2]; 98 } 99 } 100 } 101 } 102 return $prefer; 103 } 104 105 function hasVoted() { 106 foreach ($this->votes as $vote) 107 if ($vote['user'] === $_SERVER['REMOTE_USER']) 108 return true; 109 return false; 110 } 111 112 /* Return strength of the strongest path */ 113 function get() { 114 115 $in = $this->getPreferences(); 116 $out = array(); 117 foreach ($this->candys as $i) { 118 foreach ($this->candys as $j) { 119 if ($i != $j && $in[$i][$j] > $in[$j][$i]) { 120 $out[$i][$j] = $in[$i][$j]; 121 } else { 122 $out[$i][$j] = 0; 123 } 124 } 125 } 126 127 foreach ($this->candys as $i) { 128 foreach ($this->candys as $j) { 129 if ($i!=$j) { 130 foreach ($this->candys as $k) { 131 if ($i!=$k) { 132 if ($j!=$k) { 133 $out[$j][$k] = max($out[$j][$k], min($out[$j][$i], $out[$i][$k])); 134 } 135 } 136 } 137 } 138 } 139 } 140 return $out; 141 } 142 143 function getRanking() { 144 $get = $this->get(); 145 146 $ret = array(); 147 while (count($get) > 0) { 148 $winners = array(); 149 foreach (array_keys($get) as $test) { 150 if ($this->isWinnerCandidate($test, $get)) { 151 $winners[] = $test; 152 } 153 } 154 if (count($winners) == 0) { 155 $winners = array_keys($get); 156 } 157 foreach($winners as $winner) { 158 unset($get[$winner]); 159 } 160 $ret[] = $winners; 161 } 162 return $ret; 163 } 164 165 function getWinner() { 166 $get = $this->get(); 167#dbg($get); 168 169 foreach ($this->candys as $test) { 170# echo "test $test..."; 171 if ($this->isWinner($test, $get)) { 172# echo "winner!"; 173 return $test; 174 } 175# echo "looser!\n"; 176 } 177 return null; 178 } 179 180 function isWinnerCandidate($candy, $get) { 181 foreach ($this->candys as $other) { 182 if ($candy == $other) continue; 183 if ($get[$candy][$other] < $get[$other][$candy]) { 184 return false; 185 } 186 } 187 return true; 188 } 189 190 function isWinner($candy, $get) { 191 foreach ($this->candys as $other) { 192 if ($candy == $other) continue; 193 if ($get[$candy][$other] <= $get[$other][$candy]) { 194 return false; 195 } 196 } 197 return true; 198 } 199 200 // create a new vote to a candidate array 201 function createVote($candidates) { 202 if ($candidates !== $this->candys) { 203 $this->candys = $candidates; 204 $this->votes = array(); 205 } 206 } 207 208 // remove a vote for a candidate 209 function deleteVote() { 210 foreach ($this->votes as $id => $vote) 211 if ($vote['user'] === $_SERVER['REMOTE_USER']) { 212 unset ($this->votes[$id]); 213 return true; 214 } 215 return false; 216 } 217 218 // get user's vote 219 function getVote() { 220 foreach ($this->votes as $id => $vote) { 221 if ($vote['user'] === $_SERVER['REMOTE_USER']) { 222 return $vote['data']; 223 } 224 } 225 return array(); 226 } 227 228 // dealing with older data 229 function updatePoll($data) { 230 $vote = array('user' => 'unknown', 'data' => array()); 231 $vote_this = array('user' => $_SERVER['REMOTE_USER'], 'data' => array()); 232 foreach ($this->candys as $cand) { 233 $vote['data'][$cand] = 1; 234 $vote_this['data'][$cand] = 0; 235 } 236 foreach ($data['prefer'] as $cand => $pref) { 237 foreach ($pref as $cand2 => $score) { 238 $vote['data'][$cand2] += $score; 239 } 240 } 241 array_push($this->votes, $vote, $vote_this); 242 $this->outdated = true; 243 } 244} 245