Passed
Push — master ( 1d252d...bd204f )
by Daimona
01:55
created

PageRiconferma::getUser()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php declare( strict_types=1 );
2
3
namespace BotRiconferme\Wiki\Page;
4
5
use BotRiconferme\Message;
6
7
/**
8
 * Represents a single riconferma page
9
 */
10
class PageRiconferma extends Page {
11
	// Sections of the page, value = section number. Loaded in self::defineSections
12
	private $supportSection;
13
	private $opposeSection;
14
	/** @var array Counts of votes for each section */
15
	private $sectionCounts = [];
16
17
	// Possible outcomes of a vote
18
	public const OUTCOME_OK = 0;
19
	public const OUTCOME_FAIL_VOTES = 1;
20
	public const OUTCOME_NO_QUOR = 2;
21
	public const OUTCOME_FAIL = self::OUTCOME_FAIL_VOTES | self::OUTCOME_NO_QUOR;
22
23
	// Values depending on bureaucracy
24
	public const REQUIRED_OPPOSE = 15;
25
	public const SIMPLE_DURATION = 7;
26
	public const VOTE_DURATION = 14;
27
	public const SUCCESS_RATIO = 2 / 3;
28
29
	/**
30
	 * Define the numbers of the support and oppose sections. These are lazy-loaded
31
	 * because they can vary depending on whether the page is a vote, which is relatively
32
	 * expensive to know since it requires parsing the content of the page.
33
	 */
34
	private function defineSections() : void {
35
		$this->supportSection = $this->isVote() ? 3 : 0;
36
		$this->opposeSection = $this->isVote() ? 4 : 3;
37
	}
38
39
	/**
40
	 * Get the name of the user from the title
41
	 *
42
	 * @return string
43
	 */
44
	public function getUserName() : string {
45
		return explode( '/', $this->title )[2];
46
	}
47
48
	/**
49
	 * Returns the progressive number in the title
50
	 *
51
	 * @return int
52
	 */
53
	public function getNum() : int {
54
		$bits = explode( '/', $this->getTitle() );
55
		return (int)end( $bits );
56
	}
57
58
	/**
59
	 * Get the last part of the title as Username/Num
60
	 *
61
	 * @return string
62
	 */
63
	public function getUserNum() : string {
64
		return explode( '/', $this->getTitle(), 3 )[2];
65
	}
66
67
	/**
68
	 * Get the amount of opposing votes
69
	 *
70
	 * @return int
71
	 */
72
	public function getOpposingCount() : int {
73
		$this->defineSections();
74
		return $this->getCountForSection( $this->opposeSection );
75
	}
76
77
	/**
78
	 * Get the amount support votes
79
	 *
80
	 * @return int
81
	 * @throws \BadMethodCallException
82
	 */
83
	public function getSupportCount() : int {
84
		if ( !$this->isVote() ) {
85
			throw new \BadMethodCallException( 'Cannot get support for a non-vote page.' );
86
		}
87
		$this->defineSections();
88
		return $this->getCountForSection( $this->supportSection );
89
	}
90
91
	/**
92
	 * Count the votes in the given section
93
	 *
94
	 * @param int $secNum
95
	 * @return int
96
	 */
97
	protected function getCountForSection( int $secNum ) : int {
98
		if ( !isset( $this->sectionCounts[ $secNum ] ) ) {
99
			$content = $this->wiki->getPageContent( $this->title, $secNum );
100
			// Let's hope that this is good enough...
101
			$this->sectionCounts[$secNum] = preg_match_all( "/^# *(?![# *:]|\.\.\.$)/m", $content );
102
		}
103
		return $this->sectionCounts[$secNum];
104
	}
105
106
	/**
107
	 * Gets the quorum used for the current page
108
	 *
109
	 * @return int
110
	 */
111
	protected function getQuorum() : int {
112
		$reg = "!soddisfare il \[\[[^|\]]+\|quorum]] di '''(\d+) voti'''!";
113
		return (int)$this->getMatch( $reg )[1];
114
	}
115
116
	/**
117
	 * Whether this page has enough opposing votes
118
	 *
119
	 * @return bool
120
	 */
121
	public function hasOpposition() : bool {
122
		return $this->getOpposingCount() >= self::REQUIRED_OPPOSE;
123
	}
124
125
	/**
126
	 * Gets the outcome for the vote
127
	 *
128
	 * @return int One of the OUTCOME_* constants
129
	 */
130
	public function getOutcome() : int {
131
		if ( !$this->isVote() ) {
132
			return self::OUTCOME_OK;
133
		}
134
		$totalVotes = $this->getOpposingCount() + $this->getSupportCount();
135
136
		if ( $this->getSupportCount() < $this->getQuorum() ) {
137
			$ret = self::OUTCOME_NO_QUOR;
138
		} elseif ( $this->getSupportCount() < self::SUCCESS_RATIO * $totalVotes ) {
139
			$ret = self::OUTCOME_FAIL_VOTES;
140
		} else {
141
			$ret = self::OUTCOME_OK;
142
		}
143
		return $ret;
144
	}
145
146
	/**
147
	 * Get the result text for the page itself
148
	 *
149
	 * @return string
150
	 * @throws \BadMethodCallException
151
	 * @throws \LogicException
152
	 */
153
	public function getOutcomeText() : string {
154
		if ( !$this->isVote() ) {
155
			throw new \BadMethodCallException( 'No need for an outcome text.' );
156
		}
157
158
		$text = sprintf(
159
			' Con %d voti a favore e %d contrari',
160
			$this->getSupportCount(),
161
			$this->getOpposingCount()
162
		);
163
		$user = $this->getUserName();
164
165
		switch ( $this->getOutcome() ) {
166
			case self::OUTCOME_OK:
167
				$text .= " $user viene riconfermato amministratore.";
168
				break;
169
			/** @noinspection PhpMissingBreakStatementInspection */
170
			case self::OUTCOME_NO_QUOR:
171
				$text .= ', non raggiungendo il quorum,';
172
				// Fall-through intended
173
			case self::OUTCOME_FAIL:
174
				$text .= " $user non viene riconfermato amministratore.";
175
				break;
176
			default:
177
				throw new \LogicException( 'Invalid outcome: ' . $this->getOutcome() );
178
		}
179
		return $text;
180
	}
181
182
	/**
183
	 * Whether this page is a vote
184
	 *
185
	 * @return bool
186
	 */
187
	public function isVote() : bool {
188
		$sectionReg = '/<!-- SEZIONE DA UTILIZZARE PER/';
189
		return !$this->matches( $sectionReg );
190
	}
191
192
	/**
193
	 * Get the timestamp of the creation of the page
194
	 *
195
	 * @return int
196
	 */
197
	public function getCreationTimestamp() : int {
198
		return $this->wiki->getPageCreationTS( $this->title );
199
	}
200
201
	/**
202
	 * Get the end time
203
	 *
204
	 * @return int
205
	 */
206
	public function getEndTimestamp() : int {
207
		if ( $this->isVote() ) {
208
			$reg = "!La votazione ha inizio il.+ alle ore ([\d:]+) e ha termine il (.+) alla stessa ora!";
209
			[ , $hours, $day ] = $this->getMatch( $reg );
210
			$day = preg_replace( '![^ \w]!', '', $day );
211
			return Message::getTimestampFromLocalTime( "$day $hours" );
212
		}
213
		return $this->getCreationTimestamp() + 60 * 60 * 24 * self::SIMPLE_DURATION;
214
	}
215
}
216