<!DOCTYPE html>
<html lang="en-US">

<?php

/*
Book Listing Page
Provides Book Listing Based on Search/Category/Author and Ordered by Sorting
*/

// GENERAL SERVER LIBRARIES

// read the parameters for the current domain
$domain = preg_split('*/*', __FILE__)[4];
if (!defined('HOMEPATH')) { define("HOMEPATH", "/var/www/html/$domain/"); } // get server-user homepath
require_once(HOMEPATH . "/parameters/parameters-db.php");  								// db connection info
require_once(HOMEPATH . "/parameters/parameters-publisher.php");  						// publisher info
require_once(HOMEPATH . "/libraries/lib-utils.php"); 									// utility functions
require_once(HOMEPATH . "/libraries/lib-metadata.php"); 								// catalog data functions

// --------------------------------------- PAGE FUNCTIONS ----------------------------------------------

function getCoupon ($code) {
	/* search discount table for code matching $coupon
	return coupon row if found */

	if (!$code) {
		return False;
	}
	
	$result = SQLi("
	SELECT * FROM discounts
	WHERE
		code = ?
	LIMIT 1",
	's', [$code]);

	if (!$result) {
		return False; 
	}

	$discount = $result->fetch_assoc();

	return $discount;

}

function getCouponTitles ($coupon, $author_initials) {
	/* 
	if passed coupon applicable only to specific titles,
		return list of matching titles as an array of project numbers as integers
		only return titles matching $author_initials */
	
	if (!$coupon['allowed_titles']) {
		return False;
	}

	$rawtitles = explode(',',$coupon['allowed_titles']);
	$projnums = array();

	foreach ($rawtitles as $key => $rawtitle) {
		if (preg_match('~^\s*([a-zA-Z]+)\-([0-9]+)\s*$~', $rawtitle, $matches)) {

			if (strtolower($matches[1]) == $author_initials) {
				if (!in_array((int)$matches[2], $projnums)) {
					$projnums[] = (int)$matches[2];
				}
			}
		}

	}

	if (!count($projnums)) {
		return False;
	}

	return $projnums;
}

function baseLink (...$exceptions) {
	/* builds relative link to current page
	recycles all GET values into url
	skips any GET keys in array $exceptions */

	$baselink = './listing.php?';
	foreach ($_GET as $key => $value) {
		if (!in_array($key, $exceptions)) {
			$baselink .= urlencode($key) . "=" . urlencode($value) . "&";
		}
	}

	return $baselink;
}

function getAll () {

	global $AUTHOR, $sort;

	$result = SQLi("
	SELECT * FROM book_catalog
	WHERE
		author = ? AND
		status IN ('ARC', 'Pre-release','Amazon-Exclusive','Available','Announced')
	ORDER BY $sort",
	's', [$AUTHOR['initials']]);

	// build into standard result array of form bookcode => bookrow

	$resultarray = array();

	if ($result) {
		while ($row = $result->fetch_assoc()) {
			$bookcode = $row['author'] . '-' . str_pad("$row[project_num]", 3, '0', STR_PAD_LEFT);
			$resultarray[$bookcode] = array_merge(Array('matches' => 0, 'bookcode' => $bookcode), $row);
		}
	}

	return $resultarray;

}

function searchBooks ($bookarray, $searchstring) {
	/* split search string into its consituent words
	remove articles, etc.
	search each book in bookarray for number of matches in title, blurb, series, and keywords fields
		giving triple-weight to title */

	global $AUTHOR, $PUBLISHER;

	// log user search unless the user is a crawler/bot

	if (!userBotCheck()) {
		reportInfo("usage-records@$PUBLISHER[site].com", 'Listing Search - ' . anonIP($_SERVER['REMOTE_ADDR']), $searchstring . '\n' . print_r($_GET, True));
	}
	
	// parse searchstring into a list of meaningful words
	
	$rawsearcharray = explode(' ',$searchstring);
	$searcharray = array();
	$stopwords = ["a", "about", "above", "after", "again", "against", "all", "am", "an", "and", "any", "are", "as", "at", "be", "because", "been", "before", "being", "below", "between", "both", "but", "by", "could", "did", "do", "does", "doing", "down", "during", "each", "few", "for", "from", "further", "had", "has", "have", "having", "he", "he'd", "he'll", "he's", "her", "here", "here's", "hers", "herself", "him", "himself", "his", "how", "how's", "i", "i'd", "i'll", "i'm", "i've", "if", "in", "into", "is", "it", "it's", "its", "itself", "let's", "me", "more", "most", "my", "myself", "nor", "of", "on", "once", "only", "or", "other", "ought", "our", "ours", "ourselves", "out", "over", "own", "same", "she", "she'd", "she'll", "she's", "should", "so", "some", "such", "than", "that", "that's", "the", "their", "theirs", "them", "themselves", "then", "there", "there's", "these", "they", "they'd", "they'll", "they're", "they've", "this", "those", "through", "to", "too", "under", "until", "up", "very", "was", "we", "we'd", "we'll", "we're", "we've", "were", "what", "what's", "when", "when's", "where", "where's", "which", "while", "who", "who's", "whom", "why", "why's", "with", "would", "you", "you'd", "you'll", "you're", "you've", "your", "yours", "yourself", "yourselves"];

	foreach ($rawsearcharray as $searchword) {
		$searchword = trim(strtolower($searchword));
		if (!$searchword) { continue; }
		if (in_array($searchword, $stopwords)) { continue; }
		if (in_array($searchword, $searcharray)) { continue; }
		$searcharray[] = $searchword;
	}

	// iterate through books in bookarray, derive a compound searchable field, count matches and append match count to array and array to $searchfound

	$searchfound = array();
	
	foreach ($bookarray as $bookcode => $book) {

		// parse title, blurb and keyword fields into single string, double-weighting title
		$bookinfo = strtolower($book['title'] .' '. $book['title'] .' '. $book['title'] .' '. $book['blurb'] .' '. $book['series'] .' '. $book['tags'] . ' ' . $AUTHOR['fullname']);
		$matchcount = 0;

		foreach ($searcharray as $searchword) {

			// escape any incidental regex characters to provide literal string search
			$searchword = '~' . preg_quote($searchword) . '~';

			if(preg_match_all($searchword, $bookinfo, $matches)) {

				// slightly unintuitive behavior here: $matches is not [$match1, $match2, $match3, etc.] but rather [$allfullmatches, $allmatchgroup1s, $allmatchgroup2s, etc.]
				// thus, to get a list of matches, use $matches[0]
				foreach ($matches[0] as $match) {
					$matchcount += 1;
				}
			}
		}

		// if search was found, assign matches value and add to $searchfound array

		if ($matchcount) {
			$book['matches'] = $matchcount;
			$searchfound[$bookcode] = $book;
		}
	}
	return $searchfound;
}

function sort_arrays ($sortkey, $target_array, $direction = True) {

	/* sort an array of arrays by value of key in each respective array */

	$sortkeyarray = Array();

	foreach ($target_array as $key => $array) {
		$sortkeyarray[$key] = $array[$sortkey];
	}

	asort($sortkeyarray);
	if ($direction) { $sortkeyarray = array_reverse($sortkeyarray, TRUE); }

	$sorted_array = Array();

	foreach ($sortkeyarray as $key => $val) {
		$sorted_array[] = $target_array[$key];
	}
	
	return $sorted_array;

}

// --------------------------------------- GET GENERAL PARAMETERS ------------------------------------------------



// database connection
global $dbhost,$rs_sqluser,$rs_sqlpass, $rs_dbmail;
$db = new mysqli($dbhost,$rs_sqluser,$rs_sqlpass, $rs_dbmail);

// get author
$author_initials = strtolower(basename(getcwd()));
global $AUTHOR; $AUTHOR = getAuthor($author_initials); // lib-utils utility

// establish default listing parameters

$disp_num = 10;
$disp_offset = 0;
$specialmessage = '';

// sort options

$sortoptions = array(	"Most Recent" => 'release_date DESC',
						"Price Low to High" => 'price ASC',
						"Price High to Low" => 'price DESC',
						"Shortest to Longest" => 'wordcount ASC', 
						"Longest to Shortest" => 'wordcount DESC',
						"Title A-Z" => 'title ASC',
						"Title Z-A" => 'title DESC');

// ------------------------------------------- GET BOOK LIST ---------------------------------------------------

if (array_key_exists('srt', $_GET) && $_GET['srt']) {
	if (array_key_exists($_GET['srt'], $sortoptions)) {
		$sort = $sortoptions[$_GET['srt']];
		$explicitsort = $_GET['srt'];
	}
}
if (!isset($sort)) {
	$sort = 'release_date DESC';
    	$explicitsort = null;
}

// if coupon was passed, display qualifying titles

if (array_key_exists('coupon', $_GET) && $_GET['coupon']) {

	// get array of eligible titles from current author, by project number
	
	$coupon = getCoupon(trim($_GET['coupon']));

	if ($coupon) {

		$coupontitles = getCouponTitles($coupon, $author_initials);

		// retrieve book information from book_catalog

		$prm_query = '(?' . str_repeat(",?",count($coupontitles)-1) . ')';
		$prm_format = str_repeat('i',count($coupontitles));

		$result = SQLi("
		SELECT * FROM book_catalog
		WHERE
			project_num IN $prm_query AND
			author = ?
		ORDER BY $sort",
		$prm_format . 's', array_merge($coupontitles,[strtolower($AUTHOR['initials'])]));

		// build into standard result array of form bookcode => bookrow

		$resultarray = array();

		if ($result) {
			while ($row = $result->fetch_assoc()) {
				$bookcode = $row['author'] . '-' . str_pad("$row[project_num]", 3, '0', STR_PAD_LEFT);
				$resultarray[$bookcode] = array_merge(Array('matches' => 0, 'bookcode' => $bookcode), $row);
			}
		}

		// if successful, construct special message to display information about the coupon

		if (count($resultarray)) {
			$percent = $coupon['discount'] * 100;
			$specialmessage .= "$_GET[coupon] will give $percent % off the listed price of the titles listed here, in addition to the standard subscriber's discount if applicable.";
		}
	}
}

// if search string was passed, search the string

elseif (array_key_exists('srch', $_GET) && $_GET['srch']) {
	$srch = urldecode($_GET['srch']);

	$bookarray = getAll();
	$resultarray = searchBooks ($bookarray, $srch);

	// sort by matches unless sort was explicitly set by GET

	if (!(array_key_exists('srt', $_GET)) || ($_GET['srt'] == 'Best Match')) {
		$resultarray = sort_arrays('matches', $resultarray);
		$explicitsort = 'Best Match';
	}

	// add best match to possible sort options

	$sortoptions['Best Match'] = '';

	// if no matches found report search failure to user

	if (!count($resultarray)) {
		$specialmessage = "No results found";
	}
} else { $srch = ''; }

// if no specialized method has constructed list of titles, create a list of all author titles and list in reverse order of release
// the desired behavior is that if a specialized method attempts and fails to retrieve any titles, no titles should be displayed

if (!isset($resultarray)) {
	$resultarray = getAll();
}

// --------------------------------------- BUILD LIST CONTEXT -------------------------------------------

// if valid displaynumber passed, use it

if (array_key_exists('srt', $_GET) && preg_match("/^\d+$/", $_GET['n'])) {
	$disp_num = (int)$_GET['n'];
}

// if valid display offset passed, use it

if (array_key_exists('o', $_GET) && preg_match("/^\d+$/", $_GET['o'])) {
	$disp_offset = (int)$_GET['o'];
}

// limit list to number and offset

$bookarray = array_slice($resultarray, $disp_offset, $disp_num);

// --------------------------------------- PAGE CONTENT ------------------------------------------------

// header data and banner

include('header.php');

// ---------------- Result Description and Options ---------------------

echo "<div class='content-container'>";

	echo "<div class='store-listing-options'>";

	// special message

	if ($specialmessage) {
		echo "<h3>$specialmessage</h3>";
	}

	// result description

	echo "<p>Showing Results $disp_offset - " . (string)($disp_offset + count($bookarray)) . " out of " . (string)count($resultarray) . "</p>";
	echo "</div>";

	// search bar

	echo "<form method='get' action='listing.php'>
	<input class='center-input' type='text' name='srch' value='$srch' placeholder='Search All Books'>
	<button class='center-submit' type='submit'>Search</button></form>";

	// offer sort by dropdwon

	echo "<p>Sorted By <select name='Sort by' onchange='location = this.value;' class='listing-dropdown'>";

	// the presumed desired behavior here is to reset to first search results when re-ordering, so don't pass offset as well in the base link
	$link = baseLink('srt', 'o');
	foreach ($sortoptions as $key => $code) {
		$urlkey = urlencode($key);
		if ($key != null && $key == $explicitsort) {
			echo "<option value='" . $link . "srt=$urlkey' selected='selected'>$key</option>";
		}
		else {
			echo "<option value='" . $link . "srt=$urlkey'>$key</option>";
		}
			
	}

	echo "</select></p>";

// ---------------- Listing Content ---------------------

	echo "<div class='store-listing-box'>";

	foreach ($bookarray as $bookcode => $book) {
		echo "<div class='store-book-row'>";

			// Cover
			
			echo "<div class='store-book-cell store-cover-cell'><a class='img-link' href='./book.php?id=$book[bookcode]'>
				<img src='https://$PUBLISHER[site].com/shop/graphics/covers/$book[bookcode]-Final-M.jpg' class='store-book-cover-image'>
			</a></div>";

			// Title
			
			echo "<div class='store-book-cell store-title-cell'><a class='neutral-link' href='./book.php?id=$book[bookcode]'>
				<h3>$book[title]</h3>
			</a></div>";

			// ShortBlurb
			// order of preference : explicit value of 'short_blurb' > modified value of 'blurb' > holdertext
			// bingbingbing this is a sloppy solution, but it'll do for now

			$shortblurb = $book['short_blurb'];

			// if no true short_blurb, attempt to modify longblurb

			if (!$shortblurb) {
				$shortblurb = longBlurbtoShort($book['blurb']);
			}

			$shortblurb = Paragraph_Tag($shortblurb);

			echo "<div class='store-book-cell store-content-cell'><a class='neutral-link' href='./book.php?id=$book[bookcode]'>
				<p>$shortblurb</p></b></i></h1></h2></h3></u>
			</a></div>";

			// Price
			if ($book['status'] == 'Available') {
				if (!$book['price']) { $price = "FREE"; }
				else { $price = $book['price']; }
			}
			elseif (in_array($book['status'], ['Announced', 'ARC'])) {
				if ($book['release_date']) {
					$date = new DateTime($book['release_date']);
					$human_date = $date->format('M j');
					$price = "Coming $human_date";
				}
				else {
					$price = "Coming Soon";
				}
			}
			elseif ($book['status'] == 'Pre-Release') {
				$price = "Pre-Order Now";
			}
			elseif ($book['status'] == 'Amazon-Exclusive') {
				$price = "Amazon Exclusive";
			}
			else {
				$price = '';
			}
			
			echo "<div class='store-book-cell store-price-cell'><a class='neutral-link' href='./book.php?id=$book[bookcode]'>
				<p>$price</p>
			</a></div>";

		echo "</div>";

	}

	echo "</div>";
	echo "<div class='store-listing-pages'>";

		$link = baseLink('o');
		$x = 0;
		$y = 0;
		echo "<h3><a href='" . $link . "o=" . (string)($disp_offset - $disp_num) . "'>&#8592;</a> ";
		while ($x < count($resultarray)) {

			echo " <a href='" . $link ."o=" . (string)($disp_num * $y) . "'>$y</a> ";
			$x = $x + $disp_num;
			$y = $y + 1;
		}

		echo " <a href='" . $link . "o=" . (string)($disp_offset + $disp_num) . "'>&#8594;</a> </h3>";

	echo "</div>";

echo "</div></div>";

include('footer.php');
?>

</html>
