﻿<?
// Contributed to the Sandcastle Help File Builder project by Thomas Levesque

class Ranking
{
    public $filename;
    public $pageTitle;
    public $rank;

    function __construct($file, $title, $rank)
    {
        $this->filename = $file;
        $this->pageTitle = $title;
        $this->rank = $rank;
    }
}


/// <summary>
/// Split the search text up into keywords
/// </summary>
/// <param name="keywords">The keywords to parse</param>
/// <returns>A list containing the words for which to search</returns>
function ParseKeywords($keywords)
{
    $keywordList = array();
    $words = preg_split("/[^\w]+/", $keywords);

    foreach($words as $word)
    {
        $checkWord = strtolower($word);
        $first = substr($checkWord, 0, 1);
        if(strlen($checkWord) > 2 && !ctype_digit($first) && !in_array($checkWord, $keywordList))
        {
            array_push($keywordList, $checkWord);
        }
    }

    return $keywordList;
}


/// <summary>
/// Search for the specified keywords and return the results as a block of
/// HTML.
/// </summary>
/// <param name="keywords">The keywords for which to search</param>
/// <param name="fileInfo">The file list</param>
/// <param name="wordDictionary">The dictionary used to find the words</param>
/// <param name="sortByTitle">True to sort by title, false to sort by
/// ranking</param>
/// <returns>A block of HTML representing the search results.</returns>
function Search($keywords, $fileInfo, $wordDictionary, $sortByTitle)
{
    $sb = "<ol>";
    $matches = array();
    $matchingFileIndices = array();
    $rankings = array();

    $isFirst = true;

    foreach($keywords as $word)
    {
        if (!array_key_exists($word, $wordDictionary))
        {
            return "<strong>Nothing found</strong>";
        }
        $occurrences = $wordDictionary[$word];

        $matches[$word] = $occurrences;
        $occurrenceIndices = array();

        // Get a list of the file indices for this match
        foreach($occurrences as $entry)
            array_push($occurrenceIndices, ($entry >> 16));

        if($isFirst)
        {
            $isFirst = false;
            foreach($occurrenceIndices as $i)
            {
                array_push($matchingFileIndices, $i);
            }
        }
        else
        {
            // After the first match, remove files that do not appear for
            // all found keywords.
            for($idx = 0; $idx < count($matchingFileIndices); $idx++)
            {
                if (!in_array($matchingFileIndices[$idx], $occurrenceIndices))
                {
                    array_splice($matchingFileIndices, $idx, 1);
                    $idx--;
                }
            }
        }
    }

    if(count($matchingFileIndices) == 0)
    {
        return "<strong>Nothing found</strong>";
    }

    // Rank the files based on the number of times the words occurs
    foreach($matchingFileIndices as $index)
    {
        // Split out the title, filename, and word count
        $fileIndex = explode("\x00", $fileInfo[$index]);

        $title = $fileIndex[0];
        $filename = $fileIndex[1];
        $wordCount = intval($fileIndex[2]);
        $matchCount = 0;

        foreach($keywords as $words)
        {
            $occurrences = $matches[$word];

            foreach($occurrences as $entry)
            {
                if(($entry >> 16) == $index)
                    $matchCount += $entry & 0xFFFF;
            }
        }

        $r = new Ranking($filename, $title, $matchCount * 1000 / $wordCount);
        array_push($rankings, $r);

        if(count($rankings) > 99)
            break;
    }

    // Sort by rank in descending order or by page title in ascending order
    if($sortByTitle)
    {
        usort($rankings, "cmprankbytitle");
    }
    else
    {
        usort($rankings, "cmprank");
    }

    // Format the file list and return the results
    foreach($rankings as $r)
    {
        $f = $r->filename;
        $t = $r->pageTitle;
        $sb .= "<li><a href=\"$f\" target=\"_blank\">$t</a></li>";
    }

    $sb .= "</ol";

    if(count($rankings) < count($matchingFileIndices))
    {
        $c = count(matchingFileIndices) - count(rankings);
        $sb .= "<p>Omitted $c more results</p>";
    }

    return $sb;
}

function cmprank($x, $y)
{
    return $y->rank - $x->rank;
}

function cmprankbytitle($x, $y)
{
    return strcmp($x->pageTitle, $y->pageTitle);
}

?>
