<?php namespace HashOver;// Copyright (C) 2010-2021 Jacob Barkdull// This file is part of HashOver.//// HashOver is free software: you can redistribute it and/or modify// it under the terms of the GNU Affero General Public License as// published by the Free Software Foundation, either version 3 of the// License, or (at your option) any later version.//// HashOver is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU Affero General Public License for more details.//// You should have received a copy of the GNU Affero General Public License// along with HashOver.  If not, see <http://www.gnu.org/licenses/>.class Thread{	protected $setup;	public $data;	public $commentList = array ();	public $threadCount = array ();	public $primaryCount = 1;	public $totalCount = 1;	public $primaryDeletedCount = 0;	public $collapsedDeletedCount = 0;	public $totalDeletedCount = 0;	public function __construct (Setup $setup)	{		// Store parameters as properties		$this->setup = $setup;		// Name of data format class to instantiate		$data_class = 'HashOver\\Parse' . strtoupper ($setup->dataFormat);		// Instantiate data format class		$this->data = new $data_class ($setup, $this);	}	// Queries a list of comments	public function queryComments ()	{		// Query a list of comments		$comment_list = $this->data->query ();		// Check if comments could be queried		if (!empty ($comment_list)) {			// If so, set comments as comment list			$this->commentList = $comment_list;			// And organize comments			$this->organizeComments ();		}	}	// Counts a comment	public function countComment ($comment)	{		// Check if comment has replies		if (strpos ($comment, '-') !== false) {			// If so, split comment by dashes			$file_parts = explode ('-', $comment);			// Get parent comment			$thread = basename ($comment, '-' . end ($file_parts));			// Check if parent comment reply count exists			if (isset ($this->threadCount[$thread])) {				// If so, increase parent comment reply count				$this->threadCount[$thread]++;			} else {				// If not, create parent comment reply count				$this->threadCount[$thread] = 1;			}		} else {			// If not, increase primary comment count			$this->primaryCount++;		}		// Check if thread comment count exists		if (isset ($this->threadCount[$comment])) {			// If so, increase thread comment count			$this->threadCount[$comment]++;		} else {			// If not, create thread comment count			$this->threadCount[$comment] = 1;		}		// Increase total comment count		$this->totalCount++;	}	// Explode a string, cast substrings to integers	protected function intExplode ($delimiter, $string)	{		// Initial integers		$ints = array ();		// Split string by delimiter		$parts = explode ($delimiter, $string);		// Cast all parts of string to integers		for ($i = 0, $il = count ($parts); $i < $il; $i++) {			$ints[] = (int)($parts[$i]);		}		return $ints;	}	// Counts a deleted comment	protected function countDeleted ($comment)	{		// Count deleted replies		if (strpos ($comment, '-') === false) {			$this->primaryDeletedCount++;		}		// Get count from comment key		$comment_parts = $this->intExplode ('-', $comment);		$comment_count = array_sum ($comment_parts);		// Count collapsed deleted comments		if ($comment_count > $this->setup->collapseLimit) {			$this->collapsedDeletedCount++;		}		// Count all other deleted comments		$this->totalDeletedCount++;	}	// Check for missing comments	protected function findMissingComments ($key)	{		// Get integers from key		$key_parts = $this->intExplode ('-', $key);		// Initial comment tree		$comment_tree = '';		// Run through each key		foreach ($key_parts as $key => $reply) {			// Check for comments counting backward from the current			for ($i = 1; $i <= $reply; $i++) {				// Current level to check for				if ($key > 0) {					$current = $comment_tree . '-' . $i;				} else {					$current = $i;				}				// Check for the comment in the list				if (!isset ($this->commentList[$current])) {					// If it doesn't exist, mark comment as missing					$this->commentList[$current] = 'missing';					// Count the missing comment					$this->countComment ($current);					$this->countDeleted ($current);				}			}			// Add current reply number to tree			if ($key > 0) {				$comment_tree .= '-' . $reply;			} else {				$comment_tree = $reply;			}		}	}	// Organize comments	protected function organizeComments ()	{		// Run through comment list		foreach ($this->commentList as $key) {			// Check for missing comments			$this->findMissingComments ($key);			// Count comment			$this->countComment ($key);		}		// Sort comments by their keys alphabetically in ascending order		uksort ($this->commentList, 'strnatcasecmp');	}	// Read comments	public function read ($end = -1)	{		// Initial data to return		$comments = array ();		// Number of comments successfully added to return data		$added_count = 0;		// Run through each comment		foreach ($this->commentList as $i => $key) {			// Stop at end point			if ($end !== -1 and $added_count >= $end) {				break;			}			// Skip deleted comments			if ($key === 'missing') {				$comments[$i]['status'] = 'missing';				continue;			}			// Read comment			$comment = $this->data->read ($key);			// See if it read successfully			if ($comment !== false) {				// If so, add the comment to output				$comments[$i] = $comment;				// Count deleted status comments				if (Misc::getArrayItem ($comment, 'status') === 'deleted') {					$this->countDeleted ($key);				}				// And increase added count				$added_count++;			} else {				// If not, set comment status as a read error				$comments[$i]['status'] = 'read-error';			}		}		return $comments;	}	// Queries an array of websites	public function queryWebsites ()	{		return $this->data->queryWebsites ();	}	// Queries an array of comment threads	public function queryThreads ()	{		return $this->data->queryThreads ();	}}