<?PHP
#
#   FILE:  Pages_Page.php (Pages plugin)
#
#   Copyright 2012-2015 Edward Almasy and Internet Scout Research Group
#   http://scout.wisc.edu/cwis/
#

/**
* Class representing individual pages in the Pages plugin.
*/
class Pages_Page extends Resource
{

    # ---- PUBLIC INTERFACE --------------------------------------------------

    /**
    * Object constructor for loading an existing page.  (To create a new
    * page, use Pages_Page::Create().).
    * @param int $PageId ID of the page to load.
    */
    public function __construct($PageId)
    {
        # run base class constructor
        parent::__construct($PageId);

        # load viewing privilege setting if available
        $Data = $this->DB->Query("SELECT ViewingPrivileges"
                ." FROM Pages_Privileges"
                ." WHERE PageId = ".intval($PageId),
                "ViewingPrivileges");
        $this->ViewingPrivs = ($Data === FALSE) ? new PrivilegeSet()
                : new PrivilegeSet($Data);
    }

    /**
    * Create a new page.
    * @param int $SchemaId XX (DO NOT USE -- for compatibility with Resource::Create())
    * @return object Pages_Page object.
    * @throws Exception If bad metadata schema ID parameter is provided.
    */
    public static function Create($SchemaId = NULL)
    {
        # bail out of erroneous schema ID was provided
        if (($SchemaId !== NULL) && ($SchemaId != Pages_PageFactory::$SchemaId))
        {
            throw new Exception("Unnecessary and erroneous schema ID provided.");
        }

        # create a resource
        $Resource = Resource::Create(Pages_PageFactory::$SchemaId);

        # reload resource as a page
        $Id = $Resource->Id();
        unset($Resource);
        $Page = new Pages_Page($Id);

        # return page to caller
        return $Page;
    }

    /**
    * Determine if the given user can view the page.  The result of this
    * method may be modified via EVENT_RESOURCE_VIEW_PERMISSION_CHECK.
    * @param User $User User to check.
    * @param bool $AllowHooksToModify If TRUE, hooks to the modification
    *       event will be allowed to change the result.
    * @return bool TRUE if the user can view the page and FALSE otherwise
    */
    public function UserCanView(User $User, $AllowHooksToModify = TRUE)
    {
        # construct a key to use for our permissions cache
        $CacheKey = "UserCanView".$User->Id();

        # if we don't have a cached value for this perm, compute one
        if (!isset($this->PermissionCache[$CacheKey]))
        {
            # check passes if user privileges are greater than resource set
            $CheckResult = ($this->ViewingPrivs->MeetsRequirements($User, $this)
                    && parent::UserCanView($User, FALSE)) ? TRUE : FALSE;

            # save the result of this check in our cache
            $this->PermissionCache[$CacheKey] = $CheckResult;
        }

        # retrieve value from cache
        $Value = $this->PermissionCache[$CacheKey];

        # allow any hooked functions to modify the result if allowed
        if ($AllowHooksToModify)
        {
            $SignalResult = $GLOBALS["AF"]->SignalEvent(
                    "EVENT_RESOURCE_VIEW_PERMISSION_CHECK",
                    array(
                            "Resource" => $this,
                            "User" => $User,
                            "CanView" => $Value,
                            "Schema" => $this->Schema(), ));
            $Value =  $SignalResult["CanView"];
        }

        # return result to caller
        return $Value;
    }

    /**
    * Get/set viewing privileges for page.
    * @param object $NewValue New viewing privilege setting.  (OPTIONAL)
    * @return object Current viewing privilege setting or NULL if no
    *       viewing privileges have been set..
    */
    public function ViewingPrivileges(PrivilegeSet $NewValue = NULL)
    {
        # if new privilege setting was supplied
        if ($NewValue !== NULL)
        {
            # save new setting in database
            $Value = $this->DB->Query("SELECT ViewingPrivileges"
                    ." FROM Pages_Privileges"
                    ." WHERE PageId = ".intval($this->Id()),
                    "ViewingPrivileges");
            if ($this->DB->NumRowsSelected())
            {
                $this->DB->Query("UPDATE Pages_Privileges"
                        ." SET ViewingPrivileges ="
                        ." '".addslashes($NewValue->Data())."'"
                        ." WHERE PageId = ".intval($this->Id()));
            }
            else
            {
                $this->DB->Query("INSERT INTO Pages_Privileges"
                        ." (PageId, ViewingPrivileges) VALUES"
                        ." (".intval($this->Id()).","
                        ." '".addslashes($NewValue->Data())."')");
            }

            # save new setting for local use
            $this->ViewingPrivs = $NewValue;
        }
        else
        {
            # if setting has not already been loaded
            if (!isset($this->ViewingPrivs))
            {
                # load setting from database
                $Value = $this->DB->Query("SELECT ViewingPrivileges"
                        ." FROM Pages_Privileges"
                        ." WHERE PageId = ".intval($this->Id()),
                        "ViewingPrivileges");
                $this->ViewingPrivs = ($Value === FALSE) ? NULL
                        : new PrivilegeSet($Value);
            }
        }

        # return current privilege settings to caller
        return $this->ViewingPrivs;
    }

    /**
    * Checker whether current page contains jquery-ui tabs.
    * @return TRUE for pages that have tabs, FALSE for pages that do not.
    */
    public function ContainsTabs()
    {
        if (!isset($this->HasTabs))
        {
            $this->HasTabs =
                preg_match('/<h2 class="cw-tab-start">/',
                           $this->Get("Content")) ?
                TRUE : FALSE;
        }

        return $this->HasTabs;
    }

    /**
    * Convert the Pages internal markup for tabs into the format that jquery-ui wants
    * @param string $Html Html to process
    * @return string processed HTML.
    */
    public static function ProcessTabMarkup($Html)
    {
        # divide the input up into pretab, tab header, and tab content
        $PretabContent = '';
        $TabHeader = '';
        $TabContent = '';
        $ActiveTabParameter = '';

        # keep track of which tab we are in, zero if we aren't in one yet
        $Count = 0;

        # iterate through all the lines (assumes ckeditor will
        #   keep the <h2's on their own line)
        foreach (explode("\n", $Html) as $Line)
        {
            # if this is the beginning of a new tab
            if (preg_match('%<h2 class="cw-tab-start">(.*)</h2>%', $Line, $Matches))
            {
                $Count++;

                # when we're the 2nd or later tab, end the previous one
                if ($Count > 1)
                {
                    $TabContent .= "</div>\n";
                }

                # start a new tab and add it to the header
                $TabHeader .= "<li><a href='#cw-tabs-".$Count."'>".
                           $Matches[1]."</a></li>";
                $TabContent .= "<div id='cw-tabs-".$Count."'>\n";

                # look for and save active tab setting
                if (isset($_GET["AT"]))
                {
                    $TabKeyword = strtolower(preg_replace("/[^A-Za-z0-9]/",
                            "", strip_tags($Matches[1])));
                    if (strtolower($_GET["AT"]) == $TabKeyword)
                    {
                        $ActiveTabParameter = "{active: ".($Count - 1)."}";
                    }
                }
            }
            else
            {
                # if we're not in a tab yet, this line is pretab content
                #  otherwise, it is tab content
                if ($Count == 0)
                {
                    $PretabContent .= $Line;
                }
                else
                {
                    $TabContent .= $Line;
                }
            }
        }
        # end the last tab
        $TabContent .= "</div>\n";

        # generate the markup and the javascript for jquery-ui to make our tabs
        return $PretabContent
            ."<div id='cw-tabs'>"
            ."<ul>".$TabHeader."</ul>"
            .$TabContent
            ."</div>"
            ."<script type='text/javascript'>"
            ."jQuery(document).ready(function() { jQuery('#cw-tabs').tabs("
                    .$ActiveTabParameter.");});"
            ."</script>";
    }

    /**
    * Get page summary text, based on page content.
    * @param int $Length Target length for summary, in characters.  (OPTIONAL,
    *       defaults to 320)
    * @return string Summary text.
    */
    public function GetSummary($Length = 320)
    {
        # get main page content
        $Content = $this->Get("Content");

        # strip out any headings
        $Content = preg_replace("%<h[1-3]>.+</h[1-3]>%", "", $Content);

        # strip out any HTML
        $Content = strip_tags($Content);

        # truncate result to desired length
        $Summary = NeatlyTruncateString($Content, $Length);

        # return "summary" to caller
        return $Summary;
    }


    # ---- PRIVATE INTERFACE -------------------------------------------------

    private $HasTabs;
    private $ViewingPrivs;
}
