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

/**
* A converastion forum which includes topics and messages.
* @nosubgrouping
*/
class Forum
{

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

    # Error codes for the forum object
    const OK = 0;
    const NONEXISTENT = 1;
    const NOSUCHTOPIC = 2;
    const NOSUCHMESSAGE = 3;

    /** @name Setup/Initialization/Destruction */
    /*@{*/

    /**
    * Object Constructor. After constructing the object, be sure to call
    * GetErrorStatus() and verify that it returns Forum::OK.
    * @param int $ForumId ID of the forum to retrieve from the database, or -1
    *   to create a new forum.
    * @see GetErrorStatus()
    */
    public function __construct($ForumId = NULL)
    {
        $this->ErrorStatus = self::OK;
        # locate class in database
        $this->DB = new Database();
        $DB = $this->DB;
        # if ID supplied
        if ($ForumId !== NULL)
        {
            $this->ForumId = intval($ForumId);
            $DB->Query("SELECT * FROM Forums WHERE ForumId = "
                    .$this->ForumId);

            # if row was loaded
            if ($DB->NumRowsSelected() > 0)
            {
                # set attributes to values returned by database
                $this->DBFields = $DB->FetchRow();
            }
            else
            {
                $this->ErrorStatus = self::NONEXISTENT;
            }
        }
        elseif (func_num_args()==0)
        {
            # add record to database with that ID
            $DB->Query("INSERT INTO Forums (ForumId) VALUES (NULL)");
            $this->ForumId = $DB->Query("SELECT LAST_INSERT_ID() AS ForumId"
                    ." FROM Forums", "ForumId");
        }
        else
        {
            $this->ErrorStatus = self::NONEXISTENT;
        }

    }

    /**
    * Remove this forum, deleting all assocated topics and messages.
    */
    public function Delete()
    {
        if ($this->ErrorStatus == self::OK)
        {
            $this->DB->Query("Select * from Topics where ForumId = ".
                             $this->ForumId." ORDER BY DateCreated Desc");

            # get list of topics for this forum
            while ($Entry = $this->DB->FetchRow())
            {
                $Topic = new Topic($Entry["TopicId"]);
                $Topic->Delete();
            }
            # delete record from database
            $this->DB->Query("DELETE FROM Forums WHERE ForumId = ".$this->ForumId);
        }
    }
    /*@}*/

    /** @name Accessors */
    /*@{*/

    /**
    * Get the forum's ID.
    * @return Returns the forum ID
    */
    public function ForumId()
    {
        return $this->ForumId;  }

    /**
    * Get the date of the most recent post to the forum.
    * @return Returns the date of the most recent post or "None" for empty
    *      forums
    */
    public function LastMessageDate()
    {
        $Message = $this->GetLastMessage();
        if (isset($Message)) {
            return $Message->DatePosted()." by "; }
        else {
            return "None"; }
    }

    /**
    * Get the CWIS username of the user with the most recent post.
    * @return Returns the CWIS username of the user with the most recent post.
    */
    public function LastMessagePoster()
    {
        $Message = $this->GetLastMessage();
        if (isset($Message)) {
            return $Message->PosterName(); }
    }

    /**
    * Get the e-mail address of the user with the most recent post.
    * @return Returns the e-mail address of the user with the most recent post.
    */
    public function LastMessagePosterEmail()
    {
        $Message = $this->GetLastMessage();
        if (isset($Message)) {
            return $Message->PosterEmail(); }
    }

    /**
    * Get the CWIS username of the forum's moderator.
    * @return Returns the CWIS username of the forum's moderator
    */
    public function ModeratorName()
    {
        $ModeratorName = new CWUser((int)$this->ModeratorId());
        return $ModeratorName->Get("UserName");
    }

    /**
    * Get the e-mail address of the forum's moderator.
    * @return Returns the e-mail address of the forum's modreator
    */
    public function ModeratorEmail()
    {
        $ModeratorName = new CWUser((int)$this->ModeratorId());
        return $ModeratorName->Get("EMail");
    }

    /**
    * Get the list of the topics in this forum.
    * @return Returns an array of topic IDs for this forum's conversations.
    */
    public function GetTopicList()
    {
        $Topics = array();

        $this->DB->Query("Select * from Topics where ForumId = ".
                    $this->ForumId." ORDER BY DateCreated Desc");

        # get list of topics for this forum
        while ($Entry = $this->DB->FetchRow())
        {
            $Topics[$Entry["TopicId"]] = new Topic($Entry["TopicId"]);
        }
        return $Topics;
    }

    /**
    * Get the last message posted in the forum.
    * @return Returns a Message object of the last posted message or NULL if
    *      there isn't one.
    */
    public function GetLastMessage()
    {
        $Message = NULL;

        $this->DB->Query("
            SELECT M.* FROM Messages M
            LEFT JOIN Topics T
            ON M.ParentId = T.TopicId
            WHERE M.ParentType = ".addslashes(Message::PARENTTYPE_TOPIC)."
            AND T.ForumId = '".addslashes($this->ForumId)."'
            ORDER BY DatePosted DESC
            LIMIT 1");

        if ($this->DB->NumRowsSelected())
        {
            $Row = $this->DB->FetchRow();
            $Message = new Message($Row["MessageId"]);
        }

        return $Message;
    }

    /**
    * Get or modify the forum's name.
    * @param string $NewValue New forum name. This parameter is optional.
    * @return Returns the current forum name.
    */
    public function ForumName($NewValue = DB_NOVALUE)
    {
        return $this->UpdateValue("ForumName", $NewValue);
    }

    /**
    * Get or modify the forum description.
    * @param string $NewValue New forum description. This parameter is optional.
    * @return Returns the current forum description.
    */
    public function ForumDescription($NewValue = DB_NOVALUE)
    {
        return $this->UpdateValue("ForumDescription", $NewValue);
    }

    /**
    * Get or set the forum's topic count.
    * @param int $NewValue New forum topic count. This parameter is optional.
    * @return Returns the forum's current topic count.
    */
    public function TopicCount($NewValue = DB_NOVALUE)
    {
        return $this->UpdateValue("TopicCount", $NewValue);
    }

    /**
    * Get or set the forum's message count.
    * @param int $NewValue New forum message count. This parameter is optional.
    * @return Returns the current message count.
    */
    public function MessageCount($NewValue = DB_NOVALUE)
    {
        return $this->UpdateValue("MessageCount", $NewValue);
    }

    /**
    * Get or set the forum's moderator.
    * @param int $NewValue New forum moderator's user ID. This parameter is
    *      optional.
    * @return Returns the CWIS user ID of the forum's moderator.
    */
    public function ModeratorId($NewValue = DB_NOVALUE)
    {
        return $this->UpdateValue("ModeratorId", $NewValue);
    }

    /**
    * Retrieve error codes associated with the creation of the forum.
    * @return Returns Forum::OK if everything worked, something else otherwise.
    */
    public function GetErrorStatus()
    {
        return $this->ErrorStatus;
    }

    /*@}*/

    /**
    * Add topic to forum.
    * @param string $Author User adding new topic.
    * @param string $TopicName Name of new topic.
    * @param string $Subject Subject for new topic.
    * @param string $Body Text body for new topic.
    * @return int ID of new topic.
    */
    public function AddTopic($Author, $TopicName, $Subject, $Body)
    {
        $Topic = new Topic();

        $Topic->TopicName($TopicName);
        $Topic->DateCreated(date("YmdHis"));
        $Topic->ForumId($this->ForumId);
        $Topic->ViewCount("0");
        $Topic->MessageCount("0");
        $Topic->CreatorId($Author->Id() );

        $this->TopicCount( $this->TopicCount() + 1 );

        $this->PostMessage($Topic->TopicId(), $Author, $Subject, $Body);

        return $Topic->TopicId();
    }

    /**
    * Post new message to topic.
    * @param int $TopicId ID of topic.
    * @param string $Author User adding new message.
    * @param string $Subject Subject for new message.
    * @param string $Body Text body for new message.
    */
    public function PostMessage($TopicId, $Author, $Subject, $Body )
    {
        $Topic = new Topic($TopicId);
        if ($Topic->GetErrorStatus() == Topic::OK)
        {
            # If the selected topic and forum exist
            $Message = new Message();
            $Message->ParentId( $TopicId );
            $Message->ParentType(Message::PARENTTYPE_TOPIC );
            $Message->DatePosted(date("YmdHis"));
            $Message->PosterId( $Author->Id() );
            $Message->Subject( $Subject );
            $Message->Body( $Body );

            # update counts for topic and forum
            $this->MessageCount($this->MessageCount() + 1 );

            $Topic->MessageCount($Topic->MessageCount() + 1);

            return self::OK;
        }
        else
        {
            return self::NOSUCHTOPIC;
        }
    }

    /**
    * Delete a message from a forum, updating the message counts for
    * the associated forum and topic.
    * @param int $MessageId ID of the message to delete
    * @return Forum::OK on success, or an appropriate error code on failure.
    */
    public static function DeleteMessage($MessageId)
    {
        $Message = new Message($MessageId);

        if ($Message->GetErrorStatus() == Message::OK)
        {
            $TopicId = $Message->ParentId();
            $Topic = new Topic($TopicId);
            if ($Topic->GetErrorStatus() == Topic::OK)
            {
                $ForumId = $Topic->ForumId();
                $Forum = new Forum($ForumId);
                if ($Forum->GetErrorStatus() == self::OK)
                {
                    # update count for topic and forum and delete message
                    $Topic->MessageCount($Topic->MessageCount() - 1 );
                    $Forum->MessageCount($Forum->MessageCount() - 1 );

                    $Message->Delete();

                    return self::OK;
                }
                else
                {
                    return self::NONEXISTENT;
                }
            }
            else
            {
                return self::NOSUCHTOPIC;
            }
        }
        else
        {
            return self::NOSUCHMESSAGE;
        }
    }

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

    private $ForumId;
    private $DB;
    private $DBFields;
    private $ErrorStatus;

    /**
    * Convenience method to supply parameters to Database::UpdateValue().
    * @param string $FieldName Name of the field to update.
    * @param mixed $NewValue New value to set for the field.
    */
    private function UpdateValue($FieldName, $NewValue)
    {
        if ($this->ErrorStatus==self::OK)
        {
            return $this->DB->UpdateValue("Forums", $FieldName, $NewValue,
                    "ForumId = '".$this->ForumId."'", $this->DBFields, TRUE);
        }
        else
        {
            return NULL;
        }
    }
}
