﻿/****************************************
*        CallServerActionEnum
*****************************************/

/// <summary>
/// Post Type Enumeration
/// </summmary>
var CallServerActionEnum =
{
    GoToPage : 0,
    RatePost : 1,
    DeletePost : 2,
    ClosePost : 3,
    CreatePost : 4,
    EditPost : 5,
    SearchPosts : 6,
    GoToPost : 7,
    Refresh : 8,
    ClearSearch : 9
} // CallServerActionEnum

/****************************************
*        DialogActionEnum
*****************************************/

/// <summary>
/// Dialog Action Enumeration
/// </summmary>
var DialogActionEnum =
{
    NewPost : 0,
    ReplyToPost : 1,
    EditPost : 2,
    ErrorMessage : 3,
    SearchPosts : 4
} // DialogActionEnum

/****************************************
*        OpenMessageModeEnum
*****************************************/

/// <summary>
/// Post Type Enumeration
/// </summmary>
var OpenMessageModeEnum =
{
    OneAtTime : 0,
    MultipleAtTime : 1
} // OpenMessageModeEnum

/****************************************
*        PostTypeEnum
*****************************************/

/// <summary>
/// Post Type Enumeration
/// </summmary>
var PostTypeEnum =
{
    GeneralComment : 0,
    NewsInfo : 1,
    Question : 2,
    Answer : 3,
    AdminMessage : 4,
    Sticky : 5
} // PostTypeEnum

/****************************************
*            RichMessageBoard
*****************************************/

/// <summary>
/// RichMessageBoard class
/// </summmary>
function RichMessageBoard( id )
{
    this.ID = id;
    this.OpenMessageMode = OpenMessageModeEnum.OneAtTime;
    this.Theme = null;
    this.RatingUpTo = 3;
    this.UserIsAdmin = false;
    this.InitialConfigurationValid = false;
    this.InitialConfigurationErrorMessage = null;
    this.RichTextBoxID = null;
    this.CurrentPage = 1;
    
    //used for searching
    this._searchCurrentPosts = null; // array with the found posts ids of the current search
    this._searchCurrentPost = null;
    this._searchFor = null;
    this._searchPostedBy = null;
    this._searchActive = false;
    
    //Used to open and close message contents
    this._currentOpenedPostContentRow = null;
    this._currentOpenedPostContentHeaderRow = null;
    
    //IDs for the RichMessageBoard child objects
    this._MainContainerID = this.ID + '_MainContainer';
    this._RichTextBoxContainerID = this.ID + '_RTBContainer';
    this._DialogRichTextBoxContainerID = this.ID + '_DialogRTBContainer';
    this._PopupDivID = this.ID + '_Popup';
    this._DialogID = this.ID + '_DialogWindow';
    this._FormRadioListPostTypeID = this.ID + '_RadioListPostType';
    this._FormPostTitleID = this.ID + '_PostTitle';
    this._SearchFormPostedByID = this.ID + '_PostedByFilter';
    this._SearchFormSearchForID = this.ID + '_SearchForFilter';
    
    //Element child objects of the RichMessageBoard
    this._RichTextBoxContainerElement = null;
    this._MainContainerElement = null;
    this._PopupContainerElement = null;
    
    //UI objects for searching
    this._searchStartDate = null;
    this._searchEndDate = null;
    
    //others
    this._IsDialogOpened = false;
    
    //Hidden fields for the viewstate
    this._currentPageHiddenID = this.ID + '_Hidden_CurrentPage';
    this._searchSearchActiveHiddenID = this.ID + '_Hidden_SearchActive';
    this._searchForHiddenID = this.ID + '_Hidden_SearchFor';
    this._searchPostedByHiddenID = this.ID + '_Hidden_SearchBy';
    this._searchStartDateHiddenID = this.ID + '_Hidden_SearchStartDate';
    this._searchEndDateHiddenID = this.ID + '_Hidden_SearchEndDate';
} // RichMessageBoard

/// <summary>
/// RichMessageBoard class prototype
/// </summary>
RichMessageBoard.prototype =
{
    /// <summary>
    /// Initializes this RichMessageBoard Instance
    /// </summary>
    Initialize: function() {
        var thisRef = this;

        this._CheckMainContainerElement();
        this._CheckPopupContainerElement();
        this._CheckRichTextBoxContainerElement();
        this._CheckSearchDatesObjects();

        //Keep initializing until we find the main element and the init callback function exists
        if (this._MainContainerElement == null || ! window.WebForm_InitCallback )
            window.setTimeout(function() { thisRef.Initialize(); }, 100);
        //If the main container is found
        else {
            //If the initial configuration is not valid
            if ( ! this.InitialConfigurationValid) 
            {
                this._ShowErrorDialog('RichMessageBoard - Initialization Error', this.InitialConfigurationErrorMessage);
            }
            else 
            {
                this._MainContainerElement.className = this.Theme;

                //this._searchActive = ( $(this._searchSearchActiveHiddenID).value == 'true' );
                this.GoToPage( this.CurrentPage );
                
                if ( ! this._searchActive )
                {
                    if ( this._searchStartDate != null )
                        this._searchStartDate.ClearDate();
                        
                    if ( this._searchEndDate != null )
                        this._searchEndDate.ClearDate();
                }
            }
        }
    }, // Initialize

    /// <summary>
    /// Shows the create new post dialog to the user
    /// </summary>
    ShowCreateNewPostDialog: function() 
    {
        if ( ! this._IsDialogOpened ) 
        {
            //Set dialog parameters
            this._PopupContainerElement.Parameters = new Object();
            this._PopupContainerElement.Parameters.IsRoot = 'true';
            this._PopupContainerElement.Parameters.DialogTitle = 'New Post';
            this._PopupContainerElement.Parameters.Action = DialogActionEnum.NewPost;

            //Show the dialog
            this._ShowDialog();
        }
    }, // ShowCreateNewPostDialog

    /// <summary>
    /// Shows the search dialog to the user
    /// </summary>
    ShowSearchDialog: function() 
    {
        if ( ! this._IsDialogOpened ) 
        {
            //Set dialog parameters
            this._PopupContainerElement.Parameters = new Object();
            this._PopupContainerElement.Parameters.Action = DialogActionEnum.SearchPosts;

            //Show the dialog
            this._ShowSearchDialog();
        }
    }, // ShowSearchDialog

    /// <summary>
    /// Shows the reply to post dialog to the user
    /// </summary>
    /// <param name="postId">Post ID</param>
    ShowReplyPostDialog: function( postId ) 
    {
        if ( ! this._IsDialogOpened ) 
        {
            var parentRow = null;

            parentRow = $(this.ID + '_PostHeader_' + postId);

            //Set dialog parameters
            this._PopupContainerElement.Parameters = new Object();
            this._PopupContainerElement.Parameters.DialogTitle = 'Reply to Post';
            this._PopupContainerElement.Parameters.PostID = postId;
            this._PopupContainerElement.Parameters.Action = DialogActionEnum.ReplyToPost;

            //Show the dialog
            this._ShowDialog();

            //Set the reply dialog main title
            $(this._FormPostTitleID).value = 'RE: ' + RicherComponents_DecodeHTML( parentRow.getAttribute('PostTitle') );
        }
    }, // ShowReplyPostDialog

    /// <summary>
    /// Shows the edit post dialog to the user
    /// </summary>
    /// <param name="postId">Post ID</param>
    ShowEditPostDialog: function( postId )
    {
        if ( ! this._IsDialogOpened) 
        {
            var row = null;
            var contentCell = null;
            var content = null;

            row = $(this.ID + '_PostHeader_' + postId);
            contentCell = $(this.ID + '_PostContentCell_' + postId);

            //Set dialog parameters
            this._PopupContainerElement.Parameters = new Object();
            this._PopupContainerElement.Parameters.IsRoot = row.getAttribute('IsRoot');
            this._PopupContainerElement.Parameters.DialogTitle = 'Edit Post Content';
            this._PopupContainerElement.Parameters.PostID = postId;
            this._PopupContainerElement.Parameters.Action = DialogActionEnum.EditPost;

            //Show the dialog
            this._ShowDialog();

            //Set the edit dialog main title
            $(this._FormPostTitleID).value = RicherComponents_DecodeHTML( row.getAttribute('PostTitle') );
            //Set the actual type
            this._FormSetType( row.getAttribute('PostType') );

            //get the content
            content = contentCell.getAttribute( 'PostContent' );
            if ( content == null || content == '' )
                content = contentCell.innerHTML;

            //Set the content for the RTB
            this._FormSetRichTextBoxHTMLContent( content );
        }
    }, // ShowEditPostDialog

    /// <summary>
    /// Ask to the user is is sure to delete the selected post from the database,
    /// if agreed then delete it from the database otherwise do nothing.
    /// </summary>
    /// <param name="postId">Post ID</param>
    PostDelete: function(postId) 
    {
        var actions = '';
        var parameters = '';
        var context = null;

        //Ask to the user if he is sure to delete the post
        if (window.confirm('Are you sure you want to delete this post and all its replies?')) {
            //set the context values
            context = new Object();
            context.Action = CallServerActionEnum.DeletePost;
            context.Sender = this;

            //Set the argument of the call back
            parameters += this._GetCallbackSearchParameters();
            parameters += RicherComponents_BuildParameterString('PostID', postId);
            actions += RicherComponents_BuildActionString(CallServerActionEnum.DeletePost, parameters);

            //Call the server
            this._CallServer(actions, context);
        }
    }, // PostDelete

    /// <summary>
    /// Ask to the user is is sure to close the selected post on the database,
    /// if agreed then close it on the database otherwise do nothing.
    /// </summary>
    /// <param name="postId">Post ID</param>
    PostClose: function(postId) {
        var actions = '';
        var parameters = '';
        var context = null;

        //Ask to the user if he is sure to close the post
        if (window.confirm('Are you sure you want to close this thread?')) {
            //set the context values
            context = new Object();
            context.Action = CallServerActionEnum.ClosePost;
            context.Sender = this;

            //Set the argument of the call back
            parameters += this._GetCallbackSearchParameters();
            parameters += RicherComponents_BuildParameterString('PostID', postId);
            actions += RicherComponents_BuildActionString(CallServerActionEnum.ClosePost, parameters);

            //Call the server
            this._CallServer(actions, context);
        }
    }, // PostClose

    /// <summary>
    /// Expands the post content for the given post.
    /// If the content is already expanded then it does nothing.
    /// </summary>
    /// <param name="postId">Post ID</param>
    PostExpandContent: function(postId) 
    {
        this._PostExpandOrCollapse(postId, true);
    }, // PostExpandContent

    /// <summary>
    /// Collapses the post content for the given post.
    /// If the content is already collapsed then it does nothing.
    /// </summary>
    /// <param name="postId">Post ID</param>
    PostCollapseContent: function(postId) 
    {
        this._PostExpandOrCollapse(postId, false);
    }, // PostCollapseContent

    /// <summary>
    /// Checks if the given post is expanded or collapsed
    /// </summary>
    /// <param name="postId">Post ID</param>
    PostIsExpanded: function(postId) 
    {
        var row = null;
        var expanded = false;

        //Get the post row
        row = $(this.ID + '_PostContent_' + postId);
        expanded = (row.Expanded == true);

        return expanded;
    }, // PostIsExpanded

    /// <summary>
    /// Changes the visible status of the post. If expanded then collapse.
    /// if collapsed then expand.
    /// </summary>
    /// <param name="postId">Post ID</param>
    PostChangeExpandOrCollapse: function(postId) 
    {
        if (this.PostIsExpanded(postId))
            this.PostCollapseContent(postId);
        else
            this.PostExpandContent(postId);
    }, // PostChangeExpandOrCollapse

    /// <summary>
    /// Rate the given post (the rate is maded by the current user ONLY)
    /// </summary>
    /// <param name="postId">Post ID</param>
    /// <param name="rate">Rate of the post</param>
    PostRate: function(postId, rate) 
    {
        var container = null;
        var actions = '';
        var parameters = '';
        var context = null;

        container = $(this.ID + '_RatingBox_' + postId);

        //Show loading box
        container.innerHTML = this._BuildRateLoading().ToHTML();

        //set the context values
        context = new Object();
        context.Action = CallServerActionEnum.RatePost;
        context.PostID = postId;
        context.Sender = this;

        //Set the argument of the call back
        parameters += RicherComponents_BuildParameterString('PostID', postId);
        parameters += RicherComponents_BuildParameterString('Rate', rate);
        actions += RicherComponents_BuildActionString(CallServerActionEnum.RatePost, parameters);

        //Call the server
        this._CallServer(actions, context);
    }, // PostRate

    /// <summary>
    /// Edit the post in the database
    /// </summary>
    /// <param name="postId">Post ID</param>
    /// <param name="title">Post title</param>
    /// <param name="type">Post type</param>
    /// <param name="content">Post content</param>
    PostEdit: function(postId, title, type, content) 
    {
        var actions = '';
        var parameters = '';
        var context = null;

        //set the context values
        context = new Object();
        context.Action = CallServerActionEnum.EditPost;
        context.Sender = this;
        context.PostID = postId;

        //Set the argument of the call back
        parameters += this._GetCallbackSearchParameters();
        parameters += RicherComponents_BuildParameterString('PostID', postId);
        parameters += RicherComponents_BuildParameterString('Title', title, true);
        parameters += RicherComponents_BuildParameterString('Type', type);
        parameters += RicherComponents_BuildParameterString('Content', content, true);
        
        actions += RicherComponents_BuildActionString(CallServerActionEnum.EditPost, parameters);

        //Call the server
        this._CallServer(actions, context);
    }, // PostEdit

    /// <summary>
    /// Creates a new post in the database
    /// </summary>
    /// <param name="title">Post title</param>
    /// <param name="type">Post type</param>
    /// <param name="content">Post content</param>
    /// <param name="parentPostId">Parent Post ID (optional)</param>
    PostCreate : function(title, type, content, parentPostId) 
    {
        var actions = '';
        var parameters = '';
        var context = null;

        //set the context values
        context = new Object();
        context.Action = CallServerActionEnum.CreatePost;
        context.Sender = this;

        //Set the argument of the call back
        parameters += this._GetCallbackSearchParameters();
        parameters += RicherComponents_BuildParameterString('Title', title, true);
        parameters += RicherComponents_BuildParameterString('Type', type);
        parameters += RicherComponents_BuildParameterString('Content', content, true);
        
        if (parentPostId)
            parameters += RicherComponents_BuildParameterString('ParentPostID', parentPostId);

        actions += RicherComponents_BuildActionString(CallServerActionEnum.CreatePost, parameters);

        //Call the server
        this._CallServer(actions, context);
    }, // PostCreate
    
    /// <summary>
    /// Search for posts
    /// </summary>
    /// <param name="searchFor">Keyword to find</param>
    /// <param name="postedBy">Posted by user</param>
    /// <param name="startDate">Start date range</param>
    /// <param name="endDate">End date range</param>
    SearchPosts : function( searchFor, postedBy, startDate, endDate )
    {
        var actions = '';
        var parameters = '';
        var context = null;
        
        //update hidden fields
        $( this._searchForHiddenID ).value = this._searchFor;
        $( this._searchPostedByHiddenID ).value = this._searchPostedBy;
        if ( this._GetSearchFormStartDate() != null )
            $( this._searchStartDateHiddenID ).value = this._GetSearchFormStartDate().ToString();
        else
            $( this._searchStartDateHiddenID ).value = '';
        if ( this._GetSearchFormEndDate() != null )
            $( this._searchEndDateHiddenID ).value = this._GetSearchFormEndDate().ToString();
        else
            $( this._searchEndDateHiddenID ).value = '';
        $( this._searchSearchActiveHiddenID ).value = 'false';

        //set the context values
        context = new Object();
        context.Action = CallServerActionEnum.SearchPosts;
        context.Sender = this;

        parameters = this._GetCallbackSearchParameters(searchFor, postedBy, startDate, endDate, true);        
        actions += RicherComponents_BuildActionString(CallServerActionEnum.SearchPosts, parameters);

        //Call the server
        this._CallServer(actions, context);
    }, // SearchPosts

    /// <summary>
    /// Set the active page number for the RichMessageBoard
    /// </summary>
    /// <param name="pageNumber">Page Number</param>
    GoToPage: function(pageNumber) 
    {
        var actions = '';
        var parameters = '';
        var context = null;
        
        //update current page
        this._SetCurrentPage( pageNumber );

        //Show loading box
        this._ShowLoadingBox();

        //set the context values
        context = new Object();
        context.Action = CallServerActionEnum.GoToPage;
        context.Sender = this;

        //Set the argument of the call back
        parameters += this._GetCallbackSearchParameters();
        parameters += RicherComponents_BuildParameterString('PageNum', pageNumber);
        actions += RicherComponents_BuildActionString(CallServerActionEnum.GoToPage, parameters);
        
        //Call the server
        this._CallServer(actions, context);
    }, // GoToPage
    
    /// <summary>
    /// Set the active post item for this RichMessageBoard
    /// </summary>
    /// <param name="postID">Post ID</param>
    GoToPost: function( postID ) 
    {
        var actions = '';
        var parameters = '';
        var context = null;
        
        //If the post is not found then means that the post is on another page
        //rather than the current one
        if ( $(this.ID + '_PostContent_' + postID) == null )
        {
            //Show loading box
            this._ShowLoadingBox();

            //set the context values
            context = new Object();
            context.Action = CallServerActionEnum.GoToPost;
            context.Sender = this;
            context.PostID = postID;

            //Set the argument of the call back
            parameters += this._GetCallbackSearchParameters();
            parameters += RicherComponents_BuildParameterString('PostID', postID);
            actions += RicherComponents_BuildActionString(CallServerActionEnum.GoToPost, parameters);

            //Call the server
            this._CallServer(actions, context);
        }
        else
        {
            //if the post is on the current page then just show the content to the user
            this._PostExpandOrCollapse( postID, true );
        }
    }, // GoToPost
    
    /// <summary>
    /// Clear the current search criteria
    /// </summary>
    ClearCurrentSearch : function()
    {
        var actions = '';
        var context = null;
        
        //Show loading box
        this._ShowLoadingBox();
        
        //Clear current search criteria values
        this._searchFor = null;
        this._searchPostedBy = null;
        this._searchStartDate.ClearDate();
        this._searchEndDate.ClearDate();
        
        //update hidden fields
        $( this._searchForHiddenID ).value = '';
        $( this._searchPostedByHiddenID ).value = '';
        $( this._searchStartDateHiddenID ).value = '';
        $( this._searchEndDateHiddenID ).value = '';
        $( this._searchSearchActiveHiddenID ).value = 'false';
        
        //set the context values
        context = new Object();
        context.Action = CallServerActionEnum.ClearSearch;
        context.Sender = this;
        
        //Set the argument of the call back
        actions += RicherComponents_BuildActionString(CallServerActionEnum.ClearSearch, '');
    
        this._searchActive = false;
        
        //Call the server
        this._CallServer(actions, context);
    }, // ClearCurrentSearch
    
    /// <summary>
    /// Returns the callback search parameters
    /// </summary>
    /// <param name="searchFor">Keyword to find</param>
    /// <param name="postedBy">Posted by user</param>
    /// <param name="startDate">Start date range</param>
    /// <param name="endDate">End date range</param>
    /// <param name="force">If _searchActive is false then this method returns an empty
    /// string, if force is set to true then no mather what it always returns the parameters 
    /// information</param>
    _GetCallbackSearchParameters : function(searchFor, postedBy, startDate, endDate, force)
    {
        var parameters = '';
        
        if ( this._searchActive || force )
        {
            if ( endDate == null )
                endDate = this._GetSearchFormEndDate();
            if ( startDate == null )
                startDate = this._GetSearchFormStartDate();
            if ( searchFor == null )
                searchFor = this._searchFor;
            if ( postedBy == null )
                postedBy = this._searchPostedBy;
            
            if ( searchFor != null && searchFor != '' )
                parameters += RicherComponents_BuildParameterString('SearchFor', searchFor, true);
                
            if ( postedBy != null && postedBy != '' )
                parameters += RicherComponents_BuildParameterString('PostedBy', postedBy, true);
                
            if ( startDate != null )
                parameters += RicherComponents_BuildParameterString('StartDate', startDate.ToString());
            
            if ( endDate != null )
                parameters += RicherComponents_BuildParameterString('EndDate', endDate.ToString());
                
            parameters += RicherComponents_BuildParameterString('SearchActive', 'true');
        }
        
        return parameters;
    }, // _GetCallbackSearchParameters
    
    /// <summary>
    /// Set the current page number
    /// </summary>
    /// <param name="pageNumber">Page number to set</param>
    _SetCurrentPage : function( pageNumber )
    {
        this.CurrentPage = pageNumber;
        $( this._currentPageHiddenID ).value = pageNumber;
    }, // _SetCurrentPage
    
    /// <summary>
    /// Hides the loading box
    /// </summary>
    _HideLoadingBox : function()
    {
        var loadDiv = $( this.ID + '_LoadingInfoBox' );
        var loadMsg = $( this.ID + '_LoadingMessage' );
         
        if ( loadDiv != null )
        {
            this._MainContainerElement.style.overflow = '';
            this._MainContainerElement.style.width = '';
            this._MainContainerElement.style.height = '';

            this._MainContainerElement.removeChild( loadDiv );
            this._MainContainerElement.removeChild( loadMsg );
            loadMsg.innerHTML = '';
            loadDiv.innerHTML = '';
        }
    }, // _HideLoadingBox

    /// <summary>
    /// Shows the loading box indicating that the MessageBoard is processing information
    /// </summary>
    _ShowLoadingBox: function() 
    {
        var width = GetWidth(this._MainContainerElement);
        var height = GetHeight(this._MainContainerElement);
        var loadDiv = document.createElement('div');
        var loadMsg = document.createElement('div');
        var fadeInFunc = null;

        if (width > 0 && height > 0) 
        {
            loadDiv.setAttribute( 'id', this.ID + '_LoadingInfoBox' );
            loadDiv.style.width = width + 'px';
            loadDiv.style.height = height + 'px';
            loadDiv.style.top = '-' + height + 'px';
            loadDiv.style.left = '0px';
            loadDiv.className = 'LoadingBox';
            
            if ( loadDiv.style.filter != null )
                loadDiv.style.filter = 'alpha(opacity=0)';
            loadDiv.style.MozOpacity = 0;
            loadDiv.style.opacity = 0;
            loadDiv.setAttribute('opac', '0');

            loadMsg.appendChild( document.createTextNode('Loading...') );
            loadMsg.setAttribute( 'id', this.ID + '_LoadingMessage' );
            loadMsg.className = 'LoadingMessage';
            loadMsg.style.top = '-' + ((height * 2) - 20) + 'px'; //'-' + Math.floor( (height / 2) ) - height + 'px';
            loadMsg.style.left = '20px'; //Math.floor( (width / 2) ) + 'px';

            this._MainContainerElement.style.overflow = 'hidden';
            this._MainContainerElement.style.width = width + 'px';
            this._MainContainerElement.style.height = height + 'px';

            this._MainContainerElement.appendChild(loadDiv);
            this._MainContainerElement.appendChild(loadMsg);
            
            fadeInFunc = function()
            {
                if ( loadDiv == null )
                    return; 
                    
                var opac = loadDiv.getAttribute( 'opac' ) * 1;
                
                if ( opac < 20 && loadDiv.parentNode != null )
                {
                    opac += 1;
                    
                    if ( loadDiv.style.filter != null )
                        loadDiv.style.filter = 'alpha(opacity=' + opac + ')';
                    loadDiv.style.MozOpacity = opac / 100;
                    loadDiv.style.opacity = opac / 100;
                    loadDiv.setAttribute('opac', opac);
                    setTimeout( function() { fadeInFunc(); }, 0);
                }
            };
            
            setTimeout( function() { fadeInFunc(); }, 0);
        }
    }, // _ShowLoadingBox

    /// <summary>
    /// Shows an error dialog
    /// </summary>
    /// <param name="title">Dialog title</param>
    /// <param name="errorMessage">Error message to show</param>
    _ShowErrorDialog: function(title, errorMessage) {
        //Set dialog parameters
        this._PopupContainerElement.Parameters = new Object();
        this._PopupContainerElement.Parameters.DialogTitle = title;
        this._PopupContainerElement.Parameters.ErrorMessage = errorMessage;
        this._PopupContainerElement.Parameters.Action = DialogActionEnum.ErrorMessage;

        //Show the dialog
        this._ShowDialog();
    }, // _ShowErrorDialog

    /// <summary>
    /// Shows the search dialog to the user
    /// </summary>
    _ShowSearchDialog: function() {
        var dialog = null;
        var dialogContent = null;

        dialogContent = this._CreateSearchForm();
        dialog = this._PopupCreateSearchDialog(dialogContent);

        this._PopupContainerElement.innerHTML = dialog.ToHTML();
        this._PopupContainerElement.style.display = 'block';

        $('searchStartDateContainerDiv').appendChild(this._searchStartDate.MainContainerElement);
        $('searchEndDateContainerDiv').appendChild(this._searchEndDate.MainContainerElement);
        this._searchStartDate.ShowControl();
        this._searchEndDate.ShowControl();

        this._ShowModalDialog();
    }, // _ShowSearchDialog

    /// <summary>
    /// Shows the dialog to the user
    /// </summary>
    _ShowDialog: function() 
    {
        var dialog = null;
        var dialogContent = null;
        var dialogRTBContainer = null;
        var isErrorDialog = this._PopupContainerElement.Parameters.Action == DialogActionEnum.ErrorMessage;

        if ( isErrorDialog ) 
        {
            dialogContent = this._ErrorDialogMessageCreate
                            (
                                this._PopupContainerElement.Parameters.DialogTitle,
                                this._PopupContainerElement.Parameters.ErrorMessage
                            );
            dialog = this._PopupCreateErrorDialog(dialogContent);
        }
        else 
        {
            dialogContent = this._FormCreate(this._PopupContainerElement.Parameters.DialogTitle);
            dialog = this._PopupCreateDialog(dialogContent);
        }

        this._PopupContainerElement.innerHTML = dialog.ToHTML();

        if ( ! isErrorDialog ) 
        {
            dialogRTBContainer = $(this._DialogRichTextBoxContainerID);
            dialogRTBContainer.appendChild(this._RichTextBoxContainerElement);

            this._RichTextBoxContainerElement.style.display = 'block';
            this._RichTextBoxContainerElement.style.visibility = 'visible';

            this._PopupContainerElement.style.display = 'block';

            //Initialize the RTB (needed for firefox usage)
            RTB_Initialize(frames[this.RichTextBoxID + '_x5'], true, false, '', this.RichTextBoxID + '_x5', false);
        }

        this._ShowModalDialog();
    }, // _ShowDialog

    /// <summary>
    /// Shows the modal dialog
    /// </summary>
    _ShowModalDialog: function() {
        this._IsDialogOpened = true;
        ModalDialog_ShowDialog(this._DialogID);
    }, // _ShowModalDialog

    /// <summary>
    /// This function is implemented/overrided by the Render 
    /// function on the server side.
    /// </summary>
    /// <param name="arg">Arguments</param>
    /// <param name="context">Context</param>
    _CallServer: function(arg, context) {
        //Do nothing
    }, // _CallServer

    /// <summary>
    /// This function handles the CallServer Response event data
    /// </summary>
    /// <param name="serverResponse">Server Response Object</param>
    /// <param name="context">Context</param>
    _CallServerResponse : function(serverResponse, context) 
    {
        var fixedServerResponse = null;
        var newViewStateValue = null;
        var thisRef = null;
        
        //Get this reference
        thisRef = context.Sender;

        //Check for server errors first
        if ( serverResponse.indexOf('ERROR:') == 0 )
        {
            //ignore the ERROR: keyword
            alert( serverResponse.substring( 6 ) );
            
            //Perform error action
            switch ( context.Action )
            {
                case CallServerActionEnum.GoToPage:
                case CallServerActionEnum.RatePost:
                case CallServerActionEnum.DeletePost:
                case CallServerActionEnum.ClosePost:
                case CallServerActionEnum.CreatePost:
                case CallServerActionEnum.EditPost:
                case CallServerActionEnum.GoToPost:
                case CallServerActionEnum.ClearSearch:  
                    thisRef._HideLoadingBox();
                    thisRef._searchActive = false;
                    break;
                    
                case CallServerActionEnum.SearchPosts:
                    thisRef._HideLoadingBox();
                    break;
                
                default:
                    alert('Invalid action requested (_CallServerResponse [Error Action])');
                    break;
            }
        }
        else
        {        
            //When the pipe "|" character begins the string is because the new viewstate is next and another pipe "|"
            //is at the ending of the viewstate value
            if ( serverResponse.indexOf('|') == 0 )
            {
                //Get first the new view state value
                newViewStateValue = serverResponse.substring( 1, serverResponse.indexOf('|', 1) );
                //Get the server response
                fixedServerResponse = serverResponse.substring( serverResponse.indexOf('|', 1) + 1 );
                
                //Update the view state hidden field
                //$( '__VIEWSTATE' ).value = newViewStateValue;
                //ASPNET_InitCallback();
                //alert($( '__VIEWSTATE' ).value);
                //alert(newViewStateValue);
            }
            else
            {
                //set the fixed response as the server response
                fixedServerResponse = serverResponse;
            }

            //clear size of the main container if for any reason it was changed
            if (thisRef._MainContainerElement != null) 
            {
                thisRef._MainContainerElement.style.width = '';
                thisRef._MainContainerElement.style.height = '';
            }

            switch (context.Action) 
            {
                case CallServerActionEnum.GoToPage:
                    thisRef._CallServerResponse_GoToPage(fixedServerResponse, context);
                    break;

                case CallServerActionEnum.RatePost:
                    thisRef._CallServerResponse_RatePost(fixedServerResponse, context);
                    break;

                case CallServerActionEnum.DeletePost:
                    thisRef._CallServerResponse_DeletePost(fixedServerResponse, context);
                    break;

                case CallServerActionEnum.ClosePost:
                    thisRef._CallServerResponse_ClosePost(fixedServerResponse, context);
                    break;

                case CallServerActionEnum.CreatePost:
                    thisRef._CallServerResponse_CreatePost(fixedServerResponse, context);
                    break;

                case CallServerActionEnum.EditPost:
                    thisRef._CallServerResponse_EditPost(fixedServerResponse, context);
                    break;
                    
                case CallServerActionEnum.SearchPosts:
                    thisRef._CallServerResponse_SearchPosts(fixedServerResponse, context);
                    break;
                    
                case CallServerActionEnum.GoToPost:
                    thisRef._CallServerResponse_GoToPost(fixedServerResponse, context);
                    break;
                    
                case CallServerActionEnum.ClearSearch:
                    thisRef._CallServerResponse_ClearSearch(fixedServerResponse, context);
                    break;

                default:
                    alert('Invalid action requested (_CallServerResponse)');
            }
        }
    }, // _CallServerResponse
    
    /// <summary>
    /// This function handles the CallServer Response ClearSearch event data
    /// </summary>
    /// <param name="serverResponse">Server Response Object</param>
    /// <param name="context">Context</param>
    _CallServerResponse_ClearSearch : function(serverResponse, context) 
    {
        this._MainContainerElement.innerHTML = serverResponse;
    }, // _CallServerResponse_ClearSearch
    
    /// <summary>
    /// This function obtain the result of the search process and fix the 
    /// server response string
    /// </summary>
    /// <param name="serverResponse">Server Response Object</param>
    _CallServerResponse_SerchActive : function(serverResponse)
    {
        var fixedServerResponse = null;
        var listOfRecordsFound = null;
        
        fixedServerResponse = serverResponse;
        if ( this._searchActive )
        {        
            //Get first the list of records found
            listOfRecordsFound = fixedServerResponse.substring( 0, fixedServerResponse.indexOf('|') );
            //Get the server response
            fixedServerResponse = fixedServerResponse.substring( fixedServerResponse.indexOf('|') + 1 );
            //get founded records
            this._searchCurrentPosts = listOfRecordsFound.split( ',' );
            //save founded records on the hidden object
            $( this._searchSearchActiveHiddenID ).value = 'true';
        }
        
        return fixedServerResponse;
    }, // _CallServerResponse_SerchActive
    
    /// <summary>
    /// This function handles the CallServer Response SearchPosts event data
    /// </summary>
    /// <param name="serverResponse">Server Response Object</param>
    /// <param name="context">Context</param>
    _CallServerResponse_SearchPosts : function(serverResponse, context) 
    {
        var fixedServerResponse = null;
        var listOfRecordsFound = null;
        
        this._searchActive = true;
        
        //set the new rendered content for the board
        this._MainContainerElement.innerHTML = this._CallServerResponse_SerchActive( serverResponse );
        
        //set the first founded record
        this._searchCurrentPost = 0;
        //this.GoToPost( this._searchCurrentPost ); -> This starts an infite loop between SearchPosts and GoToPost I DON'T KNOW WHY
        window.setTimeout(function() { context.Sender.GoToPost( context.Sender._searchCurrentPosts[ context.Sender._searchCurrentPost ] ); }, 100);
    }, // _CallServerResponse_SearchPosts
    
    /// <summary>
    /// This function handles the CallServer Response GoToPost event data
    /// </summary>
    /// <param name="serverResponse">Server Response Object</param>
    /// <param name="context">Context</param>
    _CallServerResponse_GoToPost : function(serverResponse, context) 
    {
        //FORMAT OF THE SERVER RESPONSE: [CURRENT PAGE NUMBER] + ',' + [CONTENT]
        var content = null;
        var currentPage = null;
        var postId = null;
        var tempContent = null;
        
        serverResponse = this._CallServerResponse_SerchActive( serverResponse );        
        currentPage = serverResponse.substring( 0, serverResponse.indexOf(',') );
        tempContent = serverResponse.substring( serverResponse.indexOf(',') + 1 );
        
        postId = context.PostID;
        content = tempContent;
        
        this._SetCurrentPage( currentPage );
        this._MainContainerElement.innerHTML = content;
        this.PostExpandContent( postId );
    }, // _CallServerResponse_GoToPost

    /// <summary>
    /// This function handles the CallServer Response EditPost event data
    /// </summary>
    /// <param name="serverResponse">Server Response Object</param>
    /// <param name="context">Context</param>
    _CallServerResponse_EditPost: function(serverResponse, context) 
    {
        //FORMAT OF THE SERVER RESPONSE: [CURRENT PAGE NUMBER] + ',' + [CONTENT]
        var content = null;
        var currentPage = null;
        var postId = null;
        var tempContent = null;
        
        serverResponse = this._CallServerResponse_SerchActive( serverResponse );
        currentPage = serverResponse.substring( 0, serverResponse.indexOf(',') );
        tempContent = serverResponse.substring( serverResponse.indexOf(',') + 1 );
        
        postId = context.PostID;
        content = tempContent;
        
        this._SetCurrentPage( currentPage );
        this._MainContainerElement.innerHTML = content;
        this.PostExpandContent( postId );
    }, // _CallServerResponse_EditPost

    /// <summary>
    /// This function handles the CallServer Response CreatePost event data
    /// </summary>
    /// <param name="serverResponse">Server Response Object</param>
    /// <param name="context">Context</param>
    _CallServerResponse_CreatePost: function(serverResponse, context) 
    {   
        //FORMAT OF THE SERVER RESPONSE: [NEW POST ID] + ',' + [CURRENT PAGE NUMBER] + ',' + [CONTENT]
        var content = null;
        var currentPage = null;
        var postId = null;
        var tempContent = null;
        
        serverResponse = this._CallServerResponse_SerchActive( serverResponse );
        postId = serverResponse.substring( 0, serverResponse.indexOf(',') );
        tempContent = serverResponse.substring( serverResponse.indexOf(',') + 1 );
        
        currentPage = tempContent.substring( 0, tempContent.indexOf(',') );
        tempContent = tempContent.substring( tempContent.indexOf(',') + 1 );
        
        content = tempContent;
        
        this._SetCurrentPage( currentPage );
        this._MainContainerElement.innerHTML = content;
        this.PostExpandContent( postId );
    }, // _CallServerResponse_CreatePost

    /// <summary>
    /// This function handles the CallServer Response ClosePost event data
    /// </summary>
    /// <param name="serverResponse">Server Response Object</param>
    /// <param name="context">Context</param>
    _CallServerResponse_ClosePost: function(serverResponse, context) 
    {
        alert('The thread has been closed');
        serverResponse = this._CallServerResponse_SerchActive( serverResponse );
        this._MainContainerElement.innerHTML = serverResponse;
    }, // _CallServerResponse_ClosePost

    /// <summary>
    /// This function handles the CallServer Response DeletePost event data
    /// </summary>
    /// <param name="serverResponse">Server Response Object</param>
    /// <param name="context">Context</param>
    _CallServerResponse_DeletePost: function(serverResponse, context) 
    {
        alert('The post has been deleted');
        serverResponse = this._CallServerResponse_SerchActive( serverResponse );
        this._MainContainerElement.innerHTML = serverResponse;
    }, // _CallServerResponse_DeletePost

    /// <summary>
    /// This function handles the CallServer Response GoToPage event data
    /// </summary>
    /// <param name="serverResponse">Server Response Object</param>
    /// <param name="context">Context</param>
    _CallServerResponse_GoToPage: function(serverResponse, context) 
    {
        serverResponse = this._CallServerResponse_SerchActive( serverResponse );
        this._MainContainerElement.innerHTML = serverResponse;

        if (context.PostID != null) {
            //Show the content to the user
            this.PostExpandContent(context.PostID);
        }
    }, // _CallServerResponse_GoToPage

    /// <summary>
    /// This function handles the CallServer Response RatePost event data
    /// </summary>
    /// <param name="serverResponse">Server Response Object</param>
    /// <param name="context">Context</param>
    _CallServerResponse_RatePost: function(serverResponse, context) 
    {
        var rateDiv = null;

        rateDiv = $(this.ID + '_RatingBox_' + context.PostID);
        rateDiv.innerHTML = serverResponse;
    }, // _CallServerResponse_RatePost

    /// <summary>
    /// This function handles the CallServer Error event data
    /// </summary>
    /// <param name="message">Error Message</param>
    /// <param name="context">Context</param>
    _CallServerError: function(message, context) {
        alert('An exception was thrown when trying to get information from the server. More info: "' + message + '"');
    }, // _CallServerError

    /// <summary>
    /// Checks if the rich text box container element is initialized or not.
    /// If not then initialize it.
    /// </summary>
    _CheckRichTextBoxContainerElement: function() {
        if (this._RichTextBoxContainerElement == null)
            this._RichTextBoxContainerElement = $(this._RichTextBoxContainerID);

        if (this._RichTextBoxContainerElement != null && this._RichTextBoxContainerElement.parentNode != null)
            this._RichTextBoxContainerElement.parentNode.removeChild(this._RichTextBoxContainerElement);
    }, // _CheckRichTextBoxContainerElement

    /// <summary>
    /// Checks if the popup container element is initialized or not.
    /// If not then initialize it.
    /// </summary>
    _CheckPopupContainerElement: function() {
        if (this._PopupContainerElement == null)
            this._PopupContainerElement = $(this._PopupDivID);

        if (this._PopupContainerElement != null)
            this._PopupContainerElement.className = this.Theme;
    }, // _CheckPopupContainerElement

    /// <summary>
    /// Checks if the search dates objects are initialized or not.
    /// </summary>
    _CheckSearchDatesObjects: function() 
    {
        if (this._searchStartDate == null && eval('window.' + this.ID + '_dateStart') ) 
        {
            this._searchStartDate = eval('window.' + this.ID + '_dateStart');
            //force to set the main container property (look for the container element)
            this._searchStartDate._GetContainer();
        }

        if (this._searchEndDate == null && eval('window.' + this.ID + '_dateEnd') ) 
        {
            this._searchEndDate = eval('window.' + this.ID + '_dateEnd');
            //force to set the main container property (look for the container element)
            this._searchEndDate._GetContainer();
        }
    }, // _CheckSearchDatesObjects

    /// <summary>
    /// Checks if the main container element is initialized or not.
    /// If not then initialize it.
    /// </summary>
    _CheckMainContainerElement: function() {
        if (this._MainContainerElement == null)
            this._MainContainerElement = $(this._MainContainerID);
    }, // _CheckMainContainerElement

    /// <summary>
    /// Builds and returns the loading rate UI dialog
    /// </summary>
    _BuildRateLoading: function() {
        var loading = null;
        var dialog = null;

        dialog = new RCHTMLObject('div');
        dialog.Attributes.Add('class', this.Theme + ' Rating');

        loading = new RCHTMLObject('div');
        loading.Attributes.Add('class', this.Theme + ' LoadingRate');
        loading.AddControl('Loading Rate...');
        dialog.AddControl(loading);

        return dialog;
    }, // _BuildRateLoading

    /// <summary>
    /// Creates and returns the main input form 
    /// to get the data from the user (RCHTMLObject)
    /// </summary>
    /// <param name="title">Title for the input form</param>
    /// <param name="message">Message to show</param>
    _ErrorDialogMessageCreate: function(title, message) {
        var form = null;
        var control = null;

        //Create the main form
        form = new RCHTMLObject('div');

        //Add the title
        control = new RCHTMLObject('div');
        control.Attributes.Add('class', 'ErrorDialogTitle');
        control.AddControl(title);
        form.AddControl(control);

        //Add the message
        control = new RCHTMLObject('div');
        control.Attributes.Add('class', 'ErrorDialogMessage');
        control.AddControl(message);
        form.AddControl(control);

        //add the close button
        control = RCHTMLObject_CreateAnchor('btnClose', 'ActionButton ErrorDialogButton', 'javascript:void(0);', 'Close');
        control.Attributes.Add('onclick', this.ID + '._DialogClose();');
        form.AddControl(control);

        return form;
    }, // _ErrorDialogMessageCreate 

    /// <summary>
    /// Creates and returns the main input form 
    /// to get the data from the user (RCHTMLObject)
    /// </summary>
    /// <param name="title">Title for the input form</param>
    _FormCreate: function(title) 
    {
        var form = null;
        var table = null;
        var row = null;
        var cell = null;
        var control = null;

        //Create the main form
        form = new RCHTMLObject('div');

        //Add the title
        control = new RCHTMLObject('div');
        control.Attributes.Add('class', 'DialogTitle');
        control.AddControl(title);
        form.AddControl(control);

        //Create the main table
        table = RCHTMLObject_CreateTable(null, 2, 2);
        table.Style.Add('width', '100%');
        form.AddControl(table);

        //Create the post type row
        row = RCHTMLObject_AddRowToTable(table);

        cell = RCHTMLObject_AddCellToRow(row);
        cell.AddControl('Type:');

        cell = RCHTMLObject_AddCellToRow(row);
        cell.Style.Add('width', '5px');

        cell = RCHTMLObject_AddCellToRow(row);
        cell.AddControl(RCHTMLObject_CreateRadio(this._FormRadioListPostTypeID, 'General', PostTypeEnum.GeneralComment, true));
        cell.AddControl('&nbsp;');
        cell.AddControl(RCHTMLObject_CreateRadio(this._FormRadioListPostTypeID, 'News/Info', PostTypeEnum.NewsInfo));
        cell.AddControl('&nbsp;');
        cell.AddControl(RCHTMLObject_CreateRadio(this._FormRadioListPostTypeID, 'Question', PostTypeEnum.Question));
        cell.AddControl('&nbsp;');
        cell.AddControl(RCHTMLObject_CreateRadio(this._FormRadioListPostTypeID, 'Answer', PostTypeEnum.Answer));
        if ( this.UserIsAdmin )
        {
            cell.AddControl('&nbsp;');
            cell.AddControl(RCHTMLObject_CreateRadio(this._FormRadioListPostTypeID, 'Admin Message', PostTypeEnum.AdminMessage));
            
            if ( this._PopupContainerElement.Parameters.IsRoot == 'true' )
            {   
                cell.AddControl('&nbsp;');
                cell.AddControl(RCHTMLObject_CreateRadio(this._FormRadioListPostTypeID, 'Sticky', PostTypeEnum.Sticky));
            }
        }

        //Create the post title row
        row = RCHTMLObject_AddRowToTable(table);

        cell = RCHTMLObject_AddCellToRow(row);
        cell.AddControl('Title:');

        cell = RCHTMLObject_AddCellToRow(row);
        cell.Style.Add('width', '5px');

        cell = RCHTMLObject_AddCellToRow(row);
        control = RCHTMLObject_CreateTextBox(this._FormPostTitleID, '');
        control.Style.Add('width', '99%');
        cell.AddControl(control);

        //Create the post content row
        row = RCHTMLObject_AddRowToTable(table);

        cell = RCHTMLObject_AddCellToRow(row);
        cell.AddControl('Content:');

        cell = RCHTMLObject_AddCellToRow(row);
        cell.Attributes.Add('colspan', 2);

        row = RCHTMLObject_AddRowToTable(table);

        cell = RCHTMLObject_AddCellToRow(row);
        cell.Attributes.Add('colspan', 3);
        cell.AddControl('<div id="' + this._DialogRichTextBoxContainerID + '"></div>');

        //Create the buttons row
        row = RCHTMLObject_AddRowToTable(table);

        cell = RCHTMLObject_AddCellToRow(row);
        cell.Attributes.Add('colspan', 3);
        cell.Style.Add('text-align', 'center');

        control = RCHTMLObject_CreateAnchor('btnClose', 'ActionButton', 'javascript:void(0);', 'Close');
        control.Attributes.Add('onclick', this.ID + '._DialogClose();');
        cell.AddControl(control);

        control = RCHTMLObject_CreateAnchor('btnPost', 'ActionButton', 'javascript:void(0);', 'Post');
        control.Attributes.Add('onclick', this.ID + '._ExecuteDialogAction();');
        control.Style.Add('margin-right', '5px');
        cell.AddControl(control);

        return form;
    }, // _FormCreate

    /// <summary>
    /// Creates and returns the search form (RCHTMLObject)
    /// </summary>
    _CreateSearchForm: function() 
    {
        var form = null;
        var table = null;
        var row = null;
        var cell = null;
        var control = null;

        //Create the main form
        form = new RCHTMLObject('div');

        //Add the title
        control = new RCHTMLObject('div');
        control.Attributes.Add('class', 'DialogTitle');
        control.AddControl('Search for Posts');
        form.AddControl(control);

        //Create the main table
        table = RCHTMLObject_CreateTable(null, 2, 2);
        table.Style.Add('width', '100%');
        form.AddControl(table);

        //Create the search for row
        row = RCHTMLObject_AddRowToTable(table);

        cell = RCHTMLObject_AddCellToRow(row);
        cell.AddControl('Search for:');
        cell.Style.Add('width', '120px');

        cell = RCHTMLObject_AddCellToRow(row);
        cell.Style.Add('width', '5px');

        cell = RCHTMLObject_AddCellToRow(row);
        control = RCHTMLObject_CreateTextBox(this._SearchFormSearchForID, this._searchFor);
        control.Style.Add('width', '99%');
        cell.AddControl(control);
        
        //Create the example row
        row = RCHTMLObject_AddRowToTable(table);
       
        cell = RCHTMLObject_AddCellToRow(row); //display nothing on this
        cell = RCHTMLObject_AddCellToRow(row); //display nothing on this
        cell = RCHTMLObject_AddCellToRow(row);
        //example row info
        control = new RCHTMLObject( 'span' );
        control.Attributes.Add( 'class', 'InfoSmall' );
        control.AddControl( 'Sample: "find an string" OR (word AND NOT notIncluded)' );
        cell.AddControl(control);

        //Create the posted by row
        row = RCHTMLObject_AddRowToTable(table);

        cell = RCHTMLObject_AddCellToRow(row);
        cell.AddControl('Posted By:');
        cell.Style.Add('width', '120px');

        cell = RCHTMLObject_AddCellToRow(row);
        cell.Style.Add('width', '5px');

        cell = RCHTMLObject_AddCellToRow(row);
        control = RCHTMLObject_CreateTextBox(this._SearchFormPostedByID, this._searchPostedBy);
        control.Style.Add('width', '99%');
        cell.AddControl(control);

        //Create the date range row
        row = RCHTMLObject_AddRowToTable(table);

        cell = RCHTMLObject_AddCellToRow(row);
        cell.AddControl('Between dates:');
        cell.Style.Add('width', '120px');

        cell = RCHTMLObject_AddCellToRow(row);
        cell.Style.Add('width', '5px');

        cell = RCHTMLObject_AddCellToRow(row);
        cell.AddControl('<table cellpadding="0" cellspacing="0" border="0"><tr><td>');
        cell.AddControl('<div id="searchStartDateContainerDiv"></div>');
        cell.AddControl('</td><td>');
        cell.AddControl('&nbsp;&nbsp;&nbsp;and&nbsp;&nbsp;&nbsp;');
        cell.AddControl('</td><td>');
        cell.AddControl('<div id="searchEndDateContainerDiv"></div>');
        cell.AddControl('</td></tr></table>');
        //control = RCHTMLObject_CreateTextBox(this._SearchFormPostedByID, '');
        //control.Style.Add( 'width', '99%' );
        //cell.AddControl( control );

        //Create the buttons row
        row = RCHTMLObject_AddRowToTable(table);

        cell = RCHTMLObject_AddCellToRow(row);
        cell.Attributes.Add('colspan', 3);
        cell.Style.Add('text-align', 'center');

        control = RCHTMLObject_CreateAnchor('btnClose', 'ActionButton', 'javascript:void(0);', 'Close');
        control.Attributes.Add('onclick', this.ID + '._DialogClose();');
        cell.AddControl(control);

        control = RCHTMLObject_CreateAnchor('btnPost', 'ActionButton', 'javascript:void(0);', 'Search');
        control.Attributes.Add('onclick', this.ID + '._ExecuteSearchAction();');
        control.Style.Add('margin-right', '5px');
        cell.AddControl(control);

        return form;
    }, // _CreateSearchForm
    
    /// <summary>
    /// Executes the search action
    /// </summary>
    _ExecuteSearchAction : function()
    {
        var message = null;
        
        if ( this._SearchFormValidateUserInput() )
        {    
            //Show loading box
            this._ShowLoadingBox();
            
            //get search filter values
            this._searchFor = this._GetSearchFormSearchFor();
            this._searchPostedBy = this._GetSearchFormPostedBy();
            
            //search for the posts
            this.SearchPosts( this._searchFor, this._searchPostedBy, this._GetSearchFormStartDate(), this._GetSearchFormEndDate() );
            
            //Close the dialog
            this._DialogClose();
        }
    }, // _ExecuteSearchAction
    
    /// <summary>
    /// Search button click event handler
    /// </summary>
    _SearchButtonClick : function()
    {
        if ( ! this._searchActive )
            this.ShowSearchDialog();
        else
            this.ClearCurrentSearch();
    }, // _SearchButtonClick

    /// <summary>
    /// Executes the action indicated by the dialog
    /// </summary>
    _ExecuteDialogAction : function() 
    {
        var title = null;
        var type = null;
        var content = null;

        if ( this._FormValidateUserInput() ) 
        {
            //Show loading box
            this._ShowLoadingBox();

            //get the input data from the user
            title = this._FormGetTitle();
            type = this._FormGetType();
            content = this._FormGetRichTextBoxHTMLContent();

            switch (this._PopupContainerElement.Parameters.Action) 
            {
                case DialogActionEnum.EditPost:
                    this.PostEdit
                    (
                        this._PopupContainerElement.Parameters.PostID,
                        title,
                        type,
                        content
                    );
                    break;

                case DialogActionEnum.NewPost:
                    this.PostCreate(title, type, content);
                    break;

                case DialogActionEnum.ReplyToPost:
                    this.PostCreate(title, type, content, this._PopupContainerElement.Parameters.PostID);
                    break;

                case DialogActionEnum.ErrorMessage:
                    //do nothing
                    break;

                default:
                    alert('Invalid action \'' + action + '\'');
            }

            //Close the dialog
            this._DialogClose();
        }
    }, // _ExecuteDialogAction
    
    /// <summary>
    /// Checks for the user input and returns if is ok or not
    /// </summary>
    _SearchFormValidateUserInput : function()
    {
        var searchFor = null;
        var postedBy = null;
        var startDate = null;
        var endDate = null;
        var message = null;
        
        searchFor = this._GetSearchFormSearchFor();
        postedBy = this._GetSearchFormPostedBy();
        startDate = this._GetSearchFormStartDate();
        endDate = this._GetSearchFormEndDate();
        
        if ( searchFor == '' && postedBy == '' &&
             startDate == null && endDate == null )
        {
            message = 'No search filter was provided';
        }
        else if ( startDate != null && endDate != null && 
                  startDate > endDate )
        {
            message = 'Invalid date range';
        }
        
        if ( message != null )
            alert( message );
            
        return message == null;
    }, // _SearchFormValidateUserInput
    
    /// <summary>
    /// Returns the search form search for field value
    /// </summary>
    _GetSearchFormSearchFor : function()
    {
        return $( this._SearchFormSearchForID ).value;
    }, // _GetSearchFormSearchFor
    
    /// <summary>
    /// Set the search form search for field value
    /// </summary>
    _SetSearchFormSearchFor : function( value )
    {
        $( this._SearchFormSearchForID ).value = value;
    }, // _SetSearchFormSearchFor
    
    /// <summary>
    /// Returns the search form posted by field value
    /// </summary>
    _GetSearchFormPostedBy : function()
    {
        return $( this._SearchFormPostedByID ).value;
    }, // _GetSearchFormPostedBy
    
    /// <summary>
    /// Set the search form posted by field value
    /// </summary>
    _SetSearchFormPostedBy : function( value )
    {
        $( this._SearchFormPostedByID ).value = value;
    }, // _SetSearchFormPostedBy
    
    /// <summary>
    /// Returns the search form start date field value
    /// </summary>
    _GetSearchFormStartDate : function()
    {
        return this._searchStartDate.SelectedDate;
    }, // _GetSearchFormStartDate
    
    /// <summary>
    /// Returns the search form end date field value
    /// </summary>
    _GetSearchFormEndDate : function()
    {
        return this._searchEndDate.SelectedDate;
    }, // _GetSearchFormEndDate

    /// <summary>
    /// Checks for the user input and returns if is ok or not
    /// </summary>
    _FormValidateUserInput : function() 
    {
        var title = null;
        var content = null;
        var validation = false;

        //get the input data from the user
        title = this._FormGetTitle();
        content = this._FormGetRichTextBoxHTMLContent();

        if (title == '') {
            alert('Please insert the title for the post');
            $(this._FormPostTitleID).focus();
        }
        else if (content == '')
            alert('Please insert the content for the post');
        else
            validation = true;

        return validation;
    }, // _FormValidateUserInput

    /// <summary>
    /// Returns the current RichTextBox HTML content
    /// entered by the user
    /// </summary>
    _FormGetRichTextBoxHTMLContent: function() {
        var frame = null;
        var html = null;

        //get the RTB frame object
        frame = document.getElementById(this.RichTextBoxID + '_x5');
        html = frame.contentWindow.document.body.innerHTML;

        return html;
    }, // _FormGetRichTextBoxHTMLContent

    /// <summary>
    /// Sets the RichTextBox HTML content
    /// </summary>
    /// <param name="htmlContent">HTML Content</param>
    _FormSetRichTextBoxHTMLContent: function(htmlContent) {
        /*
        var frame = null;
        var chkHTMLMode = null;
        var rtbID = null;
        
        /*
        //Set the ID of the RTB
        rtbID = 'RTB' + this.ID;
        //get the check box that changes between html mode and normal mode
        chkHTMLMode = $( rtbID + '_ShowHTML' );
        //get the RTB frame object
        frame = document.getElementById( rtbID + '_x5' );
        //Change to normal view
        RTB_ChangeMode( frame, false, true );
        chkHTMLMode.checked = false;
        
        //Set the HTML text
        RTB_PasteFromHTML( htmlContent, frame );
        * /
        
        var hidden = null;
        
        //Set the ID of the RTB
        rtbID = 'RTB' + this.ID;
        //get the check box that changes between html mode and normal mode
        chkHTMLMode = $( rtbID + '_ShowHTML' );
        //get the RTB frame object
        frame = FindAjaxFrame( rtbID + '_x5' );
        //frame = document.getElementById( rtbID + '_x5' );
        //Change to normal view
        
        if ( chkHTMLMode.checked )
        {
        RTB_ChangeMode( frame, false, true );
        chkHTMLMode.checked = false;
        }
        
        //The very first time that the RTB shows it uses this value instead 
        //of the RTB_PasteFromHTML function
        hidden = $( rtbID );
        hidden.value = htmlContent;
        
        if ( frame.contentWindow )
        frame.contentWindow.document.body.innerHTML = '';
        else
        frame.document.body.innerHTML = '';
            
        RTB_PasteFromHTML( htmlContent, frame );
        RTB_DisplayWordCount( frame );
        
        //frame.contentWindow.document.body.focus();
        //RTB_SaveSnapshot( frame );
        
        //Set the HTML text
        //RTB_PasteFromHTML( htmlContent, frame );
        */

        //////////////////////////////////////////////////////////////////////////////

        var frame = null;
        var chkHTMLMode = null;
        var hidden = null;

        //get the check box that changes between html mode and normal mode
        chkHTMLMode = $(this.RichTextBoxID + '_ShowHTML');
        //get the RTB frame object
        frame = FindAjaxFrame(this.RichTextBoxID + '_x5');

        //Change to normal view
        if (chkHTMLMode.checked) {
            RTB_ChangeMode(frame, false, true);
            chkHTMLMode.checked = false;
        }

        //The very first time that the RTB shows it uses this value instead 
        //of the RTB_PasteFromHTML function
        hidden = $(this.RichTextBoxID);
        hidden.value = htmlContent;

        if (frame.contentWindow)
            frame.contentWindow.document.body.innerHTML = htmlContent;
        else
            frame.document.body.innerHTML = htmlContent;

        //RTB_PasteFromHTML( htmlContent, frame );
        RTB_DisplayWordCount(frame);
    }, // _FormSetRichTextBoxHTMLContent

    /// <summary>
    /// Returns the post type selected by the user
    /// </summary>
    _FormGetType: function() {
        var inputs = null;
        var value = null;

        inputs = document.getElementsByTagName('input');
        for (var i = 0; i < inputs.length && value == null; i++)
            if (inputs[i].type == 'radio' && inputs[i].name == this._FormRadioListPostTypeID && inputs[i].checked)
            value = inputs[i].value;

        return value;
    }, // _FormGetType

    /// <summary>
    /// Set the post type
    /// </summary>
    _FormSetType : function( type ) 
    {
        var inputs = null;
        var found = false;

        inputs = document.getElementsByTagName('input');
        for (var i = 0; i < inputs.length && !found; i++) 
        {
            if (inputs[i].type == 'radio' && inputs[i].name == this._FormRadioListPostTypeID && inputs[i].value == type) 
            {
                inputs[i].checked = true;
                found = true;
            }
        }
    }, // _FormSetType

    /// <summary>
    /// Returns the title entered by the user
    /// </summary>
    _FormGetTitle: function() 
    {
        return $( this._FormPostTitleID ).value;
    }, // _FormGetTitle

    /// <summary>
    /// Close the current opened dialog
    /// </summary>
    _DialogClose: function() 
    {
        if (this._IsDialogOpened) 
        {
            var isErrorDialog = this._PopupContainerElement.Parameters.Action == DialogActionEnum.ErrorMessage;
            var isSearchDialog = this._PopupContainerElement.Parameters.Action == DialogActionEnum.SearchPosts;

            //Clear parameters
            this._PopupContainerElement.Parameters = null;

            if ( ! isErrorDialog && !isSearchDialog ) 
            {
                //Clear any contents of the RichTextBox
                this._FormSetRichTextBoxHTMLContent('');

                this._RichTextBoxContainerElement.parentNode.removeChild(this._RichTextBoxContainerElement);
                this._RichTextBoxContainerElement.style.display = 'none';
            }

            if ( isSearchDialog ) 
            {
                this._searchStartDate.MainContainerElement.parentNode.removeChild(this._searchStartDate.MainContainerElement)
                this._searchEndDate.MainContainerElement.parentNode.removeChild(this._searchEndDate.MainContainerElement)
            }

            ModalDialog_HideDialog(this._PopupDivID);

            this._PopupContainerElement.innerHTML = '';
            this._PopupContainerElement.style.display = 'none';

            this._IsDialogOpened = false;
        }
    }, // _DialogClose

    /// <summary>
    /// Creates and returns a popup error dialog (RCHTMLObject)
    /// </summary>
    /// <param name="contentControl">Content control to show inside the dialog</param>
    _PopupCreateErrorDialog: function(contentControl) {
        return this._PopupCreateGenericDialog(contentControl, 'ErrorDialog', 'ErrorDialogHeaderTL', 'ErrorDialogHeaderTR',
                                               'ErrorDialogHeader', 'ErrorDialogHeaderClose', 'ErrorDialogContent');
    }, // _PopupCreateErrorDialog

    /// <summary>
    /// Creates and returns a popup search dialog (RCHTMLObject)
    /// </summary>
    /// <param name="contentControl">Content control to show inside the dialog</param>
    _PopupCreateSearchDialog: function(contentControl) {
        return this._PopupCreateGenericDialog(contentControl, 'SearchDialog', 'SearchDialogHeaderTL', 'SearchDialogHeaderTR',
                                               'SearchDialogHeader', 'SearchDialogHeaderClose', 'SearchDialogContent');
    }, // _PopupCreateErrorDialog

    /// <summary>
    /// Creates and returns a popup dialog (RCHTMLObject)
    /// </summary>
    /// <param name="contentControl">Content control to show inside the dialog</param>
    _PopupCreateDialog: function(contentControl) {
        return this._PopupCreateGenericDialog(contentControl, 'Dialog', 'DialogHeaderTL', 'DialogHeaderTR',
                                               'DialogHeader', 'DialogHeaderClose', 'DialogContent');
    }, // _PopupCreateDialog

    /// <summary>
    /// Creates and returns a popup dialog (RCHTMLObject)
    /// </summary>
    /// <param name="contentControl">Content control to show inside the dialog</param>
    _PopupCreateGenericDialog: function(contentControl, dialogClass,
                                          dialogHeaderTLClass, dialogHeaderTRClass,
                                          dialogHeaderClass, dialogHeaderCloseClass,
                                          dialogContentClass) {
        var dialog = null;
        var content = null;
        var table = null;
        var row = null;
        var cell = null;
        var control = null;
        var closeControl = null;

        dialog = new RCHTMLObject('div');
        dialog.Attributes.Add('id', this._DialogID);
        dialog.Attributes.Add('class', dialogClass);
        dialog.Style.Add('visibility', 'hidden');

        table = new RCHTMLObject('table');
        table.Attributes.Add('border', 0);
        table.Attributes.Add('cellspacing', 0);
        table.Attributes.Add('cellpadding', 0);
        dialog.AddControl(table);

        /**********
        *  Header *
        **********/

        row = new RCHTMLObject('tr');
        table.AddControl(row);

        cell = new RCHTMLObject('td');
        row.AddControl(cell);

        //Set the top left div
        control = new RCHTMLObject('div');
        control.Attributes.Add('class', dialogHeaderTLClass);
        control.Attributes.Add('onmouseover', '_dialogMouseOver = true;');
        control.Attributes.Add('onmouseout', '_dialogMouseOver = false;');
        control.Attributes.Add('ondblclick', 'void(0);');
        cell.AddControl(control);

        //set the title div
        control = new RCHTMLObject('div');
        control.Attributes.Add('class', dialogHeaderClass);
        control.Attributes.Add('onmouseover', '_dialogMouseOver = true;');
        control.Attributes.Add('onmouseout', '_dialogMouseOver = false;');
        control.Attributes.Add('ondblclick', 'void(0);');
        cell.AddControl(control);

        //Create the header close option
        closeControl = new RCHTMLObject('div');
        closeControl.Attributes.Add('class', dialogHeaderCloseClass);
        closeControl.Attributes.Add('ondblclick', 'void(0);');
        closeControl.Attributes.Add('onmouseover', '_dialogMouseOver = false;');
        closeControl.Attributes.Add('title', 'Close window');
        closeControl.Attributes.Add('onclick', this.ID + '._DialogClose();');
        control.AddControl(closeControl);

        //Set the top right div
        control = new RCHTMLObject('div');
        control.Attributes.Add('class', dialogHeaderTRClass);
        control.Attributes.Add('onmouseover', '_dialogMouseOver = true;');
        control.Attributes.Add('onmouseout', '_dialogMouseOver = false;');
        control.Attributes.Add('ondblclick', 'void(0);');
        cell.AddControl(control);

        /***********
        *  Content *
        ***********/

        row = new RCHTMLObject('tr');
        table.AddControl(row);

        cell = new RCHTMLObject('td');
        row.AddControl(cell);

        content = new RCHTMLObject('div');
        content.Attributes.Add('class', dialogContentClass);
        cell.AddControl(content);

        content.AddControl(contentControl);

        return dialog;
    }, // _PopupCreateGenericDialog
    
    /// <summary>
    /// Advance to the next result of the current search
    /// </summary>
    _GoToSearchNextResult : function()
    {
        if ( this._searchCurrentPost < this._searchCurrentPosts.length - 1 )
        {
            this._searchCurrentPost++;
            this.GoToPost( this._searchCurrentPosts[this._searchCurrentPost] );
        }
    }, // _GoToSearchNextResult
    
    /// <summary>
    /// Advance to the previous result of the current search
    /// </summary>
    _GoToSearchPreviousResult : function()
    {
        if ( this._searchCurrentPost > 0 )
        {
            this._searchCurrentPost--;
            this.GoToPost( this._searchCurrentPosts[this._searchCurrentPost] );
        }
    }, // _GoToSearchPreviousResult
    
    /// <summary>
    /// Advance to the first result of the current search
    /// </summary>
    _GoToSearchFirstResult : function()
    {
        this._searchCurrentPost = 0;
        this.GoToPost( this._searchCurrentPosts[this._searchCurrentPost] );
    }, // _GoToSearchFirstResult
    
    /// <summary>
    /// Advance to the last result of the current search
    /// </summary>
    _GoToSearchLastResult : function()
    {
        this._searchCurrentPost = this._searchCurrentPosts.length - 1;
        this.GoToPost( this._searchCurrentPosts[this._searchCurrentPost] );
    }, // _GoToSearchLastResult

    /// <summary>
    /// If the content is visible to the user then hidde it otherwise show it.
    /// </summary>
    /// <param name="postId">Post ID</param>
    /// <param name="expandIt">if true then is a expand action, if false then is a collapse action</param>
    _PostExpandOrCollapse: function(postId, expandIt) {
        var row = null;
        var header = null;
        var activeCss = null;
        var regularCss = null;
        var continueAction = null;

        //Get the message row
        row = $(this.ID + '_PostContent_' + postId);
        //get the message row header
        header = $(this.ID + '_PostHeader_' + postId);
        
        //Check if must continue or not
        continueAction = ( expandIt && ! row.Expanded ) ||
                         ( ! expandIt && row.Expanded );

        if (continueAction) {
            activeCss = header.getAttribute('ActiveClass');
            regularCss = header.getAttribute('RegularClass');

            //Check the open post mode
            if (this.OpenMessageMode == OpenMessageModeEnum.OneAtTime) {
                //check post rows
                if (this._currentOpenedPostContentRow != row && this._currentOpenedPostContentHeaderRow != header
                     && this._currentOpenedPostContentRow != null && this._currentOpenedPostContentHeaderRow != null) {
                    this._currentOpenedPostContentRow.Expanded = false;
                    this._currentOpenedPostContentRow.style.display = 'none';
                    this._currentOpenedPostContentHeaderRow.className = this._currentOpenedPostContentHeaderRow.getAttribute('RegularClass');
                }

                //Set the current open objects
                this._currentOpenedPostContentRow = row;
                this._currentOpenedPostContentHeaderRow = header;
            }

            //Set display attribute
            if (expandIt) {
                row.style.display = '';
                header.className = activeCss;
            }
            else {
                row.style.display = 'none';
                header.className = regularCss;
            }

            //Update expanded status
            row.Expanded = expandIt;
        }
    }, // _PostExpandOrCollapse

    /// <summary>
    /// Builds the UI user rate
    /// </summary>
    /// <param name="starDiv">Star div element of the rate</param>
    /// <param name="selected">Indicates if the given star is selected or not</param>
    _BuildRate: function(starDiv, selected) {
        var tempStarDiv = null;
        var starValue = null;
        var css = null;

        starValue = starDiv.getAttribute('value') * 1;
        for (var i = 0; i < this.RatingUpTo; i++) {
            tempStarDiv = $(this.ID + "_Star" + (i + 1) + "_" + starDiv.getAttribute('post'));

            if (selected) {
                if (i < starValue)
                    css = 'Star StarSelected';
                else
                    css = 'Star StarUnselected';
            }
            else
                css = 'Star StarUnselected';

            if ( tempStarDiv != null )
                tempStarDiv.className = css;
        }
    } // _BuildRate
} // RichMessageBoard.prototype