<?php
#
#   FILE:  SPT--UserAgentSearch.php
#
#   FUNCTIONS PROVIDED:
#
#   FUNCTIONS EXPECTED:
#
#   Part of the Scout Portal Toolkit
#   Copyright 2005 Internet Scout Project
#   http://scout.wisc.edu
#

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

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

# utility func to find mail template file
function FindTemplateFile($FileName)
{
    $SearchPaths = array(
            "local/data/",
            "local/data/SPT--",
            "",
            "SPT--",
            "data/",
            );
    foreach ($SearchPaths as $Path)
    {
        if (is_readable($Path.$FileName))
        {
            return $Path.$FileName;
        }
    }
    return NULL;
}

# callback for generating replacement text for keywords in e-mail message templates
function KeywordReplacementCallback($Matches)
{
    global $SysConfig;
    global $RCResourceIds, $RCUser, $RCSearch;

    static $CurrentResourceId;
    static $Resources;
    static $FieldNameMappings;
    static $InSearchResults = FALSE;
    static $ResultNumber;

    # if local keyword replacement function is defined
    if (function_exists("Local_SavedSearchKeywordReplacement"))
    {
        # if currently in result list
        if ($InSearchResults)
        {
            # pass keyword to local function (including result info)
            $Replacement = Local_SavedSearchKeywordReplacement($Matches[0],
                    $RCUser, $RCSearch, $CurrentResourceId, $ResultNumber);
        }
        else
        {
            # pass keyword to local function
            $Replacement = Local_SavedSearchKeywordReplacement($Matches[0],
                    $RCUser, $RCSearch);
        }

        # if local function returned replacement
        if ($Replacement !== NULL)
        {
            # return replacement to caller
            return $Replacement;
        }
    }
    
    # load record template (if not already loaded)
    static $EmailResourceTemplate;
    if (!isset($EmailResourceTemplate))
    {
        $EmailResourceTemplate = file(
                FindTemplateFile("SearchMailTemplate--Resource.txt"));
    }

    # start out with assumption that no replacement text will be found
    $Replacement = $Matches[0];
    
    # switch on match string
    switch ($Matches[0])
    {
        case "X-PORTALNAME-X":
            $Replacement = $SysConfig->PortalName();
            break;
            
        case "X-ADMINEMAIL-X":
            $Replacement = $SysConfig->AdminEmail();
            break;
            
        case "X-LEGALNOTICE-X":
            $Replacement = $SysConfig->LegalNotice();
            break;
            
        case "X-USERLOGIN-X":
            $Replacement = $RCUser->Get("UserName");
            break;
            
        case "X-USERREALNAME-X":
            $Replacement = $RCUser->Get("RealName");
            if (!strlen(trim($Replacement))) {  $Replacement = $RCUser->Get("UserName");  }
            break;
            
        case "X-USEREMAIL-X":
            $Replacement = $RCUser->Get("EMail");
            break;
            
        case "X-RESULTCOUNT-X":
            $Replacement = count($RCResourceIds);
            break;

        case "X-SEARCHNAME-X":
            $Replacement = $RCSearch->SearchName();
            break;

        case "X-SEARCHCRITERIA-X":
            $Replacement = $RCSearch->GetSearchGroupsAsTextDescription(NULL, FALSE, FALSE);
            break;

        case "X-SEARCHRESULTS-X":
            $Replacement = "";
            if ($InSearchResults == FALSE)
            {
                $InSearchResults = TRUE;
                $ResultNumber = 1;
                foreach ($RCResourceIds as $ResourceId)
                {
                    $CurrentResourceId = $ResourceId;
                    if (!isset($Resources[$ResourceId]))
                    {
                         $Resources[$ResourceId] = new Resource($ResourceId);
                    }
                    foreach ($EmailResourceTemplate as $ResourceTemplateLine)
                    {
                        if (!preg_match("/^#/", $ResourceTemplateLine))
                        {
                            $Replacement .= preg_replace_callback("/X-[A-Z0-9:]+-X/", 
                                    "KeywordReplacementCallback", $ResourceTemplateLine);
                        }
                    }
                    $ResultNumber++;
                }
                $InSearchResults = FALSE;
            }
            break;

        case "X-RESULTNUMBER-X":
            $Replacement = $ResultNumber;
            break;

        case "X-RESOURCEID-X":
            $Replacement = $CurrentResourceId;
            break;

        default:
            # map to date/time value if appropriate
            $DateFormats = array(
                    "X-DATE-X"            => "M j Y",
                    "X-TIME-X"            => "g:ia T",
                    "X-YEAR-X"            => "Y",
                    "X-YEARABBREV-X"      => "y",
                    "X-MONTH-X"           => "n",
                    "X-MONTHNAME-X"       => "F",
                    "X-MONTHABBREV-X"     => "M",
                    "X-MONTHZERO-X"       => "m",
                    "X-DAY-X"             => "j",
                    "X-DAYZERO-X"         => "d",
                    "X-DAYWITHSUFFIX-X"   => "jS",
                    "X-WEEKDAYNAME-X"     => "l",
                    "X-WEEKDAYABBREV-X"   => "D",
                    "X-HOUR-X"            => "g",
                    "X-HOURZERO-X"        => "h",
                    "X-MINUTE-X"          => "i",
                    "X-TIMEZONE-X"        => "T",
                    "X-AMPMLOWER-X"       => "a",
                    "X-AMPMUPPER-X"       => "A",
                    );
            if (isset($DateFormats[$Matches[0]]))
            {
                $Replacement = date($DateFormats[$Matches[0]]);
            }
            else
            {
                # load field name mappings (if not already loaded)
                if (!isset($FieldNameMappings))
                {
                    $Schema = new MetadataSchema();
                    $Fields = $Schema->GetFields();
                    foreach ($Fields as $Field)
                    {
                        $NormalizedName = strtoupper(preg_replace("/[^A-Za-z0-9]/", "", $Field->Name()));
                        $FieldNameMappings[$NormalizedName] = $Field->Name();
                    }
                }
    
                # if keyword refers to known field and we have a current resource
                $KeywordIsField = preg_match("/X-FIELD:([A-Z0-9]+)-X/", $Matches[0], $SubMatches);
                if ($KeywordIsField && isset($FieldNameMappings[$SubMatches[1]]) 
                        && isset($Resources[$CurrentResourceId]))
                {
                    # replacement is value from current resource
                    $Replacement = $Resources[$CurrentResourceId]->Get($FieldNameMappings[$SubMatches[1]]);
                    if (is_array($Replacement))
                    {
                        foreach ($Replacement as $ReplacementEntry)
                        {
                            if (!isset($RebuiltReplacement))
                            {
                                $RebuiltReplacement = $ReplacementEntry;
                            }
                            else
                            {
                                $RebuiltReplacement .= ", ".$ReplacementEntry;
                            }
                        }
                        $Replacement = isset($RebuiltReplacement) ? $RebuiltReplacement : "";
                    }
                    $Replacement = wordwrap(strip_tags($Replacement), 78);
                }
            }
            break;
    }
    
    # return replacement string to caller
    return $Replacement;
}

# generate search results e-mail message body and return to caller
function GenerateSearchResultEmailBody($Search, $ResourceIds, $User)
{
    # pass values to callback function via global variables
    global $RCResourceIds, $RCUser, $RCSearch;
    $RCResourceIds = $ResourceIds;
    $RCUser = $User;
    $RCSearch = $Search;
    
    # start with empty message body
    $Body = "";
 
    # load search result e-mail templates
    $EmailBodyTemplate = file(FindTemplateFile("SearchMailTemplate--Body.txt"));
    
    # for each line of body template
    foreach ($EmailBodyTemplate as $BodyTemplateLine)
    {
        # if line does not look like a comment
        if (!preg_match("/^#/", $BodyTemplateLine))
        {
            # replace any keywords in template line with appropriate content
            #       and add line to body
            $Body .= preg_replace_callback("/X-[A-Z0-9]+-X/", 
                    "KeywordReplacementCallback", $BodyTemplateLine);
        }
    }
    
    # return message body to caller
    return $Body;
}

# email resource entry found as a result of a user agent search 
function EmailSearchResults($SearchResults, $EndUser, $Search)
{
    global $SysConfig;

    # generate header and body of e-mail message
    $MessageText = GenerateSearchResultEmailBody(
            $Search, array_keys($SearchResults), $EndUser);

    # split off header lines from body
    $AllowedHeaderKeywords = array("from", "cc", "bcc", "subject", 
            "content-type", "content-transfer-encoding", "mime-version",
            "boundary");
    $BodyLines = split("\n", $MessageText);
    $Subject = "";
    $AdditionalHeaders = "";
    while (in_array(strtolower(trim(array_shift(
                explode(":", trim($BodyLines[0]))))), $AllowedHeaderKeywords)
           || in_array(strtolower(trim(array_shift(
                explode("=", trim($BodyLines[0]))))), $AllowedHeaderKeywords))
    {
        $Line = trim(array_shift($BodyLines));
        if (preg_match("/^subject:/i", $Line))
        {
            $Subject = preg_replace("/^subject:/i", "", $Line);
        }
        else if (preg_match("/^boundary=/i", trim($BodyLines[0])))
        {
            $AdditionalHeaders .= $Line."\n\t";
        }
        else
        {
            $AdditionalHeaders .= $Line."\r\n";
        }
    }
    if (!strlen($AdditionalHeaders) && !strlen($Subject))
    {
        $Subject = trim(array_shift($BodyLines));
    }
    $Body = implode("\n", $BodyLines);

    # mail report to User
    if (strlen($EndUser->Get("EMail")) > 0)
    {
        mail($EndUser->Get("EMail"), $Subject, $Body, $AdditionalHeaders);
    }
}


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

# non-standard global variables
global $RCResourceIds;
global $RCSearch;
global $RCUser;

# if saved search mailings are enabled and mail template file is available
if ($SysConfig->UserAgentsEnabled() 
        && FindTemplateFile("SearchMailTemplate--Body.txt"))
{
    # get searches that need to be run
    $Searches = GetSavedSearchesDueToRun();

    # for each search
    foreach ($Searches as $Search)
    {
        # retrieve search criteria
        $SearchGroups = $Search->SearchGroups();

        # add search group to contain our added conditions
        $NextGroupIndex = count($SearchGroups);

        # if user has resource or release flag administrator privileges
        $EndUser = new SPTUser($Search->UserId());
        if ($EndUser->HasPriv(PRIV_RESOURCEADMIN, PRIV_RELEASEADMIN))
        {
            # add condition to find only resources created since last time search was run
            $SearchGroups[$NextGroupIndex]["Logic"] = SearchEngine::SEARCHLOGIC_OR;
            $SearchGroups[$NextGroupIndex]["SearchStrings"]["Date Of Record Creation"] = 
                    ">".$Search->DateLastRun();
            $SearchGroups[$NextGroupIndex]["SearchStrings"]["Date Of Record Release"] = 
                    ">".$Search->DateLastRun();
        }
        else
        {
            # add condition to find only released resources
            $SearchGroups[$NextGroupIndex]["Logic"] = SearchEngine::SEARCHLOGIC_AND;
            $SearchGroups[$NextGroupIndex]["SearchStrings"]["Release Flag"] = "=1";

            # add condition to find only resources released since last time search was run
            $SearchGroups[$NextGroupIndex]["SearchStrings"]["Date Of Record Release"] = 
                    ">".$Search->DateLastRun();
        }

        # perform search
        if (!isset($SearchEngine)) {  $SearchEngine = new SPTSearchEngine();  }
        $SearchResults = $SearchEngine->GroupedSearch($SearchGroups, 0, 100);

        # if search results were found
        if (count($SearchResults))
        {
            # generate results e-mail and send to user
            EmailSearchResults($SearchResults, $EndUser, $Search);
        }

        # update timestamp that indicates when search was last run
        $Search->UpdateDateLastRun();
    }
}

?>
