<?PHP
#
#   FILE:  FullRecord.php
#
#   Part of the Collection Workflow Integration System (CWIS)
#   Copyright 2012-2013 Edward Almasy and Internet Scout Research Group
#   http://scout.wisc.edu/cwis/
#

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

/**
 * Get the qualifier of a metadata field for a resource.
 * @param $Resource Resource object
 * @param $Field MetadataField object
 * @param $Id ID used for a specific value if the field value has multiple
 * @return a Qualifier object or NULL if a qualifier is not set
 */
function GetFieldQualifier(Resource $Resource, MetadataField $Field, $Id=NULL)
{
    if (!$Field->UsesQualifiers())
    {
        return NULL;
    }

    $Qualifier = $Resource->GetQualifierByField($Field, TRUE);

    # if the field allows multiple values, get the one for a specific value of
    # the group if it's set and not null
    if (!is_null($Id) && is_array($Qualifier) && isset($Id, $Qualifier))
    {
        $Qualifier = $Qualifier[$Id];
    }

    return ($Qualifier instanceof Qualifier) ? $Qualifier : NULL;
}

/**
 * DEPRECATED: use GetResourceFieldValue() instead (10/19/2011)
 * Get the value of a metadata field for a resource. The value might be modified
 * by one or more plugins.
 * @param $Resource Resource object
 * @param $Field MetadataField object
 * @return the value of a metadata field for a resource
 */
function GetFieldValue(Resource $Resource, MetadataField $Field=NULL)
{
    global $AF;

    # invalid field
    if (!IsValidMetadataField($Field))
    {
        return NULL;
    }

    $Value = $Resource->Get($Field, TRUE);

    # allow plugins to modify the value
    $SignalResult = $AF->SignalEvent(
        "EVENT_FIELD_DISPLAY_FILTER", array(
            "Field" => $Field,
            "Resource" => $Resource,
            "Value" => $Value));
    $Value = $SignalResult["Value"];

    return $Value;
}

/**
 * Determine if a field is a valid one.
 * @param $Field MetadataField object or field name
 * @return TRUE if the field is valid, FALSE otherwise
 */
function IsValidMetadataField($Field)
{
    if (is_string($Field))
    {
        $Schema = new MetadataSchema();
        $Field = $Schema->GetFieldByName($Field);
    }

    return !is_null($Field) && $Field->Status() === MetadataSchema::MDFSTAT_OK;
}

/**
 * Display the metadata field values of a resource.
 * @param $Resource Resource object
 * @param $Filter optional filter callback that returns TRUE if a resource/field
 *                pair should be filtered out
 */
function DisplayResourceFields(Resource $Resource, $Filter=NULL)
{
    $Schema = new MetadataSchema();
    $Fields = $Schema->GetFields(NULL, MetadataSchema::MDFORDER_DISPLAY);

    $HasFilter = is_callable($Filter);

    foreach ($Fields as $Field)
    {
        # filter out fields if requested
        if ($HasFilter && call_user_func($Filter, $Resource, $Field))
        {
            continue;
        }

        $Type = MetadataField::$FieldTypeDBEnums[$Field->Type()];

        $DisplayFunction = "Display" . str_replace(" ", "", $Type) . "Field";
        $DisplayFunction($Resource, $Field);
    }
}

/**
 * Display the metadata field values of a resource along with metadata field
 * groups.
 * @param Resource $Resource resource
 * @param array $Fields array of fields to display
 * @param callback $Filter optional filter callback that returns TRUE if a resource/field
 * @return void
 */
function DisplayResourceFieldsWithGroups(Resource $Resource, $Filter=NULL)
{
    $Schema = new MetadataSchema($Resource->SchemaId());
    $Ordering = $Schema->GetDisplayOrder();
    $Items = $Ordering->GetItems();
    $Blocks = array();
    $CurrentBlock = 0;
    $HasFilter = is_callable($Filter);

    foreach ($Items as $Item)
    {
        # add fields to the current block
        if ($Item instanceof MetadataField)
        {
            # filter out fields if requested
            if ($HasFilter && call_user_func($Filter, $Resource, $Item))
            {
                continue;
            }

            $Blocks[$CurrentBlock][] = $Item;
        }

        # or add the fields of the group to a block
        else if ($Item instanceof MetadataFieldGroup)
        {
            # new block for the fields in the group if the current block is not
            # empty
            if (isset($Blocks[$CurrentBlock]) && count($Blocks[$CurrentBlock]))
            {
                $CurrentBlock++;
            }

            foreach ($Item->GetFields() as $Field)
            {
                # filter out fields the user can't see
                if (!$Resource->UserCanViewField($GLOBALS["G_User"], $Field))
                {
                    continue;
                }

                $Value = GetResourceFieldValue($Resource, $Field);

                # filter out fields with empty values
                if (is_null($Value)
                    || (is_array($Value) && !count($Value))
                    || (is_string($Value) && !strlen($Value)))
                {
                    continue;
                }

                # filter out fields if requested
                if ($HasFilter && call_user_func($Filter, $Resource, $Field))
                {
                    continue;
                }

                $Blocks[$CurrentBlock][] = $Field;
            }

            # new block for fields not in a group if the current block is not
            # empty
            if (isset($Blocks[$CurrentBlock]) && count($Blocks[$CurrentBlock]))
            {
                $CurrentBlock++;
            }
        }
    }

    foreach ($Blocks as $Block)
    {
        DisplayResourceFieldBlock($Resource, $Block);
    }
}

/**
 * Display the given fields of the given resource.
 * @param Resource $Resource resource
 * @param array $Fields array of fields to display
 * @return void
 */
function DisplayFields(Resource $Resource, array $Fields)
{
    foreach ($Fields as $Field)
    {
        $Type = MetadataField::$FieldTypeDBEnums[$Field->Type()];

        $DisplayFunction = "Display" . str_replace(" ", "", $Type) . "Field";
        $DisplayFunction($Resource, $Field);
    }
}

function CumulativeRatingEnabled()
{
    global $Schema;
    return $Schema->GetFieldByName("Cumulative Rating")->Enabled();
}

function UserAlreadyRatedResource()
{
    global $Resource;
    return ($Resource->Rating() == NULL) ? FALSE : TRUE;
}

function PrintUserRatingNumber()
{
    global $Resource;
    print($Resource->Rating());
}

function PrintCumulativeRatingNumber()
{
    global $Resource;
    print($Resource->CumulativeRating());
}

function PrintUserRatingGraphic()
{
    global $Resource;
    PrintRatingGraphic($Resource->Rating());
}

function PrintCumulativeRatingGraphic()
{
    global $Resource;
    PrintRatingGraphic($Resource->CumulativeRating());
}

function PrintNumberOfRatings()
{
    global $Resource;
    print($Resource->NumberOfRatings());
}

function PrintNumberOfRatingsPlural()
{
    global $Resource;
    if ($Resource->NumberOfRatings() > 1) {  print("s");  }
}

function ResourceHasBeenRated()
{
    global $Resource;
    return ($Resource->NumberOfRatings() > 0) ? TRUE : FALSE;
}

function PrintRateResourceLink()
{
    global $ResourceId;
    print("index.php?P=RateResource&amp;F_ResourceId=".$ResourceId);
}

function CumulativeRatingFieldEnabled()
{
    global $Resource;
    return $Resource->UserCanViewField($GLOBALS["G_User"], "Cumulative Rating");
}

function ResourceCommentsAreAvailable()
{
    global $Resource;
    return ($Resource->NumberOfComments() > 0) ? TRUE : FALSE;
}

function CheckForEdit($PosterId)
{
    global $User;

    if (($User->Get("UserId") == $PosterId &&
        $User->HasPriv(PRIV_POSTCOMMENTS)) ||
        $User->HasPriv(PRIV_FORUMADMIN))
        return true;
    else
        return false;
}

function PrintResourceComments()
{
    global $User;
    global $Resource;
    global $ResourceId;

    # retrieve comments
    $Comments = $Resource->Comments();

    # for each comment
    foreach ($Comments as $Comment)
    {
        $EditOkay = CheckForEdit($Comment->PosterId());
        $MessageId = $Comment->MessageId();
        $EditLink = "index.php?P=AddResourceComment"
            ."&amp;RI=".$ResourceId."&amp;MI=".$MessageId;
        $DeleteLink = "index.php?P=AddResourceComment"
            ."&amp;RI=".$ResourceId."&amp;MI=".$MessageId;
        $SpamLink = $User->HasPriv(PRIV_FORUMADMIN, PRIV_USERADMIN) &&
            $Comment->PosterId() != $User->Id() ?
            "index.php?P=CleanSpam"
            ."&amp;PI=".$Comment->PosterId()."&amp;RI=".$ResourceId :
            "";

        # print comment
        PrintForumMessage(
                $Comment, $EditOkay, $EditLink, $DeleteLink, NULL, TRUE, $SpamLink);
    }
}

# ----- DEPRECATED FUNCTIONS --------------------------------------------------

function PrintResourceId()
{
    global $Resource;

    print $Resource->Id();
}

function PrintFieldName()
{
    global $Field;

    print "<span title=\"".defaulthtmlentities($Field->Description())."\">"
        .$Field->GetDisplayName()."</span>";
}

function PrintValue()
{
    global $Field, $Value, $TruncateValue;

    global $Resource;
    global $AF;
    $SignalResult = $AF->SignalEvent(
            "EVENT_FIELD_DISPLAY_FILTER", array(
            "Field" => $Field,
            "Resource" => $Resource,
            "Value" => $Value));
    $OurValue = $SignalResult["Value"];

    if ($Field->Type() == MetadataSchema::MDFTYPE_POINT)
    {
        if (!is_null($OurValue["X"]))
        {
            print(defaulthtmlentities($OurValue["X"]).", ".defaulthtmlentities($OurValue["Y"]));
        }

        else
        {
            print "(not set)";
        }
    }
    else if ($Field->Type() == MetadataSchema::MDFTYPE_PARAGRAPH)
    {
        if ($TruncateValue)
        {
            print(NeatlyTruncateString($OurValue, 70, TRUE));
        }
        else
        {
            print($OurValue);
        }
    }
    else
    {
        if ($TruncateValue)
        {
            print(defaulthtmlentities(NeatlyTruncateString(
                    $OurValue,70,TRUE)));
        }
        else
        {
            print(defaulthtmlentities($OurValue));
        }
    }
}

function PrintQualifier()
{
    global $Field;
    global $Entry;
    global $Value;
    global $GenericId;

    if ($Field->UsesQualifiers())
    {
        $Qualifier = $Entry[$Field->GetDisplayName()." Qualifier"];
        # normal field
        if (is_object($Qualifier) && $Field->ShowQualifiers())
        {
            $Name = $Qualifier->Name();
            if (!empty($Name))
                print "<small> (<a href=\"".$Qualifier->Url()."\">".
                    $Qualifier->Name()."</a>)</small>";
        }
        # controlled name, options, or classifications, use global Qualifier
        else if (is_array($Qualifier) && $Field->ShowQualifiers())
        {
            # look up this qualifier
            foreach ($Qualifier as $ArrayId => $QualifierObj)
            {
                if ($ArrayId == $GenericId)
                    break;
            }
            if (is_object($QualifierObj))
            {
                $Name = $QualifierObj->Name();
                if (!empty($Name))
                    print "<small> (<a href=\"".$QualifierObj->Url()."\">".
                        $QualifierObj->Name()."</a>)</small>";
            }
        }
    }
}

function GetLink()
{
    global $Link;

    print $Link;
}

function PrintControlledNameLink()
{
    global $ControlledNameLink;

    print $ControlledNameLink;
}

function PrintAllFields($OnlySecondary=FALSE)
{
    global $Entry, $Schema, $Field, $Value, $Link, $SysConfig, $DB, $Resource;
    global $G_User, $TruncateValue, $G_PrimaryResourceFieldNames;

    # for each metadata field
    $Fields = $Schema->GetFields(NULL, MetadataSchema::MDFORDER_DISPLAY);
    foreach ($Fields as $Field)
    {
        $FieldName = $Field->Name();
        $Value = $Entry[$FieldName];
        $TruncateValue = FALSE;
        if ($Resource->UserCanViewField($G_User, $Field)
            && !empty($Value)
            && (!$OnlySecondary
                || !in_array($Field->Name(), $G_PrimaryResourceFieldNames)))
        {
            switch($Field->Type())
            {
                case MetadataSchema::MDFTYPE_TEXT:
                    # special case to make Title hyperlink to URL
                    $UrlField = new MetadataField($Schema->StdNameToFieldMapping("Url"));
                    if (($Schema->FieldToStdNameMapping($Field->Id()) == "Title")
                            && $Resource->UserCanViewField($G_User, $UrlField)
                            && strlen($Resource->GetMapped("Url")))
                    {
                        $Link = "index.php?P=GoTo&amp;ID=".$Resource->Id()
                                ."&amp;MF=".$UrlField->Id()
                                ."\" title=\"".defaulthtmlentities($Resource->Get($UrlField))
                                ."\" class=\"ResourceTitle\"";
                        if ($SysConfig->ResourceLaunchesNewWindowEnabled())
                            $Link .= " target=\"_blank\"";
                        PrintLink();
                    }
                    else
                        PrintRow();
                    break;

                case MetadataSchema::MDFTYPE_URL:
                    $TruncateValue = TRUE;
                    $Link = "index.php?P=GoTo&amp;ID=".$Resource->Id()
                            ."&amp;MF=".$Field->Id()
                            ."\" title=\"".defaulthtmlentities($Value)."\"";
                    if ($SysConfig->ResourceLaunchesNewWindowEnabled())
                        $Link .= " target=\"_blank\"";
                    PrintLink();
                    break;

                case MetadataSchema::MDFTYPE_PARAGRAPH:
                    # translate newlines into <br> prior to printing
                    $Value = str_replace("\n", "<br>", $Value);
                    PrintParagraphField();
                    break;

                case MetadataSchema::MDFTYPE_NUMBER:
                    if ($FieldName != "Cumulative Rating")
                        PrintRow();
                    break;

                case MetadataSchema::MDFTYPE_POINT:
                    PrintRow();
                    break;

                case MetadataSchema::MDFTYPE_DATE:
                    $Date = $Value;
                    $Value = $Date->Formatted();
                    if (!empty($Value))
                        PrintRow();
                    break;

                case MetadataSchema::MDFTYPE_TIMESTAMP:
                    PrintRow();
                    break;

                case MetadataSchema::MDFTYPE_FLAG:
                    if ($Value > 0)
                        $Value = $Field->FlagOnLabel();
                    else
                        $Value = $Field->FlagOffLabel();
                    PrintRow();
                    break;

                case MetadataSchema::MDFTYPE_TREE:
                    PrintClassificationNames();
                    break;

                case MetadataSchema::MDFTYPE_CONTROLLEDNAME:
                case MetadataSchema::MDFTYPE_OPTION:
                    PrintCNStart();
                    PrintControlledNames();
                    PrintCNEnd();
                    break;

                case MetadataSchema::MDFTYPE_USER:
                    if ($G_User->HasPriv(PRIV_RESOURCEADMIN))
                    {
                        $NewUser = $Entry[$FieldName];
                        # make sure UserId is valid
                        if (is_null($NewUser->Get("UserId")))
                            $Value = "Unknown";
                        else
                            $Value = $NewUser->Get("UserName");
                        PrintRow();
                    }
                    break;

                case MetadataSchema::MDFTYPE_IMAGE:
                    $Images = $Resource->GetByField($Field, TRUE);
                    foreach ($Images as $Image)
                    {
                        if (is_readable($Image->PreviewUrl()))
                        {
                            PrintImageField($FieldName,
                                    "index.php?P=FullImage"
                                    ."&amp;ResourceId=".$Resource->Id()
                                    ."&amp;&FieldName=".$FieldName
                                    ."&amp;edit=0",
                                    $Image->Height(),
                                    $Image->Width(),
                                    $Image->PreviewUrl(),
                                    $Image->PreviewHeight(),
                                    $Image->PreviewWidth(),
                                    $Image->AltText());
                        }
                    }
                    break;

                case MetadataSchema::MDFTYPE_FILE:
                    if ($Resource->UserCanViewField($G_User, $Field))
                    {
                        PrintFileField($Field, $Resource);
                    }
                    break;

                case MetadataSchema::MDFTYPE_REFERENCE:
                    # retrieve all the references for this field
                    $References = $Resource->Get($Field, TRUE);

                    # print the link for each reference field
                    foreach ($References as $ReferenceId => $Reference)
                    {
                        $Link = "index.php?P=FullRecord&amp;ID=".defaulthtmlentities(urlencode($ReferenceId))
                            ."\" title=\"View more information for &quot;".defaulthtmlentities($Reference->GetMapped("Title"))
                            ."&quot;\" class=\"ResourceTitle\"";
                        if ($SysConfig->ResourceLaunchesNewWindowEnabled())
                            $Link .= " target=\"_blank\"";
                        PrintLink();
                    }
                    break;
            }
        }
    }
}

# display controlled names for this record
function PrintControlledNames()
{
    global $Schema;
    global $Field;
    global $Link;
    global $Value;
    global $Resource;
    global $GenericId;

    # retrieve list of entries for field
    $Names = $Resource->GetByField($Field);

    # print field name
    PrintNameType($Field->Name());

    # for each entry
    foreach ($Names as $GenericId => $Value)
    {
        # build link to controlled name search
        if ($Field->Type() == MetadataSchema::MDFTYPE_OPTION)
        {
            $Link = "index.php?P=AdvancedSearch&amp;Q=Y&amp;"
                ."G".$Field->Id()."=".$GenericId;
        }
        else
        {
            $Link = "index.php?P=AdvancedSearch&amp;Q=Y&amp;"
                ."F".$Field->Id()."=".urlencode("=".$Value);
        }

         # print entry
         PrintLinkedValue();
    }
}

# display classifications for this record
function PrintClassificationNames()
{
    global $Schema;
    global $Link;
    global $Field;
    global $Resource;
    global $Value;
    global $GenericId;

    if (isset($Field) && $Resource->UserCanViewField($GLOBALS["G_User"], $Field))
    {
        $Names = $Resource->Classifications();

        $NeedToPrintStart = TRUE;
        foreach ($Names as $ClassificationType => $ClassificationTypes)
        {
            if ($ClassificationType == $Field->Name())
            {
                foreach ($ClassificationTypes as $GenericId => $Classification)
                {
                    $Value = $Classification;

                    if (!empty($Classification))
                    {
                        if ($NeedToPrintStart)
                        {
                            PrintClassStart();
                            $NeedToPrintStart = FALSE;
                        }
                        $Link = "index.php?P=AdvancedSearch&amp;Q=Y&amp;"
                            ."G".$Field->Id()."=".$GenericId;
                        PrintLinkedValue();
                    }
                }
                if (count($Names) > 0)
                    PrintClassEnd();
            }
        }
    }
}

function PrintTitle()
{
    global $User, $Resource, $Schema;

    $TitleField = $Schema->GetFieldByMappedName("Title");
    print ($Resource->UserCanViewField($User, $TitleField)) ?
        defaulthtmlentities($Resource->Get($TitleField)) : "";
}

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

function PrintRatingGraphic($Rating)
{
    global $Resource;

    if (is_null($Rating) || $Resource->NumberOfRatings() < 1)
    {
        PrintRatingGraphicNoRating();
    }

    else
    {
        $Function = "PrintRatingGraphic" . intval(($Rating + 5) / 10);

        if (function_exists($Function))
        {
            $Function();
        }
    }
}

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

# non-standard global variables
global $ControlledNameLink;
global $Entry;
global $Field;
global $GenericId;
global $Link;
global $Resource;
global $ResourceId;
global $Schema;
global $Value;
global $Fields;
global $G_Resource;
global $G_PrimaryResourceFieldNames;
global $G_ReturnTo;
global $G_ReturnText;
global $H_IncorrectSchema;

PageTitle("Full Resource Record Display");

# get data for return to button
$G_ReturnTo = defaulthtmlentities(StripXSSThreats(GetArrayValue($_SESSION, "CW-ReturnTo")));
$G_ReturnText = defaulthtmlentities(StripXSSThreats(GetArrayValue($_SESSION, "CW-ReturnToText")));
$ReturnToTtl = defaulthtmlentities(StripXSSThreats(GetArrayValue($_SESSION, "CW-ReturnToTTL", 0)));

# the results have expired
if (time() > $ReturnToTtl)
{
    unset($_SESSION["CW-ReturnTo"]);
    unset($_SESSION["CW-ReturnToText"]);
    unset($_SESSION["CW-ReturnToTTL"]);
    $G_ReturnTo = NULL;
    $G_ReturnText = NULL;
}

# protect against malicious redirects
if (!IsSafeRedirectUrl($G_ReturnTo))
{
    $G_ReturnTo = NULL;
    $G_ReturnText = NULL;
}

# redirect to this page to use GET parameters since the session ones won't
# exist if someone refreshes or clicks a link and clicks the back button
if (!isset($_GET["ID"]) && $Session->IsRegistered("ResourceId"))
{
    $AF->SetJumpToPage(
        "index.php?P=FullRecord&ID=".intval($Session->Get("ResourceId")));
    return;
}

$Schema = new MetadataSchema();
$Fields = $Schema->GetFields();

# get the primary resource fields
$G_PrimaryResourceFieldNames = array(
  "Cumulative Rating", "Date Record Checked",
  $Schema->GetFieldByMappedName("Title")->Name());

if (IsValidMetadataField($Schema->GetFieldByMappedName("Url"))) {
    $G_PrimaryResourceFieldNames []= $Schema->GetFieldByMappedName("Url")->Name();
}

if (IsValidMetadataField($Schema->GetFieldByMappedName("Description"))) {
    $G_PrimaryResourceFieldNames []= $Schema->GetFieldByMappedName("Description")->Name();
}

# if resource ID was supplied
$ResourceId = isset($_GET["ID"])
        ? intval($_GET["ID"]) : (isset($_GET["ResourceId"])
        ? intval($_GET["ResourceId"]) : NULL);
if ($ResourceId !== NULL)
{
    # load resource
    $Resource = new Resource($ResourceId);
    $G_Resource = $Resource;

    # make sure the user can view the resource
    if (!$Resource->UserCanView($User))
    {
        CheckAuthorization(-1);
        return;
    }

    # redirect to the proper view page if the resource isn't using the default
    # schema
    if ($Resource->SchemaId() != MetadataSchema::SCHEMAID_DEFAULT)
    {
        # get the view page URL template for the metadata schema
        $Schema = new MetadataSchema($Resource->SchemaId());
        $ViewUrl = $Schema->ViewPage();

        # there is no view page URL template to use
        if (!strlen($ViewUrl))
        {
            CheckAuthorization(-1);
            return;
        }

        # get the view page URL for the resource and redirect to it
        $ViewUrl = preg_replace("%\\\$ID%", intval($Resource->Id()), $ViewUrl);

        # redirect to the clean URL whenever possible
        if ($AF->HtaccessSupport())
        {
            $ViewUrl = $AF->GetCleanUrlForPath($ViewUrl);
        }

        $AF->SetJumpToPage($ViewUrl);
        return;
    }

    # load resource values
    $Entry = $Resource->GetAsArray();

    # set page title
    $TitleField = $Schema->GetFieldByMappedName("Title");
    if ($Resource->UserCanViewField($User, $TitleField))
    {
        PageTitle(trim(strip_tags($Resource->Get($TitleField))));
    }

    else
    {
        PageTitle("Full Record");
    }

    # signal full record page view
    $AF->SignalEvent("EVENT_FULL_RECORD_VIEW", array("ResourceId" => $ResourceId));
}
else
{
    # display error page
    if (!CheckAuthorization(-1)) {  return;  }
}

# cache various values
if (isset($Entry["DateLastVerified"]))
    $DateLastVerified = $Entry["DateLastVerified"];
