<?PHP
#
#   FILE:  HiddenUrls.php
#
#   FUNCTIONS PROVIDED:
#       PrintPageLinks($NumPages, $Page)
#           - Print the previous and next page links
#       PrintInvalidResourceUrls($InvalidUrls)
#           - Print the data values for each invalid URL
#       PrintStatusCodeOptions($Selected=-1)
#           - Print the status codes as options for limiting the results displayed
#       safehtmlentities($string, $quote_style, $charset, $double_encode)
#           - Version-agnostic htmlentities() function
#
#   FUNCTIONS EXPECTED:
#       PrintPreviousLink($Page)
#           - Print the link to go to the previous page
#       PrintNextLink($Page)
#           - Print the link to go to the next page, if not the second to last
#       PrintLastLink($Page)
#           - Print the link to go to the last page
#       PrintInvalidResourceUrl($Values)
#           - Print out a single invalid resource URL's data
#       PrintStatusCodeOption($StatusCode, $Count, $IsSelected)
#           - Print out the status code option
#
#   OPTIONAL FUNCTIONS:
#       (none)
#
#   FORM FIELDS EXPECTED:
#       (none)
#
#   Copyright 2010 Internet Scout Project
#   http://scout.wisc.edu/
#

# ----- EXPORTED FUNCTIONS ---------------------------------------------------

/**
 * Print the previous and next page links.
 * @param $NumPages total number of pages
 * @param $Page current page number
 * @param $Limit total URLs per page to display
 */
function PrintPageLinks($NumPages, $Page, $Limit)
{
    # previous urls exist
    if ($Page > 1)
    {
        PrintPreviousLink($Limit);
    }

    # next urls exist and not the second to last page
    if ($Page < $NumPages - 1)
    {
        PrintNextLink($Limit);
    }

    # next urls exist and the second to last page
    else if ($Page < $NumPages)
    {
        PrintLastLink($Limit);
    }
}

/**
 * Print the data values for each invalid URL.
 * @param $InvalidUrls array of data values for the invalid URLs
 */
function PrintInvalidResourceUrls($InvalidUrls)
{
    foreach ($InvalidUrls as $Values)
    {
        PrintInvalidResourceUrl($Values);
    }
}

/**
 *
 * @param $Selected the status code that should be selected
 */
function PrintStatusCodeOptions($Selected=-1)
{
    global $Info;
    foreach (GenerateStatusCodeGroups($Info["HiddenInvalidUrlsForStatusCodes"]) as $StatusCodeText => $Count)
    {
        PrintStatusCodeOption($StatusCodeText, $Count, $Selected === $StatusCodeText);
    }
}

/**
 * Version-agnostic htmlentities() function.
 * See: http://www.php.net/manual/en/function.htmlentities.php
 * @param $string the input string
 * @param $quote_style defines what is done with quotes
 * @param $charset defines the character set used in conversion
 * @param $double_encode when off, PHP won't encode existing HTML entities (>= 5.2.3)
 * @return the encoded string
 */
function safehtmlentities($string, $quote_style=ENT_COMPAT, $charset="ISO-8859-1", $double_encode=TRUE)
{
    # get php's version
    list($Major, $Minor, $Maint) = explode(".", phpversion());
    $Major = intval($Major);
    $Minor = intval($Minor);
    $Maint = intval($Maint);

    # ignore $double_encode param if php version < 5.2.3
    if ($Major < 5 || $Major < 6 && $Minor < 2 || $Major < 6 && $Minor < 3 && $Maint < 4)
    {
        return htmlentities($string, $quote_style, $charset);
    }

    return htmlentities($string, $quote_style, $charset, $double_encode);
}

/**
 * Map a status code to its descriptive text form.
 * @param $StatusCode integer status code
 * @return status code description
 */
function StatusCodeToText($StatusCode)
{
    $StatusString = strval($StatusCode);

    if ($StatusCode == 404)
    {
        return "Page Not Found";
    }

    else if ($StatusString{0} == "3")
    {
        return "Redirection";
    }

    else if ($StatusCode == 401 || $StatusCode == 403)
    {
        return "Permission Denied";
    }

    else if ($StatusString{0} == "4")
    {
        return "Client Error";
    }

    else if ($StatusString{0} == "5")
    {
        return "Server Error";
    }

    else if ($StatusString{0} == "0")
    {
        return "Could Not Connect";
    }

    else if ($StatusString{0} == "2")
    {
        return "Page Not Found";
    }

    else if ($StatusString{0} == "1")
    {
        return "Information";
    }

    else
    {
        return "Unknown";
    }
}

# ----- LOCAL FUNCTIONS ------------------------------------------------------

/**
 * Create a group of status code descriptions from an array of status codes.
 * @param $StatusCodes array of status codes
 * @return an array of status code descriptions
 */
function GenerateStatusCodeGroups($StatusCodes)
{
    $Groups = array();

    foreach ($StatusCodes as $StatusCode => $Count)
    {
        $StatusAsText = StatusCodeToText($StatusCode);

        if (!isset($Groups[$StatusAsText]))
        {
            $Groups[$StatusAsText] = $Count;
        }

        else
        {
            $Groups[$StatusAsText] += $Count;
        }
    }

    return $Groups;
}

# ----- MAIN -----------------------------------------------------------------

# non-standard globals
global $Limit;
global $Offset;
global $StatusCode;
global $FieldId;
global $InvalidUrls;
global $Info;
global $InvalidCount;
global $UrlFields;
global $NumUrlFields;
global $PageNumber;
global $NumPages;
global $TitleField;
global $ReleaseFlag;

# setup
PageTitle("URL Checker Hidden URLs");
CheckAuthorization(PRIV_SYSADMIN, PRIV_COLLECTIONADMIN);
$Schema = new MetadataSchema();
$TitleField = $Schema->GetFieldByMappedName("Title");
$ReleaseFlag = $Schema->GetFieldByName("Release Flag");

# unset the release flag if it's not enabled
if (!$ReleaseFlag->Enabled())
{
    $ReleaseFlag = NULL;
}

# values that don't depend on URL checker info
$UrlFields = $Schema->GetFields(MetadataSchema::MDFTYPE_URL);
$NumUrlFields = count($UrlFields);

# limits
$OrderBy = (isset($_SESSION["P_UrlChecker_Hidden_OrderBy"]))
    ? $_SESSION["P_UrlChecker_Hidden_OrderBy"] : "StatusCode";
$OrderDirection = (isset($_SESSION["P_UrlChecker_Hidden_OrderDirection"]))
    ? $_SESSION["P_UrlChecker_Hidden_OrderDirection"] : "ASC";
$Limit = (isset($_SESSION["P_UrlChecker_Hidden_Limit"]))
    ? $_SESSION["P_UrlChecker_Hidden_Limit"] : 15;
$Offset = (isset($_SESSION["P_UrlChecker_Hidden_Offset"]))
    ? $_SESSION["P_UrlChecker_Hidden_Offset"] : 0;
$StatusCode = (isset($_SESSION["P_UrlChecker_Hidden_StatusCode"]) && strlen($_SESSION["P_UrlChecker_Hidden_StatusCode"]) && $_SESSION["P_UrlChecker_Hidden_StatusCode"] != "All")
    ? $_SESSION["P_UrlChecker_Hidden_StatusCode"] : NULL;
$FieldId = (isset($_SESSION["P_UrlChecker_Hidden_FieldId"]))
    ? $_SESSION["P_UrlChecker_Hidden_FieldId"] : FALSE;
$Constraints = array();
$Options = array();

# show hidden URLs
$Constraints[] = array("Hidden", array(1, "="));

# update limits if form values exist
$OrderBy = (isset($_GET["OrderBy"])) ? $_GET["OrderBy"] : $OrderBy;
$OrderDirection = (isset($_GET["OrderDirection"])) ? $_GET["OrderDirection"] : $OrderDirection;
$Limit = (isset($_GET["Limit"])) ? $_GET["Limit"] : $Limit;
$Offset = (isset($_GET["Page"])) ? (intval($_GET["Page"])-1)*$Limit : $Offset;
$StatusCode = (isset($_GET["StatusCode"])) ? $_GET["StatusCode"] : $StatusCode;
$FieldId = (isset($_GET["FieldId"])) ? $_GET["FieldId"] : $FieldId;

# reset the ordering if only within one type of invalid URLs and if ordering
# by status, since it would be useless
if (!is_null($StatusCode) && $StatusCode != "All" && $OrderBy == "StatusCode")
{
    $OrderBy = "CheckDate";
}

# reset the offset if the limit has changed or if it's below 0
if ((isset($_SESSION["P_UrlChecker_Hidden_Limit"])
    && $Limit != $_SESSION["P_UrlChecker_Hidden_Limit"])
    || (isset($_SESSION["P_UrlChecker_Hidden_StatusCode"])
    && $StatusCode != $_SESSION["P_UrlChecker_Hidden_StatusCode"])
    || $Offset < 0)
{
    $Offset = 0;
}

# constraints, if they exist (others are added below)
if ($StatusCode !== FALSE && strval($StatusCode) != "")
{
    switch ($StatusCode)
    {
      case "Could Not Connect":
          $Constraints[] = array("StatusCode", 0);
          break;
      case "Information":
          $Constraints[] = array("StatusCode", array(99, ">"));
          $Constraints[] = array("StatusCode", array(200, "<"));
          break;
      case "Redirection":
          $Constraints[] = array("StatusCode", array(299, ">"));
          $Constraints[] = array("StatusCode", array(400, "<"));
          break;
      case "Client Error":
          $Constraints[] = array("StatusCode", array(399, ">"));
          $Constraints[] = array("StatusCode", array(500, "<"));
          $Constraints[] = array("StatusCode", array(401, "!="));
          $Constraints[] = array("StatusCode", array(403, "!="));
          $Constraints[] = array("StatusCode", array(404, "!="));
          break;
      case "Server Error":
          $Constraints[] = array("StatusCode", array(499, ">"));
          $Constraints[] = array("StatusCode", array(600, "<"));
          break;
      case "Permission Denied":
          $Constraints[] = array("StatusCode", 401);
          break;
      case "Page Not Found":
          $Constraints[] = array("StatusCode", 404);
          break;
    }
}

if ($FieldId !== FALSE && strval($FieldId) != "")
{
    $Constraints[] = array("FieldId", $FieldId);
}

# finally save the limits for next time
$_SESSION["P_UrlChecker_Hidden_OrderBy"] = $OrderBy;
$_SESSION["P_UrlChecker_Hidden_OrderDirection"] = $OrderDirection;
$_SESSION["P_UrlChecker_Hidden_Limit"] = $Limit;
$_SESSION["P_UrlChecker_Hidden_Offset"] = $Offset;
$_SESSION["P_UrlChecker_Hidden_StatusCode"] = $StatusCode;
$_SESSION["P_UrlChecker_Hidden_FieldId"] = $FieldId;

# if ordering by a resource field, we need to pass a MetadataField object
if ($OrderBy == "Title")
{
    $OrderBy = $TitleField;
}

if ($OrderBy == "ReleaseFlag" && !is_null($ReleaseFlag))
{
    $OrderBy = $ReleaseFlag;
    $OrderDirection = "DESC";
}

else
{
    $OrderDirection = "ASC";
}

if ($OrderBy == "ReleaseFlag" && is_null($ReleaseFlag))
{
    $OrderBy = "CheckDate";
}

# set the offset to its max if it's greater than it
if  ($Offset != 0 && $Offset > ($NumPages-1)*$Limit && $Info["NumInvalid"] > 0)
{
    $_SESSION["P_UrlChecker_Hidden_Offset"] = ($NumPages > 1) ? ($NumPages-1)*$Limit : 0;
    $AF->SuppressHTMLOutput();
    $AF->SetJumpToPage("index.php?P=P_UrlChecker_HiddenUrls");
    return;
}

# if given GET data, then refresh the page to avoid the "are you sure you want
# to resend..." message
if (count($_GET) > 1)
{
    $AF->SuppressHTMLOutput();
    $AF->SetJumpToPage("index.php?P=P_UrlChecker_HiddenUrls");
    return;
}

# invalid urls
$InvalidUrls = $AF->SignalEvent("URLCHECKER_GET_INVALID_URLS", array(
    $Constraints, $OrderBy, $OrderDirection, $Limit, $Offset, $Options));
$InvalidCount = $AF->SignalEvent("URLCHECKER_GET_INVALID_COUNT", array($Constraints));

# lump in 200s with Page Not Found (404)
if ($StatusCode == "Page Not Found")
{
    if ($FieldId !== FALSE && strval($FieldId) != "")
    {
        $OtherConstraints[] = array("FieldId", $FieldId);
    }

    $OtherConstraints[] = array("StatusCode", array(199, ">"));
    $OtherConstraints[] = array("StatusCode", array(300, "<"));
    $OtherConstraints[] = array("Hidden", array(1, "="));
    $PNFInvalidUrls = $AF->SignalEvent("URLCHECKER_GET_INVALID_URLS", array(
        $OtherConstraints, $OrderBy, $OrderDirection, $Limit, $Offset, $Options));

    $InvalidUrls = array_merge($PNFInvalidUrls, $InvalidUrls);
    $InvalidCount += count($PNFInvalidUrls);
}

# lump in 403 with Permission Denied (403)
else if ($StatusCode == "Permission Denied")
{
    if ($FieldId !== FALSE && strval($FieldId) != "")
    {
        $OtherConstraints[] = array("FieldId", $FieldId);
    }

    $OtherConstraints[] = array("StatusCode", 403);
    $OtherConstraints[] = array("Hidden", array(1, "="));
    $PNFInvalidUrls = $AF->SignalEvent("URLCHECKER_GET_INVALID_URLS", array(
        $OtherConstraints, $OrderBy, $OrderDirection, $Limit, $Offset, $Options));

    $InvalidUrls = array_merge($PNFInvalidUrls, $InvalidUrls);
    $InvalidCount += count($PNFInvalidUrls);
}

# info
$Info = $AF->SignalEvent("URLCHECKER_GET_INFORMATION");
$PageNumber = ($Limit > 0 && $Offset > 0) ? ceil($Offset/$Limit)+1 : 1;
$NumPages = ($Limit > 0) ? ceil($InvalidCount/$Limit) : 1;
