<?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()
    */
    function Forum($ForumId = NULL)
    {
        $this->ErrorStatus = Forum::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 = Forum::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 = Forum::NONEXISTENT;
        }

    }

    /**
    * Remove this forum, deleting all assocated topics and messages.
    */
    function Delete()
    {
        if ($this->ErrorStatus == Forum::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
    */
    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
    */
    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.
    */
    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.
    */
    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
    */
    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
    */
    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.
    */
    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.
    */
    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.
    */
   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.
   */
   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.
   */
   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.
   */
   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.
   */
   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.
   */
   function GetErrorStatus() { return $this->ErrorStatus; }

   /*@}*/

   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();
   }

   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 Forum::OK;
       }
       else
       {
           return Forum::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.
   */
   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==Forum::OK)
       {
           return $this->DB->UpdateValue("Forums", $FieldName, $NewValue,
                                         "ForumId = '".$this->ForumId."'", $this->DBFields, TRUE);
       }
       else
       {
           return NULL;
       }
   }

}
