Subversion Repositories cheapmusic

Rev

Rev 79 | Rev 82 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

<?php
include_once ('php/clsLibGTIN.php');
include_once ('php/exchangeRates.php');
include_once ('php/countryCodes.php');
include_once ('php/constants.php');
include_once ('php/ebay.php');
include_once ('php/discogs.php');
include_once ('php/linkshare.php');
include_once ('php/cjaffiliate.php');
include_once ('php/walmart.php');
include_once ('php/itunes.php');
include_once ('php/amazon.php');

error_reporting(E_ALL);

// search
function performSearch() {
    $currentMd5SearchTerm = md5SearchTerm();
    if ($currentMd5SearchTerm == $_SESSION['md5LastSearch']) {
        return;
    }
    $_SESSION['md5LastSearch'] = $currentMd5SearchTerm;

    $_SESSION["barcode"]["Type"] = clsLibGTIN::GTINCheck($_SESSION["searchTerm"], false, 1);
    $_SESSION["barcode"]["Value"] = clsLibGTIN::GTINCheck($_SESSION["searchTerm"]);

    updatePbFile(true);

    findDiscogsMaster($_SESSION["searchTerm"]);
    updatePbFile();

    $_SESSION["currentView"] = 'All';
    $_SESSION["currentLayout"] = 'TableView';
    $_SESSION["resultArr"] = [];
    $_SESSION["resultArr"] = searchAll($_SESSION["searchTerm"]);
    updatePbFile();

    $_SESSION["resultArr"] = applySearchFilter($_SESSION["resultArr"]);
    updatePbFile();

    //echo "<pre>";print_r($_SESSION["resultArr"]);echo "</pre>";
    $_SESSION["lowestPrice"]["Used"] = findLowestCondition("Used");
    $_SESSION["lowestPrice"]["New"] = findLowestCondition("New");
    $_SESSION["lowestPrice"]["CD"] = findLowestMediaType("CD");
    $_SESSION["lowestPrice"]["Record"] = findLowestMediaType("Record");
    $_SESSION["lowestPrice"]["Digital"] = findLowestMediaType("Digital");
    $_SESSION["lowestPrice"]["Book"] = findLowestMediaType("Book");
    $_SESSION["lowestPrice"]["All"] = 0.00;
    if (array_sum($_SESSION["lowestPrice"]) > 0) {
        $_SESSION["lowestPrice"]["All"] = minNotNull($_SESSION["lowestPrice"]);
    }
    updatePbFile();

    saveSearchResult();
    updatePbFile();
}

function resetSessionVars() {
    $_SESSION["searchTerm"] = '';
    $_SESSION["discogsTitle"] = '';
    $_SESSION["discogsArtist"] = '';
    $_SESSION['md5LastSearch'] = '';
    $_SESSION["currentView"] = 'All';
    $_SESSION["currentLayout"] = 'TableView';
    $_SESSION["barcode"]["Type"] = '';
    $_SESSION["barcode"]["Value"] = '';

    $_SESSION["resultArr"] = [];

    $_SESSION["lowestPrice"]["Used"] = 0.00;
    $_SESSION["lowestPrice"]["New"] = 0.00;
    $_SESSION["lowestPrice"]["CD"] = 0.00;
    $_SESSION["lowestPrice"]["Record"] = 0.00;
    $_SESSION["lowestPrice"]["Digital"] = 0.00;
    $_SESSION["lowestPrice"]["Book"] = 0.00;
    $_SESSION["lowestPrice"]["All"] = 0.00;
}

// search for items on all sites
function searchAll($searchKey, $batchFlag = false) {
    $arr = [];
    if ($_SESSION["filterCondition"]["New"]) {
        $arr = get_vendor($arr, 'get_ebay', $searchKey, constant("NEW"));
    }
    if (!$batchFlag) { updatePbFile(); }
    if ($_SESSION["filterCondition"]["New"]) {
        $arr = get_vendor($arr, 'get_linkshare', $searchKey, constant("NEW"));
    }
    if (!$batchFlag) { updatePbFile(); }
    if ($_SESSION["filterCondition"]["New"]) {
        $arr = get_vendor($arr, 'get_cjaffiliate', $searchKey, constant("NEW"));
    }
    if (!$batchFlag) { updatePbFile(); }
    if ($_SESSION["filterCondition"]["New"]) {
        $arr = get_vendor($arr, 'get_walmart', $searchKey, constant("NEW"));
    }
    if (!$batchFlag) { updatePbFile(); }
    if ($_SESSION["filterCondition"]["New"]) {
        $arr = get_vendor($arr, 'get_itunes', $searchKey, constant("NEW"));
    }
    if (!$batchFlag) { updatePbFile(); }

    $arr = get_vendor($arr, 'get_amazon', $searchKey, constant("NEW"));
    if (!$batchFlag) { updatePbFile(); }

    if ($_SESSION["filterCondition"]["Used"]) {
        $arr = get_vendor($arr, 'get_ebay', $searchKey, constant("USED"));
    }
    if (!$batchFlag) { updatePbFile(); }

//echo "<pre>";print_r($arr);echo "</pre";

    $arr = applyExchangeRates($arr);
    usort($arr, 'compare_price');
    if (!$batchFlag) { updatePbFile(); }

    return $arr;
}

// Search and merge
function get_vendor($arr, $func, $searchKey, $condition) {
    $arrTemp = $func($searchKey, $condition);
    return array_merge($arrTemp, $arr);
}

// check search filters
function checkSearchFilters() {
    $_SESSION["filterWarnings"] = "";
    $filterOk = true;

    if (!$_SESSION["filterCondition"]["New"] && !$_SESSION["filterCondition"]["Used"]) {
        $_SESSION["filterWarnings"] .= '<div class="alert alert-danger"><i class="fas fa-filter mr-1"></i> Please select at least one Condition (New or Used)</div>';
        $filterOk = false;
    }

    if (!$_SESSION["filterMediaType"]["CD"] && !$_SESSION["filterMediaType"]["Record"] && !$_SESSION["filterMediaType"]["Digital"] && !$_SESSION["filterMediaType"]["Book"]) {
        $_SESSION["filterWarnings"] .= '<div class="alert alert-danger"><i class="fas fa-filter mr-1"></i> Please select at least one Media Type (CD, Record, Digital or Book)</div>';
        $filterOk = false;
    }

    return ($filterOk);
}

// delete results from array that do not match the search filters
function applySearchFilter($arr) {
    unset($_SESSION['AdditionalFilterCounters']);
    unset($_SESSION['AdditionalFilters']);
    foreach ($arr as $key => $row) {
        if (!$_SESSION["filterMediaType"][$row["MediaType"]] || !$_SESSION["filterCondition"][$row["Condition"]]) {
            unset($arr[$key]);
        } else {
            if (isset($_SESSION['AdditionalFilterCounters']['Condition']['All'])) {
                $_SESSION['AdditionalFilterCounters']['Condition']['All']++;
            } else {
                $_SESSION['AdditionalFilterCounters']['Condition']['All'] = 1;
            }

            if (isset($_SESSION['AdditionalFilterCounters']['Merchant'][$row['Merchant']])) {
                $_SESSION['AdditionalFilterCounters']['Merchant'][$row['Merchant']]++;
            } else {
                $_SESSION['AdditionalFilterCounters']['Merchant'][$row['Merchant']] = 1;
                $_SESSION['AdditionalFilters']['Merchant'][$row['Merchant']] = true;
            }

            if (!empty($row['SellerName'])) {
                if (isset($_SESSION['AdditionalFilterCounters']['Seller'][$row['SellerName']])) {
                    $_SESSION['AdditionalFilterCounters']['Seller'][$row['SellerName']]++;
                } else {
                    $_SESSION['AdditionalFilterCounters']['Seller'][$row['SellerName']] = 1;
                    $_SESSION['AdditionalFilters']['Seller'][$row['SellerName']] = true;
                }
            }

            if (isset($_SESSION['AdditionalFilterCounters']['Condition'][$row['Condition']])) {
                $_SESSION['AdditionalFilterCounters']['Condition'][$row['Condition']]++;
            } else {
                $_SESSION['AdditionalFilterCounters']['Condition'][$row['Condition']] = 1;
                $_SESSION['AdditionalFilters']['Condition'][$row['Condition']] = true;
            }

            if (isset($_SESSION['AdditionalFilterCounters']['MediaType'][$row['MediaType']])) {
                $_SESSION['AdditionalFilterCounters']['MediaType'][$row['MediaType']]++;
            } else {
                $_SESSION['AdditionalFilterCounters']['MediaType'][$row['MediaType']] = 1;
                $_SESSION['AdditionalFilters']['MediaType'][$row['MediaType']] = true;
            }

            if (isset($_SESSION['AdditionalFilterCounters']['DetailCondition'][$row['DetailCondition']])) {
                $_SESSION['AdditionalFilterCounters']['DetailCondition'][$row['DetailCondition']]++;
            } else {
                $_SESSION['AdditionalFilterCounters']['DetailCondition'][$row['DetailCondition']] = 1;
                $_SESSION['AdditionalFilters']['DetailCondition'][$row['DetailCondition']] = true;
            }

            if (isset($_SESSION['AdditionalFilterCounters']['ShippingFrom'][$row['Country']])) {
                $_SESSION['AdditionalFilterCounters']['ShippingFrom'][$row['Country']]++;
            } else {
                $_SESSION['AdditionalFilterCounters']['ShippingFrom'][$row['Country']] = 1;
                $_SESSION['AdditionalFilters']['ShippingFrom'][$row['Country']] = true;
            }
        }
    }

    if (isset($_SESSION['AdditionalFilters']['Merchant'])) {
        ksort($_SESSION['AdditionalFilters']['Merchant'], SORT_NATURAL | SORT_FLAG_CASE);
    }

    if (isset($_SESSION['AdditionalFilters']['Seller'])) {
        ksort($_SESSION['AdditionalFilters']['Seller'], SORT_NATURAL | SORT_FLAG_CASE);
    }

    if (isset($_SESSION['AdditionalFilters']['Condition'])) {
        ksort($_SESSION['AdditionalFilters']['Condition'], SORT_NATURAL | SORT_FLAG_CASE);
    }

    if (isset($_SESSION['AdditionalFilters']['DetailCondition'])) {
        ksort($_SESSION['AdditionalFilters']['DetailCondition'], SORT_NATURAL | SORT_FLAG_CASE);
    }

    if (isset($_SESSION['AdditionalFilters']['ShippingFrom'])) {
        ksort($_SESSION['AdditionalFilters']['ShippingFrom'], SORT_NATURAL | SORT_FLAG_CASE);
    }

    if (isset($_SESSION['AdditionalFilters']['MediaType'])) {
        ksort($_SESSION['AdditionalFilters']['MediaType'], SORT_NATURAL | SORT_FLAG_CASE);
    }

    return $arr;
}

// filter view result table $_SESSION["resultArr"] for All, New, Used, Digital, or Book
function filterResults() {
    foreach ($_SESSION["resultArr"] as & $row) {
        if ($_SESSION["currentView"] == 'All') {
            $row["Show"] = true;
        }
        else {
            $row["Show"] = ($_SESSION["currentView"] == $row["Condition"] || $_SESSION["currentView"] == $row["MediaType"]);
        }
    }
}

// filter view result table $_SESSION["resultArr"] for detailed filter selection
function detailFilterResults($selArr) {
    if (!empty($selArr['filterCondition'])) {
        foreach($_SESSION['AdditionalFilters']['Condition'] as $key => $value) {
            $_SESSION['AdditionalFilters']['Condition'][$key] = false;
        }
        if (!is_array($selArr['filterCondition'])) { $selArr['filterCondition'] = [ $selArr['filterCondition'] ];}
        foreach($selArr['filterCondition'] as $value) {
            $_SESSION['AdditionalFilters']['Condition'][$value] = true;
        }
    } else {
        $selArr['filterCondition'] = [];
        if (!empty($_SESSION['AdditionalFilters']['Condition'])) {
            foreach($_SESSION['AdditionalFilters']['Condition'] as $key => $value) {
                if ($value) {
                    $selArr['filterCondition'][] = $key;
                }
            }
        }
    }

    if (!empty($selArr['filterMediaType'])) {
        foreach($_SESSION['AdditionalFilters']['MediaType'] as $key => $value) {
            $_SESSION['AdditionalFilters']['MediaType'][$key] = false;
        }
        if (!is_array($selArr['filterMediaType'])) { $selArr['filterMediaType'] = [ $selArr['filterMediaType'] ];}
        foreach($selArr['filterMediaType'] as $value) {
            $_SESSION['AdditionalFilters']['MediaType'][$value] = true;
        }
    } else {
        $selArr['filterMediaType'] = [];
        if (!empty($_SESSION['AdditionalFilters']['MediaType'])) {
            foreach($_SESSION['AdditionalFilters']['MediaType'] as $key => $value) {
                if ($value) {
                    $selArr['filterMediaType'][] = $key;
                }
            }
        }
    }

    if (!empty($selArr['filterShipFrom'])) {
        foreach($_SESSION['AdditionalFilters']['ShippingFrom'] as $key => $value) {
            $_SESSION['AdditionalFilters']['ShippingFrom'][$key] = false;
        }
        if (!is_array($selArr['filterShipFrom'])) { $selArr['filterShipFrom'] = [ $selArr['filterShipFrom'] ];}
        foreach($selArr['filterShipFrom'] as $value) {
            $_SESSION['AdditionalFilters']['ShippingFrom'][$value] = true;
        }
    } else {
        $selArr['filterShipFrom'] = [];
        if (!empty($_SESSION['AdditionalFilters']['ShippingFrom'])) {
            foreach($_SESSION['AdditionalFilters']['ShippingFrom'] as $key => $value) {
                if ($value) {
                    $selArr['filterShipFrom'][] = $key;
                }
            }
        }
    }

    if (!empty($selArr['filterMerchant'])) {
        foreach($_SESSION['AdditionalFilters']['Merchant'] as $key => $value) {
            $_SESSION['AdditionalFilters']['Merchant'][$key] = false;
        }
        if (!is_array($selArr['filterMerchant'])) { $selArr['filterMerchant'] = [ $selArr['filterMerchant'] ];}
        foreach($selArr['filterMerchant'] as $value) {
            $_SESSION['AdditionalFilters']['Merchant'][$value] = true;
        }
    } else {
        $selArr['filterMerchant'] = [];
        if (!empty($_SESSION['AdditionalFilters']['Merchant'])) {
            foreach($_SESSION['AdditionalFilters']['Merchant'] as $key => $value) {
                if ($value) {
                    $selArr['filterMerchant'][] = $key;
                }
            }
        }
    }

    foreach ($_SESSION["resultArr"] as & $row) {
        $row["Show"] = true;

        if (!in_array($row["Condition"], $selArr['filterCondition']) ||
            !in_array($row["MediaType"], $selArr['filterMediaType']) ||
            !in_array($row["Merchant"], $selArr['filterMerchant']) ||
            !in_array($row["Country"], $selArr['filterShipFrom'])) {
            $row["Show"] = false;
        }
    }
}

function resetDetailFilter() {
    if (isset($_SESSION['AdditionalFilters']['Merchant'])) {
        foreach($_SESSION['AdditionalFilters']['Merchant'] as $key => $field) {
            $_SESSION['AdditionalFilters']['Merchant'][$key] = true;
        }
    }

    if (isset($_SESSION['AdditionalFilters']['Seller'])) {
        foreach($_SESSION['AdditionalFilters']['Seller'] as $key => $field) {
            $_SESSION['AdditionalFilters']['Seller'][$key] = true;
        }
    }

    if (isset($_SESSION['AdditionalFilters']['Condition'])) {
        foreach($_SESSION['AdditionalFilters']['Condition'] as $key => $field) {
            $_SESSION['AdditionalFilters']['Condition'][$key] = true;
        }
    }

    if (isset($_SESSION['AdditionalFilters']['DetailCondition'])) {
        foreach($_SESSION['AdditionalFilters']['DetailCondition'] as $key => $field) {
            $_SESSION['AdditionalFilters']['DetailCondition'][$key] = true;
        }
    }

    if (isset($_SESSION['AdditionalFilters']['ShippingFrom'])) {
        foreach($_SESSION['AdditionalFilters']['ShippingFrom'] as $key => $field) {
            $_SESSION['AdditionalFilters']['ShippingFrom'][$key] = true;
        }
    }

    if (isset($_SESSION['AdditionalFilters']['MediaType'])) {
        foreach($_SESSION['AdditionalFilters']['MediaType'] as $key => $field) {
            $_SESSION['AdditionalFilters']['MediaType'][$key] = true;
        }
    }
    
    foreach ($_SESSION["resultArr"] as & $row) {
        $row["Show"] = true;
    }
}

// print result table or card deck
function printResult() {
    if ($_SESSION["currentLayout"] == 'TableView') {
        return buildTable($_SESSION["resultArr"]);
    }
    else /* CardView */ {
        return buildCardDeck($_SESSION["resultArr"]);
    }
}

// build HTML table from array
function buildTable($arr) {
    global $mediaTypeTextArr;
    global $mediaTypeIconArr;

    $str = "";

    if (count($arr) > 0) {
        $str .= "<div class=\"table\">"; // bugbug responsive?
        $str .= "<table class=\"table table-striped table-condensed table-hover small bg-info\">";
        $str .= "<thead class=\"thead-dark table-header-sticky\"><tr><th>Image</th><th class=\"text-left\">Title / Merchant</th><th>Condition</th><th class=\"hide-small\">Price</th><th class=\"hide-small\">S/H</th><th>Total</th><th class=\"hide-extra-small\"></th></tr></thead>";
        $str .= "<tbody>";

        foreach ($arr as $row) {
            if (!$row["Show"]) {
                continue;
            }

            $href = "href=\"" . $row["URL"] . "\" target=\"_blank\" onclick=\"saveTransfer('" . $row["URL"] . "'); return true;\"";
            $title = $row["Title"];
            if (mb_strlen($row["Title"], 'UTF-8') > MAXTITLELENGTH) {
                $title = mb_substr($row["Title"], 0, MAXTITLELENGTH, 'UTF-8') . '...';
            }

            $str .= "<tr>";

            // Image
            $str .= "<td><a " . $href . " data-toggle=\"tooltip\" title=\"Buy It Now\"><img class=\"img-fluid\" src=\"" . $row["Image"] . "\" alt=\"Item Image\"></a></td>";

            // Title / Merchant
            $str .= "<td class=\"text-left\"><span class=\"font-weight-bold\"><a class=\"bg-info\" " . $href . " data-toggle=\"tooltip\" title=\"Buy It Now\">" . $title . "</a></span>";
            $str .= "<br/><br/>";
            $str .= "<span class=\"font-weight-bold\">" . $row["Merchant"] . "</span>";
            if ($row["FeedbackScore"] != - 1) {
                $str .= "<span class=\"hide-extra-small\"><br/>" . $row["SellerName"] . " (" . number_format($row["FeedbackScore"], 0, "", ",") . " / " . $row["FeedbackPercent"] . "%)</span>";
            }
            else if (!empty($row["SellerName"])) {
                $str .= "<span class=\"hide-extra-small\"><br/>" . $row["SellerName"] . "</span>";
            }
            if (!empty($row["TimeLeft"])) {
                $str .= "<br>" . $row["TimeLeft"];
            }
            $str .= "</td>";

            // Condition
            $str .= "<td>";
            $mediaTypeIcon = 'media-icon ' . $mediaTypeIconArr[$row["MediaType"]];
            $tooltip = $mediaTypeTextArr[$row["MediaType"]];
            $str .= "<span class=\"font-weight-bold\">" . $row["DetailCondition"] . "</span>";
            $str .= "<br/><br/>";
            $str .= "<i class=\"" . $mediaTypeIcon . "\" title=\"" . $tooltip . "\" data-toggle=\"tooltip\" data-placement=\"right\" data-delay=\"200\"></i>";
            $str .= "</td>";

            // Price
            $str .= "<td class=\"hide-small\">" . print_monetary($row["Price"], $row["Currency"]);
            if ($row["Currency"] != $_SESSION["buyer"]["Currency"]) {
                $str .= "<br/>&asymp; " . print_monetary($row["ConvertedPrice"], $_SESSION["buyer"]["Currency"]);
            }
            if ($row["BestOffer"] == "true") {
                $str .= "<br>Best Offer Accepted";
            }
            $str .= "</td>";

            // Shipping and Handling Cost
            $str .= "<td class=\"hide-small\">";
            if ($row["ShippingCost"] == 0.00) {
                $str .= "Free Shipping";
            }
            else {
                $str .= print_monetary($row["ShippingCost"], $row["ShippingCurrency"]);
                if ($row["ShippingEstimated"]) {
                    $str .= "*";
                }
            }
            if ($row["ShippingCost"] > 0.00 && $row["ShippingCurrency"] != $_SESSION["buyer"]["Currency"]) {
                $str .= "<br/>&asymp; " . print_monetary($row["ConvertedShippingCost"], $_SESSION["buyer"]["Currency"]);
            }
            if ($row["HandlingTime"] > 0) {
                $str .= "<br>Handling Time " . $row["HandlingTime"] . " day" . ($row["HandlingTime"] > 1 ? "s" : "");
            }
            if ($row["ShippingCost"] > 0.00 && $row["FreeShippingCap"] > 0) {
                $str .= "<br>Free Shipping over " . print_monetary($row["FreeShippingCap"], $_SESSION["buyer"]["Currency"]);
            }
            $str .= "<br/><img class=\"img-fluid\" title=\"Ships from " . getCountry($row["Country"]) . "\" data-toggle=\"tooltip\" data-placement=\"right\" data-delay=\"200\" src=\"/images/flags/" . $row["Country"] . ".png\" alt=\"" . getCountry($row["Country"]) . " Flag\"></td>";

            // Total Price
            $str .= "<td class=\"font-weight-bolder\">" . print_monetary($row["ConvertedTotalPrice"], $_SESSION["buyer"]["Currency"]) . "</td>";

            // Link
            if ($row["Merchant"] == "iTunes") {
                if ($row["MediaType"] == "Digital") {
                    $badge = "images/US-UK_Apple_Music_Badge_RGB.svg";
                }
                else {
                    $badge = "images/US_UK_Apple_Books_Badge_Get_RGB_071818.svg";
                }
                $linkImage = "<a class=\"btn\" role=\"button\" " . $href . "><img class=\"img-fluid\" src=\"" . $badge . "\" alt=\"iTunes Badge\"></a>";
            } else if (strpos($row["Merchant"], "eBay") !== false) {
                $linkImage = "<a class=\"btn\" role=\"button\" " . $href . "><img class=\"img-fluid\" src=\"images/ebay-right-now.gif\" alt=\"iTunes Badge\"></a>";
            } else if (strpos($row["Merchant"], "Amazon") !== false) {
                $linkImage = "<a class=\"btn\" role=\"button\" " . $href . "><img class=\"img-fluid\" src=\"images/amazon-buy3.gif\" alt=\"iTunes Badge\"></a>";
            } else {
                $linkImage = "<a class=\"btn btn-danger\" role=\"button\" " . $href . "><i class=\"fas fa-shopping-cart btn-shop\"></i><span class=\"hide-small\"><br>Buy It Now</span></a>";
            }
            $str .= "<td class=\"hide-extra-small text-center\">" . $linkImage . "</td>";

            $str .= "</tr>";
        }

        $str .= "</tbody>";
        $str .= "<tfoot class=\"text-right\"><tr><td class=\"font-italic\" colspan=\"7\">Prices retrieved on " . gmdate("Y-m-d H:i") . " UTC<br>Daily exchange rates update</td></tr></tfoot>";
        $str .= "</table>";
        $str .= "</div>";
    }
    else {
        $str = printNoResultsWarning();
    }

    return ($str);
}

// build HTML card deck from array
function buildCardDeck($arr) {
    global $mediaTypeTextArr;
    global $mediaTypeIconArr;

    $str = "";

    if (count($arr) > 0) {
        $str .= "<div class=\"card-deck small\">";

        foreach ($arr as $row) {
            if (!$row["Show"]) {
                continue;
            }

            $href = "href=\"" . $row["URL"] . "\" target=\"_blank\" onclick=\"saveTransfer('" . $row["URL"] . "'); return true;\"";
            $title = $row["Title"];
            if (mb_strlen($row["Title"], 'UTF-8') > MAXTITLELENGTH) {
                $title = mb_substr($row["Title"], 0, MAXTITLELENGTH, 'UTF-8') . '...';
            }

            $str .= "<div class=\"card m-2 shadow mx-auto result-card\">";

            // Image
            $str .= "<a class=\"p-0 m-0 bg-light text-center result-image\" " . $href . " data-toggle=\"tooltip\" title=\"Buy It Now\"><img class=\"p-0 m-0 responsive-image\" src=\"" . $row["Image"] . "\" alt=\"Item Image\"></a>";

            $str .= "<div class=\"card-body bg-light d-flex flex-column\">";
            // Title / Merchant
            $str .= "<p class=\"card-title font-weight-bold\"><a " . $href . " data-toggle=\"tooltip\" title=\"Buy It Now\">" . $title . "</a></p>";
            $str .= "<div class=\"card-text mt-auto\"><span class=\"font-weight-bold\">" . $row["Merchant"] . "</span>";
            $str .= "<br>";

            // Condition / MediaType
            $mediaTypeIcon = 'media-icon ' . $mediaTypeIconArr[$row["MediaType"]];
            $tooltip = $mediaTypeTextArr[$row["MediaType"]];
            $str .= $row["DetailCondition"];
            $str .= "<i class=\"float-right " . $mediaTypeIcon . "\" title=\"" . $tooltip . "\" data-toggle=\"tooltip\" data-placement=\"right\" data-delay=\"200\"></i>";
            $str .= "<br>";

            // Total Price
            $str .= "<span class=\"font-weight-bolder\">" . print_monetary($row["ConvertedTotalPrice"], $_SESSION["buyer"]["Currency"]) . "</span>";
            $str .= "</div>";

            $str .= "</div>";

            // Link / Ships from Flag
            $str .= "<div class=\"card-footer bg-dark\">";
            $str .= "<div class=\"row\">";
            $str .= "<div class=\"col-9\">";
            if ($row["Merchant"] == "iTunes") {
                if ($row["MediaType"] == "Digital") {
                    $badge = "images/US-UK_Apple_Music_Badge_RGB.svg";
                }
                else {
                    $badge = "images/US_UK_Apple_Books_Badge_Get_RGB_071818.svg";
                }
                $linkImage = "<a class=\"btn p-0 m-0\" role=\"button\" " . $href . "><img class=\"img-fluid p-0 m-0\" src=\"" . $badge . "\" alt=\"iTunes Badge\"></a>";
            } else if (strpos($row["Merchant"], "eBay") !== false) {
                $linkImage = "<a class=\"btn p-0 m-0\" role=\"button\" " . $href . "><img class=\"img-fluid p-0 m-0\" src=\"images/ebay-right-now.gif\" alt=\"iTunes Badge\"></a>";
            } else if (strpos($row["Merchant"], "Amazon") !== false) {
                $linkImage = "<a class=\"btn p-0 m-0\" role=\"button\" " . $href . "><img class=\"img-fluid p-0 m-0\" src=\"images/amazon-buy3.gif\" alt=\"iTunes Badge\"></a>";
            }
            else {
                $linkImage = "<a class=\"btn btn-danger m-0\" role=\"button\" " . $href . "><i class=\"fas fa-shopping-cart\"></i></a>";
            }
            $str .= $linkImage;
            $str .= "</div>";
            $str .= "<div class=\"col-3\">";
            $str .= "<img class=\"float-right\" title=\"Ships from " . getCountry($row["Country"]) . "\" data-toggle=\"tooltip\" data-placement=\"right\" data-delay=\"200\" src=\"/images/flags/" . $row["Country"] . ".png\" alt=\"" . getCountry($row["Country"]) . " Flag\">";
            $str .= "</div>";
            $str .= "</div>";
            $str .= "</div>";

            $str .= "</div>";
        }

        $str .= "</div>";
        $str .= "<div class=\"py-2 text-right\"><p class=\"font-italic\">Prices retrieved on " . gmdate("Y-m-d H:i") . " UTC<br>Daily exchange rates update</p></div>";
    }
    else {
        $str = printNoResultsWarning();
    }

    return ($str);
}

// print directions when no results are found
function printNoResultsWarning() {
    $str = "<div class=\"text-center bg-warning p-3 rounded\">";
    $str .= "<p class=\"display-5 font-weight-bold\">Your search returned no results</p>";
    $str .= "<p>You may want to try the following:</p>";
    $str .= "<ul><li>Check the spelling</li><li>Try using fewer words</li><li>Check the search filter (<i class=\"fas fa-filter\"></i>) if you used one</li><li>Try using artist and title if you used a barcode; some albums have been released under various barcodes</li></ul>";
    $str .= "</div>";

    return $str;
}

function printResultHeader() {
    $str = '';
    $str .= '<nav class="navbar bg-black mt-2 pb-0">';
    $str .= '<ul class="nav nav-tabs">';
    $str .= '  <li class="nav-item border-0">';
    $str .= '    <a id="quickTab" class="nav-link';
    $str .= ($_SESSION["currentView"] == 'Apply' ? ' bg-white invert' : ' active bg-white') . '" href="#quickFilter">Quick</a>';
    $str .= '  </li>';
    $str .= '  <li class="nav-item border-0">';
    $str .= '    <a id="detailTab" class="nav-link';
    $str .= ($_SESSION["currentView"] == 'Apply' ? ' active bg-white' : ' bg-white invert') . '" href="#detailFilter">Detailed</a>';
    $str .= '  </li>';
    $str .= '</ul>';
    $str .= '<span class="ml-auto">';
    $str .= '    <button name="submit" value="TableView" type="' . getButtonType("TableView") . '" class="btn btn-sm filterButtonSmall ' . getBackgroundColor("TableView") . '"';
    $str .= ' data-toggle="tooltip" title="Table View" onclick="$(this).tooltip(\'hide\');"><span class="display-6 font-weight-bolder"><i class="fas fa-th-list"></i></span></button>';
    $str .= '    <button name="submit" value="CardView" type="' . getButtonType("CardView") . '" class="btn btn-sm filterButtonSmall ' . getBackgroundColor("CardView") . '"';
    $str .= ' data-toggle="tooltip" title="Card View" onclick="$(this).tooltip(\'hide\');"><span class="display-6 font-weight-bolder"><i class="fas fa-th-large"></i></span></button>';
    $str .= '</span>';
    $str .= '<span class="navbar-text text-white float-right ml-3">Showing ' . count(array_filter($_SESSION["resultArr"], function ($entry) { return ($entry['Show'] === true); })) . ' of ' . count($_SESSION["resultArr"]) . '</span>';
    $str .= '</nav>';
    $str .= '<div class="tab-content mb-3 bg-white">';
    $str .= '  <div id="quickFilter" class="tab-pane';
    $str .= ($_SESSION["currentView"] == 'Apply' ? '' : ' active') . '"><br>';
    $str .= resultHeader();
    $str .= '  </div>';
    $str .= '  <div id="detailFilter" class="container tab-pane';
    $str .= ($_SESSION["currentView"] == 'Apply' ? ' active' : ' bg-white') . '"><br>';
    $str .= detailResultHeader();
    $str .= '  </div>';
    $str .= '</div>';

  return $str;
}

// print summary/header on top of listing table
function resultHeader() {
    $str = '<div class="d-flex flex-wrap justify-content-center p-2">';
    $str .= '    <button name="submit" value="All" type="' . getButtonType("All") . '" class="btn mx-2 filterButton ' . getBackgroundColor("All") . '"';
    if ($_SESSION["lowestPrice"]["All"] <= 0) {
        $str .= ' disabled';
    }
    $str .= '><span class="display-6 font-weight-bolder">All</span><span class="display-7"> from</span><br><span class="display-6 font-weight-bolder">' . print_monetary($_SESSION["lowestPrice"]["All"], $_SESSION["buyer"]["Currency"]) . '</span>';
    $str .= '    <span class="badge">' . (isset($_SESSION['AdditionalFilterCounters']['Condition']['All']) ? $_SESSION['AdditionalFilterCounters']['Condition']['All'] : '') . '</span></button>';
    $str .= '    <button name="submit" value="New" type="' . getButtonType("New") . '" class="btn mx-2 filterButton ' . getBackgroundColor("New") . '"';
    if ($_SESSION["lowestPrice"]["New"] <= 0) {
        $str .= ' disabled';
    }
    $str .= '><span class="display-6 font-weight-bolder">New</span><span class="display-7"> from</span><br><span class="display-6 font-weight-bolder">' . print_monetary($_SESSION["lowestPrice"]["New"], $_SESSION["buyer"]["Currency"]) . '</span>';
    $str .= '    <span class="badge">' . (isset($_SESSION['AdditionalFilterCounters']['Condition']['New']) ? $_SESSION['AdditionalFilterCounters']['Condition']['New'] : '') . '</span></button>';
    $str .= '    <button name="submit" value="Used" type="' . getButtonType("Used") . '" class="btn mx-2 filterButton ' . getBackgroundColor("Used") . '"';
    if ($_SESSION["lowestPrice"]["Used"] <= 0) {
        $str .= ' disabled';
    }
    $str .= '><span class="display-6 font-weight-bolder">Used</span><span class="display-7"> from</span><br><span class="display-6 font-weight-bolder">' . print_monetary($_SESSION["lowestPrice"]["Used"], $_SESSION["buyer"]["Currency"]) . '</span>';
    $str .= '    <span class="badge">' . (isset($_SESSION['AdditionalFilterCounters']['Condition']['Used']) ? $_SESSION['AdditionalFilterCounters']['Condition']['Used'] : '') . '</span></button>';

    $str .= '</div>';

    return $str;
}

function detailResultHeader() {
    global $mediaTypeTextArr;
    global $mediaTypeIconArr;

    $str = '';
    $str .= '            <form id="detailFilterForm">';
    $str .= '                <input type="hidden" name="sessionTab" value="' . MySessionHandler::getSessionTab() . '">';
    $str .= '                <div class="">';
    $str .= '                    <div class="card-group">';
    $str .= '';

    // Condition
    if (isset($_SESSION['AdditionalFilterCounters']['Condition'])) {
        $str .= '                        <div class="card m-2">';
        $str .= '                            <div class="card-header font-weight-bold">Condition</div>';
        $str .= '                            <div class="card-body">';
        $cnt = count($_SESSION['AdditionalFilterCounters']['Condition']);
        foreach($_SESSION['AdditionalFilters']['Condition'] as $key => $value) {
            $str .= '                                <div class="form-check">';
            $str .= '                                    <label class="form-check-label">';
            $str .= '                                        <input name="filterCondition[]" type="checkbox" value="' . $key . '" class="form-check-input"';
            $str .= ($value ? " checked" : "");
            $str .= ($cnt > 2 ? "" : " disabled");
            $str .= '>' . $key . '<span class="badge badge-pill badge-dark ml-2">' . $_SESSION['AdditionalFilterCounters']['Condition'][$key] . '</span>';
            $str .= '                                    </label>';
            $str .= '                                </div>';
        }
        $str .= '                            </div>';
        $str .= '                        </div>';
    }

    // Media Type
    if (isset($_SESSION['AdditionalFilterCounters']['MediaType'])) {
        $str .= '                        <div class="card m-2">';
        $str .= '                            <div class="card-header font-weight-bold">Media Type</div>';
        $str .= '                            <div class="card-body">';
        $cnt = count($_SESSION['AdditionalFilterCounters']['MediaType']);
        foreach($_SESSION['AdditionalFilters']['MediaType'] as $key => $value) {
            $str .= '                                <div class="form-check">';
            $str .= '                                    <label class="form-check-label">';
            $str .= '                                        <input name="filterMediaType[]" type="checkbox" value="' . $key . '" class="form-check-input"';
            $str .= ($value ? " checked" : "");
            $str .= ($cnt > 1 ? "" : " disabled");
            $str .= '><i class="' . $mediaTypeIconArr[$key] . '"></i> ' . $mediaTypeTextArr[$key];
            $str .= '<span class="badge badge-pill badge-dark ml-2">' . $_SESSION['AdditionalFilterCounters']['MediaType'][$key] . '</span>';
            $str .= '                                    </label>';
            $str .= '                                </div>';
        }
        $str .= '                            </div>';
        $str .= '                        </div>';
    }

    // Merchant
    if (isset($_SESSION['AdditionalFilterCounters']['Merchant'])) {
        $str .= '                        <div class="card m-2">';
        $str .= '                            <div class="card-header font-weight-bold">Merchant</div>';
        $str .= '                            <div class="card-body">';
        $cnt = count($_SESSION['AdditionalFilterCounters']['Merchant']);
        foreach($_SESSION['AdditionalFilters']['Merchant'] as $key => $value) {
            $str .= '                                <div class="form-check">';
            $str .= '                                    <label class="form-check-label">';
            $str .= '                                        <input name="filterMerchant[]" type="checkbox" value="' . $key . '" class="form-check-input"';
            $str .= ($value ? " checked" : "");
            $str .= ($cnt > 1 ? "" : " disabled");
            $str .= '>' . $key . '<span class="badge badge-pill badge-dark ml-2">' . $_SESSION['AdditionalFilterCounters']['Merchant'][$key] . '</span>';
            $str .= '                                    </label>';
            $str .= '                                </div>';
        }
        $str .= '                            </div>';
        $str .= '                        </div>';
    }

    // Shipping From
    if (isset($_SESSION['AdditionalFilterCounters']['ShippingFrom'])) {
        $str .= '                        <div class="card m-2">';
        $str .= '                            <div class="card-header font-weight-bold">Shipping From</div>';
        $str .= '                            <div class="card-body">';
        $cnt = count($_SESSION['AdditionalFilterCounters']['ShippingFrom']);
        foreach($_SESSION['AdditionalFilters']['ShippingFrom'] as $key => $value) {
            $str .= '                                <div class="form-check">';
            $str .= '                                    <label class="form-check-label">';
            $str .= '                                        <input name="filterShipFrom[]" type="checkbox" value="' . $key . '" class="form-check-input"';
            $str .= ($value ? " checked" : "");
            $str .= ($cnt > 1 ? "" : " disabled");
            $str .= '><img class="img-fluid" title="Ships from ' . getCountry($key) . '" data-toggle="tooltip" data-delay="200" src="/images/flags/' . $key . '.png" alt="' . getCountry($key) . ' Flag"><span class="badge badge-pill badge-dark ml-2">' . $_SESSION['AdditionalFilterCounters']['ShippingFrom'][$key] . '</span>';
            $str .= '                                    </label>';
            $str .= '                                </div>';
        }
        $str .= '                            </div>';
        $str .= '                        </div>';
    }

    $str .= '                    </div>';
    $str .= '                </div>';
    $str .= '';
    $str .= '                <div class="p-2">';
    $str .= '                    <button type="submit" class="btn btn-success detailFilterButton" name="submit" value="Apply">Apply</button>';
    $str .= '                    <button type="submit" class="btn btn-danger detailFilterButton" name="submit" value="Reset">Reset</button>';
    $str .= '                </div>';
    $str .= '            </form>';

    return $str;
}

// get top button background color
function getBackgroundColor($sel) {
    if ($_SESSION["currentView"] == $sel || $_SESSION["currentLayout"] == $sel) {
        return ("btn-primary active");
    }

    return ("btn-primary invert");
}

// get top button type
function getButtonType($sel) {
    if ($_SESSION["currentView"] == $sel || $_SESSION["currentLayout"] == $sel) {
        return ("button");
    }

    return ("submit");
}

// compare price for sort low to high
function compare_price($a, $b) {
    return strnatcmp($a['ConvertedTotalPrice'], $b['ConvertedTotalPrice']);
}

// print monetary values with correct symbol and thousands/decimal delimiters
function print_monetary($num, $curr) {
    if ($curr == "USD") {
        return ("$" . number_format($num, 2, '.', ','));
    }
    else if ($curr == "CAD") {
        return ("C $" . number_format($num, 2, '.', ','));
    }
    else if ($curr == "EUR") {
        return (number_format($num, 2, ',', '.') . "&euro;");
    }
    else if ($curr == "GBP") {
        return ("&pound;" . number_format($num, 2, '.', ','));
    }
    else if ($curr == "AUD") {
        return ("AU $" . number_format($num, 2, '.', ','));
    }

    return ($curr . " " . number_format($num, 2, '.', ','));
}

// find lowest used / new prices
function findLowestCondition($condition) {
    foreach ($_SESSION["resultArr"] as $row) {
        if (!$row["Show"]) {
            continue;
        }

        if ($condition == $row["Condition"]) {
            return ($row["ConvertedTotalPrice"]);
        }
    }

    return (0);
}

// find lowest cd, record, digital and book prices
function findLowestMediaType($mediaType) {
    foreach ($_SESSION["resultArr"] as $row) {
        if (!$row["Show"]) {
            continue;
        }

        if ($mediaType == $row["MediaType"]) {
            return ($row["ConvertedTotalPrice"]);
        }
    }

    return (0);
}

// find lowest non-zero double value in array
function minNotNull(Array $values) {
    return min(array_diff(array_map('doubleval', $values) , array(
        0
    )));
}

// apply exchange rates
function applyExchangeRates($arr) {
    foreach ($arr as & $value) {
        $value["ConvertedPrice"] = $value["Price"];
        $value["ConvertedShippingCost"] = $value["ShippingCost"];

        if ($_SESSION["buyer"]["Currency"] != $value["Currency"]) {
            $value["ConvertedPrice"] = number_format($value["Price"] / getExchangeRate($_SESSION["buyer"]["Currency"], $value["Currency"]) , 2, '.', '');
        }

        if ($_SESSION["buyer"]["Currency"] != $value["ShippingCurrency"]) {
            $value["ConvertedShippingCost"] = number_format($value["ShippingCost"] / getExchangeRate($_SESSION["buyer"]["Currency"], $value["ShippingCurrency"]) , 2, '.', '');
        }

        $value["ConvertedTotalPrice"] = number_format($value["ConvertedPrice"] + $value["ConvertedShippingCost"], 2, '.', '');
    }

    return ($arr);
}

// sanitize user input
function sanitizeInput($data) {
    $data = trim(preg_replace('/[\t\n\r\s]+/', ' ', $data));
    $data = stripslashes($data);
    $data = htmlspecialchars($data);
    return $data;
}

// sanitize user input (plus delete apostrophe)
function sanitizeInput2($data) {
    $data = trim(preg_replace('/[\t\n\r\s\']+/', ' ', $data));
    $data = stripslashes($data);
    $data = htmlspecialchars($data, ENT_QUOTES | ENT_HTML5);
    return $data;
}

// convert certain utf-8 characters to ascii
function cleanString($str) {
    $utf8 = array(
        '/[áàâãªä]/u' => 'a',
        '/[ÁÀÂÃÄ]/u' => 'A',
        '/[ÍÌÎÏ]/u' => 'I',
        '/[íìîï]/u' => 'i',
        '/[éèêë]/u' => 'e',
        '/[ÉÈÊË]/u' => 'E',
        '/[óòôõºö]/u' => 'o',
        '/[ÓÒÔÕÖ]/u' => 'O',
        '/[úùûü]/u' => 'u',
        '/[ÚÙÛÜ]/u' => 'U',
        '/ç/' => 'c',
        '/Ç/' => 'C',
        '/ñ/' => 'n',
        '/Ñ/' => 'N',
        '/–/' => '-', // UTF-8 hyphen to "normal" hyphen
        '/[’‘‹›‚]/u' => ' ', // Literally a single quote
        '/[“”«»„]/u' => ' ', // Double quote
        '/ /' => ' ', // nonbreaking space (equiv. to 0x160)

    );

    return preg_replace(array_keys($utf8) , array_values($utf8) , $str);
}

// Clean the search string
function searchFriendlyString($str) {
    $str = strip_tags($str);
    $str = stripslashes($str);
    $str = cleanString($str);
    $str = str_replace(array(
        "[",
        "]",
        "<",
        ">",
        "(",
        ")",
        " - ",
        " & ",
        " / "
    ) , " ", $str); // eliminate single '-', '&', '/' and brackets
    $str = trim(preg_replace('/[\t\n\r\s]+/', ' ', $str)); // delete extra whitespaces
    return ucwords($str);
}

// get a SESSION value, return empty string if not set
function getSV($var) {
    if (!isset($_SESSION[$var])) {
        return ('');
    }

    return ($_SESSION[$var]);
}

// initialize a SESSION value if not set
function initSV($var, $value) {
    if (!isset($_SESSION[$var])) {
        $_SESSION[$var] = $value;
    }
}

// initialize sessions variables
function initSessionVariables() {
    initSV("resultArr", []);
    initSV("barcode", array(
        "Type" => "",
        "Value" => ""
    ));
    initSV("buyer", array(
        "Country" => "United States",
        "Currency" => "USD",
        "Zip" => ""
    ));
    initSV("filterCondition", array(
        "New" => true,
        "Used" => true
    ));
    initSV("filterMediaType", array(
        "CD" => true,
        "Record" => true,
        "Digital" => true,
        "Book" => true
    ));
    initSV("currentView", "All");
    initSV("currentLayout", "TableView");
    initSV("lowestPrice", array(
        "Used" => 0.00,
        "New" => 0.00,
        "CD" => 0.00,
        "Record" => 0.00,
        "Digital" => 0.00,
        "Book" => "0.00",
        "All" => 0.00
    ));
    initSV("filterWarnings", "");
    initSV("md5LastSearch", "");
}

function md5SearchTerm() {
    $data = array();
    $data['cond'] = $_SESSION['filterCondition'];
    $data['type'] = $_SESSION['filterMediaType'];
    $data['buyer'] = $_SESSION['buyer'];
    $data['term'] = array(
        $_SESSION['searchTerm']
    );

    return (md5(json_encode($data)));
}

// check POST value, return true if set and false if not
function checkPV($var) {
    if (isset($_POST[$var])) {
        return (true);
    }

    return (false);
}

// get POST or GET value, return empty if not set
function getPGV($var) {
    if (isset($_POST[$var])) {
        return ($_POST[$var]);
    }
    else if (isset($_GET[$var])) {
        return ($_GET[$var]);
    }

    return ("");
}

// print search filter modal with current selection
function printSearchFilterModal() {
    global $mediaTypeTextArr;
    global $mediaTypeIconArr;

    $str = '';
    $str .= '<div class="modal fade" id="filterModal">';
    $str .= '    <div class="modal-dialog">';
    $str .= '        <div class="modal-content">';
    $str .= '';
    $str .= '            <div class="modal-header bg-primary">';
    $str .= '                <h4 class="modal-title">Search Filters</h4>';
    $str .= '            </div>';
    $str .= '';
    $str .= '            <form method="post" action="/index.php" onsubmit="progressBar(\'Applying Modified Search Filter...\');">';
    $str .= '                <input type="hidden" name="sessionTab" value="' . MySessionHandler::getSessionTab() . '">';
    $str .= '                <div class="modal-body">';
    $str .= '                    <div class="card-group">';
    $str .= '';
    $str .= '                        <div class="card m-2">';
    $str .= '                            <div class="card-header font-weight-bold">Condition</div>';
    $str .= '                            <div class="card-body">';
    $str .= '                                <div class="form-check">';
    $str .= '                                    <label class="form-check-label">';
    $str .= '                                        <input name="filterCondition[]" type="checkbox" class="form-check-input" value="New"' . ($_SESSION["filterCondition"]["New"] ? " checked" : "") . '>New';
    $str .= '                                    </label>';
    $str .= '                                </div>';
    $str .= '                                <div class="form-check">';
    $str .= '                                    <label class="form-check-label">';
    $str .= '                                        <input name="filterCondition[]" type="checkbox" class="form-check-input" value="Used"' . ($_SESSION["filterCondition"]["Used"] ? " checked" : "") . '>Used';
    $str .= '                                    </label>';
    $str .= '                                </div>';
    $str .= '                            </div>';
    $str .= '                        </div>';
    $str .= '';
    $str .= '                        <div class="card m-2">';
    $str .= '                            <div class="card-header font-weight-bold">Media Type</div>';
    $str .= '                            <div class="card-body">';
    $str .= '                                <div class="form-check">';
    $str .= '                                    <label class="form-check-label">';
    $str .= '                                        <input name="filterMediaType[]" type="checkbox" class="form-check-input" value="CD"' . ($_SESSION["filterMediaType"]["CD"] ? " checked" : "") . '><i class="' . $mediaTypeIconArr["CD"] . '"></i> ' . $mediaTypeTextArr["CD"];
    $str .= '                                    </label>';
    $str .= '                                </div>';
    $str .= '                                <div class="form-check">';
    $str .= '                                    <label class="form-check-label">';
    $str .= '                                        <input name="filterMediaType[]" type="checkbox" class="form-check-input" value="Record"' . ($_SESSION["filterMediaType"]["Record"] ? " checked" : "") . '><i class="' . $mediaTypeIconArr["Record"] . '"></i> ' . $mediaTypeTextArr["Record"];
    $str .= '                                    </label>';
    $str .= '                                </div>';
    $str .= '                                <div class="form-check">';
    $str .= '                                    <label class="form-check-label">';
    $str .= '                                        <input name="filterMediaType[]" type="checkbox" class="form-check-input" value="Digital"' . ($_SESSION["filterMediaType"]["Digital"] ? " checked" : "") . '><i class="' . $mediaTypeIconArr["Digital"] . '"></i> ' . $mediaTypeTextArr["Digital"];
    $str .= '                                    </label>';
    $str .= '                                </div>';
    $str .= '                                <div class="form-check">';
    $str .= '                                    <label class="form-check-label">';
    $str .= '                                        <input name="filterMediaType[]" type="checkbox" class="form-check-input" value="Book"' . ($_SESSION["filterMediaType"]["Book"] ? " checked" : "") . '><i class="' . $mediaTypeIconArr["Book"] . '"></i> ' . $mediaTypeTextArr["Book"];
    $str .= '                                    </label>';
    $str .= '                                </div>';
    $str .= '                            </div>';
    $str .= '                        </div>';
    $str .= '                    </div>';
    $str .= '                </div>';
    $str .= '';
    $str .= '                <div class="modal-footer bg-primary">';
    $str .= '                    <input id="tempSearchTerm" type="hidden" name="searchTerm" value="">';
    $str .= '                    <button type="submit" class="btn btn-success" name="submit" value="Save" onclick="document.getElementById(\'tempSearchTerm\').value = document.getElementById(\'searchTerm\').value;$(\'#filterModal\').modal(\'hide\');">Save</button>';
    $str .= '                    <button type="button" class="btn btn-danger" data-dismiss="modal">Close</button>';
    $str .= '                </div>';
    $str .= '            </form>';
    $str .= '        </div>';
    $str .= '    </div>';
    $str .= '</div>';

    return ($str);
}

// print search info modal
function printSearchInfoModal() {
    global $mediaTypeTextArr;
    global $mediaTypeIconArr;

    $str = '';
    $str .= '<div class="modal fade" id="searchInfoModal">';
    $str .= '    <div class="modal-dialog">';
    $str .= '        <div class="modal-content">';
    $str .= '';
    $str .= '            <div class="modal-header bg-primary">';
    $str .= '                <h4 class="modal-title">Search Tips</h4>';
    $str .= '                <button type="button" class="close" data-dismiss="modal"><i class="fas fa-window-close btn-dismiss"></i></button>';
    $str .= '            </div>';
    $str .= '';
    $str .= '            <div class="modal-body bg-light text-dark">';
    $str .= '              <div class="shadow p-4 mb-4 bg-white">';
    $str .= '                <h4><i class="fas fa-filter"></i> Filter</h4>';
    $str .= '                <p><span class="font-weight-bold">Condition:</span>';
    $str .= '                    <br>Select "New" and / or "Used". The standard is to search for both.</p>';
    $str .= '                <p><span class="font-weight-bold">Media Type:</span>';
    $str .= '                    <br>Select <i class="' . $mediaTypeIconArr["CD"] . '"></i> "' . $mediaTypeTextArr["CD"] . '", <i class="' . $mediaTypeIconArr["Record"] . '"></i> "' . $mediaTypeTextArr["Record"] . '", <i class="' . $mediaTypeIconArr["Digital"] . '"></i> "' . $mediaTypeTextArr["Digital"] . '" and / or <i class="' . $mediaTypeIconArr["Book"] . '"></i> "' . $mediaTypeTextArr["Book"] . '". The standard is to search for all types.</p>';
    $str .= '              </div>';
    $str .= '              <div class="shadow p-4 mb-4 bg-white">';
    $str .= '                <h4><i class="fas fa-shipping-fast"></i> Shipping To</h4>';
    $str .= '                <p><span class="font-weight-bold">Country / Currency:</span>';
    $str .= '                    <br>At this time only "United States" / "USD" are supported. The exchange rates are updated daily.</p>';
    $str .= '                <p><span class="font-weight-bold">Zip Code:</span>';
    $str .= '                    <br>Enter your postal code to get the accurate shipping cost for items listed using a shipping rate table.</p>';
    $str .= '              </div>';
    $str .= '              <div class="shadow p-4 bg-white">';
    $str .= '                <h4><i class="fas fa-search"></i> Search Keywords</h4>';
    $str .= '                <p><span class="font-weight-bold">Barcode:</span>';
    $str .= '                    <br>The 12 or 13 digit barcode, normally located on the back, offers the best chance to find a specific album.</p>';
    $str .= '                <p><span class="font-weight-bold">Artist and Title:</span>';
    $str .= '                    <br>The full name of the album, including artist and title, will usually lead to a specific album.</p>';
    $str .= '                <p><span class="font-weight-bold">Just Artist or Title:</span>';
    $str .= '                    <br>Searches for artist or title alone will bring up multiple albums. You can later narrow your search further down, if necessary.</p>';
    $str .= '                    <p><span class="font-italic">The search algorithm prefers the barcode number whenever available. Since some albums have been released under various barcodes, try searching again for author and title should the barcode search come up empty.</span></p>';
    $str .= '              </div>';
    $str .= '            </div>';
    $str .= '            <div class="modal-footer bg-primary">';
    $str .= '                <button type="button" class="btn btn-danger" data-dismiss="modal">Close</button>';
    $str .= '            </div>';
    $str .= '        </div>';
    $str .= '    </div>';
    $str .= '</div>';

    return ($str);
}

function saveSearchResult() {
    $conn = MySessionHandler::getDBSessionId();

    $access = mysqli_real_escape_string($conn, time());
    // BUGBUG
    //  country
    //  currency
    $zip = mysqli_real_escape_string($conn, $_SESSION['buyer']['Zip']);
    $condNew = $_SESSION['filterCondition']['New'] ? 'Y' : 'N';
    $condUsed = $_SESSION['filterCondition']['Used'] ? 'Y' : 'N';
    $mediaCD = $_SESSION['filterMediaType']['CD'] ? 'Y' : 'N';
    $mediaRecord = $_SESSION['filterMediaType']['Record'] ? 'Y' : 'N';
    $mediaDigital = $_SESSION['filterMediaType']['Digital'] ? 'Y' : 'N';
    $mediaBook = $_SESSION['filterMediaType']['Book'] ? 'Y' : 'N';
    $data = mysqli_real_escape_string($conn, $_SESSION['searchTerm']);
    $lowNew = floatval($_SESSION['lowestPrice']['New']);
    $lowUsed = floatval($_SESSION['lowestPrice']['Used']);
    $lowDigital = floatval($_SESSION['lowestPrice']['Digital']);
    $lowBook = floatval($_SESSION['lowestPrice']['Book']);
    $count = count($_SESSION['resultArr']);
    $userId = (empty($_SESSION['sessData']['userID']) ? 'NULL' : $_SESSION['sessData']['userID']);

    $sql = "INSERT
                INTO searches
                (sessId, access, zip, condNew, condUsed, mediaCD, mediaRecord, mediaDigital, mediaBook, data, lowNew, lowUsed, lowDigital, lowBook, count, userId)
                VALUES ('" . session_id() . "', '$access', '$zip', '$condNew', '$condUsed', '$mediaCD', '$mediaRecord', '$mediaDigital', '$mediaBook', '$data', $lowNew, $lowUsed, $lowDigital, $lowBook, $count, $userId)";

    if (!($result = mysqli_query($conn, $sql))) {
        error_log("MySQL Write Searches Error: " . mysqli_error($conn) . " (" . mysqli_errno($conn) . ")");
    }

    return $result;
}

function getUrl($url, $userAgent = null) {
    $ch = curl_init();

    // Set request header with language and charset
    $header = array(
        "Accept-Language: en-US,en;q=0.5",
        "Accept-Charset: UTF-8,*;q=0.5"
    );
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

    // Set optional user-agent
    if ($userAgent) {
        curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
    }

    curl_setopt($ch, CURLOPT_ENCODING, "gzip,deflate");
    curl_setopt($ch, CURLOPT_AUTOREFERER, true);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_URL, $url);
    $response = curl_exec($ch);
    if ($response === false) {
        error_log('Curl Request Error: ' . curl_error($ch) . ' (' . curl_errno($ch) . ')');
        error_log('Url: ' . $url);
        $response = '';
    }

    curl_close($ch);

    return $response;
}

// Retrieve search history for current session id
function getSearchHistory() {
    $str = "";
    $sql = "select data, max(access) from searches where sessId = '" . session_id() . "'";
    if (!empty($_SESSION['sessData']['userID'])) {
        $sql .= " or userID = '" . $_SESSION['sessData']['userID'] . "'";
    }
    $sql .= " group by data order by max(access) desc, data limit 0,30;";
    $conn = MySessionHandler::getDBSessionId();

    if ($result = mysqli_query($conn, $sql)) {
        if (mysqli_num_rows($result) > 0) {
            while ($row = mysqli_fetch_assoc($result)) {
                $str .= "<option>" . $row["data"] . "</option>";
            }
        }
    }
    else if (mysqli_errno($conn)) {
        error_log("MySQL Read Searches SQL: " . $sql);
        error_log("MySQL Read Searches Error: " . mysqli_error($conn) . " (" . mysqli_errno($conn) . ")");
    }

    return $str;
}

// Retrieve coupons codes
function getCouponCodes() {
    $str = "";
    $lastAdvertiser = "";

    if (!isLoggedIn()) {
        return ("<h2>Please login to your Find Cheap Music account in order to see the coupons.</h2>");
    }

    $sql = 'select advertiser, date_format(enddate, "%M %e, %Y") as enddate, description, couponcode, url, pixel from coupons where DATE(NOW()) between startdate and enddate group by advertiser, description order by advertiser, id';
    $conn = MySessionHandler::getDBSessionId();

    if ($result = mysqli_query($conn, $sql)) {
        if (mysqli_num_rows($result) > 0) {
            $str .= "<div class=\"container py-4 bg-secondary border\">";
            while ($row = mysqli_fetch_assoc($result)) {
                if ($row["advertiser"] != $lastAdvertiser) {
                    if (!empty($lastAdvertiser)) {
                        $str .= "</ul>";
                    }
                    $str .= "<h3 class=\"bg-primary text-center mt-3 mb-1\">" . $row["advertiser"] . "</h3>";
                    $str .= "<ul class=\"list-group\">";
                    $lastAdvertiser = $row["advertiser"];
                }
                if (!empty($row["url"])) {
                    $str .= "<li class=\"list-group-item\"><a class=\"btn btn-link text-left\" target=\"_blank\" href=\"";
                    $str .= $row["url"];
                    $str .= "\">";
                    $str .= "<strong>" . $row["description"] . "</strong> until " . $row["enddate"];
                    if (!empty($row["couponcode"])) {
                        $str .= " (Use Coupon Code \"" . $row["couponcode"] . "\")";
                    }
                    $str .= "</a>";
                    if (!empty($row["pixel"])) {
                        $str .= "<img src=\"" . $row["pixel"] . "\" width=\"1\" height=\"1\" class=\"border-0\" alt=\"" . $row["advertiser"] . " Coupon\"/>";
                    }
                    $str .= "</li>";
                }
            }
            $str .= "</ul>";
            $str .= "</div>";
        }
    }
    else if (mysqli_errno($conn)) {
        $str .= "<h2>No Coupons available at the moment...</h2>";
    }

    return $str;
}

// Delete left over progressbar files older than 2 days
function cleanupPbFiles() {
    $files = glob("../tmp/pb*.txt");
    $now = time();
    foreach ($files as $file) {
        if (is_file($file)) {
            if ($now - filemtime($file) >= 60 * 60 * 24 * 2) { // 2 days and older
                unlink($file);
            }
        }
    }
}

// Update progressbar file for a session
function updatePbFile($flag = false) {
    static $max_pb = 13; // max progressbar steps
    static $current = 0;

    if ($flag) {
        $current = 0;
    }
    else {
        ++$current;
    }

    if ($current > $max_pb) {
        error_log("max_pb $max_pb is too small, current step is $current. Adjust tools.php (updatePbFile).");
        $max_pb = $current;
    }
    $filename = session_id() . "_" . MySessionHandler::getSessionTab();
    $arr_content = array();

    $percent = intval($current / $max_pb * 100);

    $arr_content['percent'] = $percent;
    $arr_content['message'] = $current . " search(es) processed.";
    $file = "../tmp/pb_" . $filename . ".txt";

    if ($percent >= 100) {
        @unlink($file);
    } else {
        file_put_contents($file, json_encode($arr_content));
    }
}

// Linkshare / CJ Affiliate csv dump
function ls_cj_csv($fields) {
    static $fh = null;
    $delimiter = ',';
    $enclosure = '"';
    $mysql_null = false;

    if (!$fh) {
        $fh = fopen("ls_cj.csv", "a+");
    }

    $delimiter_esc = preg_quote($delimiter, '/');
    $enclosure_esc = preg_quote($enclosure, '/');

    $output = array();
    foreach ($fields as $field) {
        if ($field === null && $mysql_null) {
            $output[] = 'NULL';
            continue;
        }

        $output[] = preg_match("/(?:${delimiter_esc}|${enclosure_esc}|\s)/", $field) ? ($enclosure . str_replace($enclosure, $enclosure . $enclosure, $field) . $enclosure) : $field;
    }

    fwrite($fh, join($delimiter, $output) . "\n");
}

// Login in check
function isLoggedIn() {
    return (!empty($_SESSION['sessData']['userLoggedIn']) && !empty($_SESSION['sessData']['userID'])) ? true : false;
}

// unset all login system session data
function unsetSessData() {
    unset($_SESSION['sessData']['userLoggedIn']);
    unset($_SESSION['sessData']['userID']);
    unset($_SESSION['sessData']['loginType']);
}

// get user image name
function getUserImage($userData) {
    if (empty($userData) || empty($userData['picture'])) {
        return 'login/assets/images/default.png';
    }

    $httpPos = strpos($userData['picture'], 'http');
    if ($httpPos === false) {
        return 'login/' . UPLOAD_PATH . 'profile_picture/' . $userData['picture'];
    }

    return $userData['picture'];
}

function startsWith($haystack, $needle) {
    return substr_compare($haystack, $needle, 0, strlen($needle)) === 0;
}

function endsWith($haystack, $needle) {
    return substr_compare($haystack, $needle, -strlen($needle)) === 0;
}

function displayBarcode($barcode) {
    $barcode = trim(preg_replace("/[^0-9]/", "", $barcode));
    $barcodeType = clsLibGTIN::GTINCheck($barcode, false, 1);

    if ($barcodeType == "UPC" && strlen($barcode) == 12) {
        return substr($barcode, 0, 1) . "-" . substr($barcode, 1, 5) . "-" . substr($barcode, 6, 5) . "-" . substr($barcode, 11, 1);
    }
    else if (($barcodeType == "EAN" || $barcodeType == "ISBN") && strlen($barcode) == 13) {
        return substr($barcode, 0, 1) . "-" . substr($barcode, 1, 6) . "-" . substr($barcode, 7, 6);
    }
    else if ($barcodeType == "EAN" && strlen($barcode) == 14) {
        return substr($barcode, 0, 1) . "-" . substr($barcode, 1, 2) . "-" . substr($barcode, 3, 5) . "-" . substr($barcode, 8, 5) . "-" . substr($barcode, 13, 1);
    }
    else {
        return $barcode;
    }
}