/*
 Copyright (c) 2008, Mangospring Technologies. All rights reserved
*/
/**
 * This file contains the functionality for chat board utility.
 * @auther : Amitesh kumar
 */




(function(){

  if (typeof ms == "undefined" || !ms) {
    /**
     * The 'ms' global namespace object.  If 'ms' is already defined, then that
     * namespace will not be overwritten rather preserved
     *
     * @namespace ms
     * @static
     */
    ms = {};
  }
  
  /**
     * Utility method to register a namespace under global namespace to avoid
     * naming conflicts that can arise with the use of user 
     * created scripts later.
     *
     * @method register
     * @param {String} ns namespace name
     * @return {Object}
     */
    ms.register = function (ns) {
        if (!ns || !ns.length) {
            return null;
        }

        var nslvl = ns.split(".");
        var namespace = ms;

        for (var i=(nslvl[0] == 'ms' ? 1 : 0); i < ns.length; i++ ) {
            namespace[nslvl[i]] = namespace[nslvl[i]] || {};
            namespace = namespace[nslvl[i]];
        }

        return namespace;
    };
    
    //Defining the shortcut for YAHOO classes
    var Y = YAHOO,
        Dom    = YAHOO.util.Dom,
        Event  = YAHOO.util.Event,
        Lang   = YAHOO.lang,
        widget = YAHOO.widget,
        SL     = YAHOO.util.Selector,
        ajax   = YAHOO.util.Connect;
    
    
    
    
    /**
     * ORDER OF THE KEYS IN THE SMILEY MAP IS IMPORTANT PLZ CHECK BEFORE ADDING OR REMOVING ELEMENT 
     */
    smiley_obj = {
        ":))" : "/images/default/emoticons/18.gif",
        ":-))" : "/images/default/emoticons/18.gif",
        ";)" : "/images/default/emoticons/4.gif",
        ";-)" : "/images/default/emoticons/4.gif",
        ":)]" : "/images/default/emoticons/100.gif",
        "/:)" : "/images/default/emoticons/20.gif",
        ":)" : "/images/default/emoticons/2.gif",
        ":-)" : "/images/default/emoticons/2.gif",
        ":D" : "/images/default/emoticons/5.gif",
        ":-D" : "/images/default/emoticons/5.gif",
        ":?" : "/images/default/emoticons/39.gif",
        ":-?" : "/images/default/emoticons/39.gif",
        ":x" : "/images/default/emoticons/21.gif",
        ":-x" : "/images/default/emoticons/21.gif",
        ":((" : "/images/default/emoticons/17.gif",
        ":-((" : "/images/default/emoticons/17.gif",
        ":P" : "/images/default/emoticons/8.gif",
        ":-P" : "/images/default/emoticons/8.gif",
        ":h" : "/images/default/emoticons/103.gif",
        ":-h" : "/images/default/emoticons/103.gif",
        ":*" : "/images/default/emoticons/7.gif",
        ":-*" : "/images/default/emoticons/7.gif",
        ":O" : "/images/default/emoticons/10.gif",    
        ":-O" : "/images/default/emoticons/10.gif", 

        ":-\\" : "/images/default/emoticons/06.gif", // there is a double slash to escape don't remove
        ":-\/" : "/images/default/emoticons/06.gif", // here also the slash is escaped
        ":(" : "/images/default/emoticons/3.gif",
        ":-(" : "/images/default/emoticons/3.gif",
        "I-)" : "/images/default/emoticons/28.gif",
        "|-)" : "/images/default/emoticons/28.gif",
        ":$" : "/images/default/emoticons/32.gif",
        ":-$" : "/images/default/emoticons/32.gif",
        "[-(" : "/images/default/emoticons/33.gif",
        "X-("  : "/images/default/emoticons/35.gif",
        "x-("  : "/images/default/emoticons/35.gif",
        "=))" : "/images/default/emoticons/24.gif",
        "B-)" : "/images/default/emoticons/12.gif",
        "#-o" : "/images/default/emoticons/34.gif",
        ":-B" : "/images/default/emoticons/22.gif"
    };





    //create 'feed' namespace
    ms.register('chatBoard');
    
    ms.chatBoard.Chat = function(){
      //chat Message block container id
      this.CHAT_MESSAGE_BLOCKS_ID = 'chatMessageBlocks';
      
      //chat Message Board container id
      this.CHAT_MESSAGE_BOARD_ID = 'chatMessageBoard';
      
      //Send button Id
      this.SEND_BUTTON_ID = "send_button";
      
      //URI for getting formmated messages
      this.GET_CONV_URI = g_service_path + "/imps/get_conv_msgs_and_members";
      
      //URI for sending message.
      this.SEND_MESSAGE_URI = g_service_path + "/imps/send_message";
      
      //URI to delete message.
      this.DELETE_MESSAGE_URI = g_service_path + "/imps/delete_message";
      
      //URI for public messages
      this.PUBLIC_MESSAGE_URI = g_service_path + "/events/get_public_chat_messages";
      
      //A function which is called first time when message is load.
      this.onFirstMessageLoad = new YAHOO.util.CustomEvent("FirstMessageLoad", this);
      
      
      //function to show scroll bar on chat message box.
      var showScroll = function () {
        try{
          /**
           * 
           */
          Element.toggle(this.CHAT_MESSAGE_BLOCKS_ID);
          Element.toggle(this.CHAT_MESSAGE_BLOCKS_ID);
             
        }catch(e){}
        this.onFirstMessageLoad.unsubscribe(showScroll); 
      };
  
      this.onFirstMessageLoad.subscribe(showScroll);
    }
    
    ms.chatBoard.Chat.prototype = {
      
      /**
       * Parameter to set the event type
       */
      isPublicEvent : false,
      /**
       * Function to initialize the chat board and load 
       * the messages from the server by Ajax.
       */
      init : function(){
        try{
          this.isPublicEvent = typeof(isPublicEvent) == 'undefined' ? false : isPublicEvent;
          var conv_id = '';
          this.view   = "chatPane";
          this.box    = "inputMsgBox";
          this.button = "send_button";
          
          //maximum character limit
          this.max_chars = 949;
          
          //stores the textrange object
          this.range = null; 
          
          //Flag to enable/disable the editing. 
          this.disabled = false;
          
          //Stores the last message sent at by the user timestamp value
          this.lastMessageSentAt = 0;
      
          this.view     = this.get(this.view);
          this.box      = this.get(this.box);
          this.button   = this.get(this.button);
          this.parentClass = null;
          
          //stores the document object of the iframe/richtext box
          this.doc = this.box.contentWindow.document;
          
          if(this.isPublicEvent){
            
            //disable the chat board.
            this.disabled = true;
            this.disable();
            $('send_file').setAttribute('disabled', true);
            $('chatGroupName').setAttribute('disabled', true);
            $('chatFilterGroupName').setAttribute('disabled', true);
            
            var defaultContent = ''
            defaultContent = '<center><span style="color:#8B8989;">You need to be signed in and part of the '+g_guest_label+' list to be able to post a message.<br/></span><center>';
            this.setValue(defaultContent);
            
          }else{
            //create the prompt box 
            this.createPrompt(conv_id);
          
            //initialize the toolbar if associated
            this.initToolbar();

            //initialize smileys
            this.initSmiley("smiley_toolbar");
    
            //initialize chat theme chooser
            //--YAHOO.util.Event.addListener("theme_chooser" + conv_id, "click", MS.Core.ConvManager.initThemeMenu);

            //add handlers to reply links
            this.initReply();
          
            //add handlers to delete system message link
            //--this.initDelete();
            //scrolls the view pane so that last message can be in the view
            //--this.scrollDown();
            this.createAlert();

            // initialize smiley and URL parsing code
            this.smileyParser = new App.util.SmileyParser();
            this.URLParser = new App.util.HyperlinkProcessor();
          
            // try to set the 'designMode' property, in some browsers if the
            // element is hidden then it throws error while setting the property
            this.setDesignMode();
          }
          //load the messages
          this.getFilteredMessages();
          
        }catch(e){            
            MS.hideWait();
        }
      },
      
      /**
       * Function to load the messages on the messages board.
       * @param {Hash} nParams : This hash contains the  parameters and values.
       * @param {Array} waitPos : An Array which contains the container Id and position for waiting image.
       */
      loadMsgBoard : function (nParams, waitPos){
        try{
          var convId = this.getSelectedSendToConvId();
          var params = null;
          if(nParams){
            params = nParams;
          }else{
            params = $H({ 
                        conv_id : convId ,
                        "related_conversation_id" : this.getSelectedSendToRelatedConvId(),
                        "conv_sub_type" : this.getSelectedSendToConvSubType(),
                        "conv_type"  :  this.getSelectedSendToConvType(),
                        "event_id"  :  this.getSelectedSendToEventId(),
                        "type"    : "LOCAL",
                        service_type : this.getSelectedSendToServiceType()
                        
                        }).toQueryString();
          }
          //If wait image position is given then show the waiting image.
          if(waitPos){
            var waitImgContId = waitPos[0];
            var hPos = (waitPos.length > 1) ? waitPos[1] : '';
            var vPos = (waitPos.length > 2) ? waitPos[2] : '';
            MS.showWait(waitImgContId, hPos, vPos);
          }else{
            MS.showWait(this.CHAT_MESSAGE_BOARD_ID);
          }
          var href = location.protocol + "//" + location.host + this.GET_CONV_URI;
          //to get only public messages.
          if(this.isPublicEvent){
            href = this.PUBLIC_MESSAGE_URI;
          } 
          ajaxCall(href, {
                     parameters : params, 
                                  onComplete: MS.hideWait
                                 });
        }catch(e){}
      },
      
      /**
       * Function to get the messages on the basis of the option selected in filted select box.
       * @param {Array} nWaitPos :  An Array which contains the container Id and position for waiting image.
       */
      getFilteredMessages : function(nWaitPos){
        try{
          //get the all parameters for fetching the messages.
          var selectFilterObj     = Dom.get("chatFilterGroupName");
          var selectFilterOption  = selectFilterObj.options[selectFilterObj.selectedIndex];
          var convId              = selectFilterOption.value;
          var rel_convn_id        = selectFilterOption.getAttribute("related_conversation_id");
          var conv_sub_type       = selectFilterOption.getAttribute("conv_sub_type");
          var conv_type           = selectFilterOption.getAttribute("conv_type");
          var event_id            = selectFilterOption.getAttribute("event_id");
          var fetch_all           = selectFilterOption.getAttribute("fetch_all");
          var service_type        = selectFilterOption.getAttribute("service_type");
          
          var params = null;
            params = $H({ 
                        conv_id : convId ,
                        related_conversation_id : rel_convn_id,
                        conv_sub_type : conv_sub_type,
                        conv_type  :  conv_type,
                        event_id  :  event_id,
                        get_public_private_msgs : fetch_all,
                        type    : "LOCAL",
                        service_type : service_type
                        
                        }).toQueryString();
          
          var waitPos = [selectFilterObj.id, 'right'];
          if(nWaitPos){
            waitPos = nWaitPos;
          }
          this.loadMsgBoard(params, waitPos);
        }catch(e){}
      },
      
      /**
       * Function to load the all current messages from the server.
       */
      refreshMessages : function(){
        try{
          this.getFilteredMessages(['refresh_chat_board_button', 'right']);
        }catch(e){}
      },
      
      /**
       * Function to update the messages board with the new messages
       * @param {JSON String} data : It is a JSON String, which contains html formatted data for messaging. 
       */
      updateMessageBoard : function(data){
        try{
          //Converting the JSON String in to JSON Object.
          data   = eval("(" + Lang.dump(data) + ")");
          var chatMsgBrd = Dom.get(this.CHAT_MESSAGE_BOARD_ID);
              chatMsgBrd.innerHTML = data.content;
              YAHOO.util.Event.onDOMReady(function () { 
                       MSChatBoard.setHeight();
                       MSChatBoard.onFirstMessageLoad.fire();
                       try{disableThePage();}catch(e){}
                   });
        }catch(e){}
      },
      
      /**
       * Function to get the conversation id for the selected group 
       * in send to select box.
       */
      getSelectedSendToConvId : function (){
        var convId = null;
        try{
          var chatConvName = Dom.get('chatGroupName');
          convId = chatConvName.options[chatConvName.selectedIndex].value;
        }catch(e){}
        return convId;
      },
      
      /**
       * Function to get the related_conversation_id for 
       * the selected group in send to select box.
       */
      getSelectedSendToRelatedConvId : function (){
        var relatedConvId = '';
        try{
          var chatConvName = Dom.get('chatGroupName');
              relatedConvId = chatConvName.options[chatConvName.selectedIndex];
              relatedConvId = relatedConvId.getAttribute("related_conversation_id");
        }catch(e){}
        return relatedConvId;
      },
      
      /**
       * Function to get the conversation sub type
       * for the selected group in send to select box.
       */
      getSelectedSendToConvSubType : function (){
        var convSubType = '';
        try{
          var chatConvName = Dom.get('chatGroupName');
          convSubType = chatConvName.options[chatConvName.selectedIndex];
          convSubType = convSubType.getAttribute("conv_sub_type");
        }catch(e){}
        return convSubType;
      },
      
      /**
       * Function to get the conversation type for the selected 
       * group in send to select box.
       */
      getSelectedSendToConvType : function (){
        var convType = '';
        try{
          var chatConvName = Dom.get('chatGroupName');
          convType = chatConvName.options[chatConvName.selectedIndex];
          convType = convType.getAttribute("conv_type");
        }catch(e){}
        return convType;
      },
      
      /**
       * Function to get the Event Id for the selected group in send to select box.
       */
      getSelectedSendToEventId : function (){
        var eventId = '';
        try{
          var chatConvName = Dom.get('chatGroupName');
          eventId = chatConvName.options[chatConvName.selectedIndex];
          eventId = eventId.getAttribute("event_id");
        }catch(e){}
        return eventId;
      },
      /**
       * Function to get the service type for the selected group in send to select box.
       */
      getSelectedSendToServiceType : function (){
        var serviceType = '';
        try{
          var chatConvName = Dom.get('chatGroupName');
          serviceType = chatConvName.options[chatConvName.selectedIndex];
          serviceType = serviceType.getAttribute("service_type");
        }catch(e){}
        return serviceType;
      },
      
      
      /**
       * Initializes the toolbar buttons of the richtext editor
       */
      initToolbar : function () {
        try{
          var conv_id     = '';
          var rel_conv_id = '';
          var panel = Dom.get('editor_controls');
          
          if(!panel){
            return; 
          }
          var tools = SL.query("img[action]", panel);
          
          for (var i = 0, len = tools.length; i < len; ++i) {
            //init each buttons
            var o       = tools[i];
            var action   = o.getAttribute("action");
            var tag      = (o.nodeName || o.tagName).toLowerCase();
            
            //if action is font color then create color picker box
            Event.addListener(o, "click", Function.bindArgs(this.changeFormatting, this, action, ""));
            Dom.setStyle(o, "border", "1px solid #fff");
          }
          
          //initialize video post link
          var post_video = Dom.get("post_video");
          if(post_video){
            Event.addListener(post_video, "click", this.prompt.show, this.prompt, true);
          }
          //initializes file send
          this.initSendFile();
          
          //initializes color picker
          this.initColorPicker(conv_id);
          
        }catch(e){}  
      },
      
      /**
       * Initializes color picker
       * @param {Number} conv_id
       */
      initColorPicker : function (conv_id) {
          try{
          //crate range object prior to displaying color box
          this.colorpicker = new YAHOO.widget.Overlay("colorListOverlay", {
                                          context : ["cpicker" + conv_id, "bl", "tl"],
                                          width   : "107px",
                                          visible : false
                                        }); 
          
          var t = this._getColorTable();
          this.colorpicker.setBody(t);
          this.colorpicker.render(document.body);

          Event.addListener(this.colorpicker.element, "click", function (e, args) {
              Event.stopEvent(e);
              //this.createSelRange();
              var c = Dom.getStyle(Event.getTarget(e), "backgroundColor");
              this.selectColor(c);
              this.colorpicker.hide();
            }, this, true);
            
          Event.addListener("cpicker" + conv_id, "click", function (e) {            
              Event.stopEvent(e);           
              this.createSelRange();
              this.colorpicker.cfg.setProperty("context", [Event.getTarget(e)]);
              this.colorpicker.align("bl", "tl");
              this.colorpicker.show();   
            }, this, true);
          
          //hide the colorpicker on body click
          Event.addListener(document.body, "click", this.colorpicker.hide, this.colorpicker, true);
          }catch(e){alert(e.message)}
      },

      /**
       * Function to generate the color table and stores it in the colorlist variable
       */
       _getColorTable : function () {
            var tbl = MS.Dom.create('table', {"class" : "smiley_controls", style : "border:1px solid #808080;background:#fff;width:100%"});

            var ptr = 0, td, colorcodes = this.genHex();
            for (var i = 0; i < 5; ++i) {
                var tr  = tbl.insertRow(-1);
                for (var j = 0; j < 5; ++j ) {
                    td  = tr.insertCell(-1);
                    Dom.setStyle(td, "cssText", "height:15px;width:15px;cursor:pointer" );
                    Dom.setStyle(td, "backgroundColor", "#" + colorcodes[ptr]);

                    Event.on(td, "mouseover", function () {
                        Dom.setStyle("preview", "backgroundColor", Dom.getStyle(this, "backgroundColor"));
                    });

                    ptr++;
                }
            }

            td = tbl.insertRow(-1).insertCell(-1);
            td.setAttribute('colSpan', 5);
            td.id= "preview";
            td.height = "15px";

            return tbl;
      },

     /**
      * Function to generate Random color hex values
      */
      genHex: function (){
            var hexs = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];
            var digits = [], color = [], result = ["000000"];

            for (var j = 0; j < 24; ++j ) {
                for (i = 0; i < 6; i++) {
                    digits[i] = hexs[Math.floor(Math.random() * 15)];
                    color.push(digits[i]);
                }
                
                result.push(color.join(""));
                color.length = 0;
            }
            
            return result;
       },

      /**
       * Initializes Send/upload file capability
       * @param {Number} conv_id
       */
      initSendFile : function () {
        Event.on("send_file", "change", function () {
          
                var conv_id = MSChatBoard.getSelectedSendToConvId();
                var related_conversation_id = MSChatBoard.getSelectedSendToRelatedConvId();
                
                var formObj = Dom.get('send_file_form');
                    formObj.conversation_id.value = conv_id;
                YAHOO.util.Connect.setForm("send_file_form", true);
                var uploadHandler = {
                        upload : function (xhr) { 
                                    alert(xhr.responseText);
                                    MS.hideWait();
                                    var selectFilterObj = Dom.get("chatFilterGroupName");
                                    selectFilterObj.selectedIndex = 0;
                                    MSChatBoard.getFilteredMessages();
                                }
                    };
                MS.showWait("mainChatBoard");
                YAHOO.util.Connect.asyncRequest("POST", g_service_path + "/upload/send_file?related_conversation_id=" + related_conversation_id, uploadHandler);
              });
      }, 

      /**
       * Function to perform formatting change related actions, like bold, italic and underline etc.
       * @param {Event} e
       * @param {String} action
       * @param {String} value - optional
       */
      changeFormatting : function (action, value, e) {
        value = value || "";
        var targ = this.getTarget(e);
  
        if(targ.nodeName.toLowerCase() == 'select') {
          value = targ.options[targ.selectedIndex].value;
        }
        this.execCommand(action, value);
      },
      
      /**
       * Function to create the alert dialog for fast typing
       */
      createPrompt : function (conv_id) {
        var that = this;
  
        this.prompt = new widget.SimpleDialog("postMedia" + conv_id, {
                width   : "300px",
                modal   : true,
                visible : false,
                /*fixedcenter : true,*/
                xy : [10, 10],
                constraintviewport : true
              });

        var success = function () {
                  that.postRichMedia(this.body.getElementsByTagName("input")[0]);
                };
        var cancel  = function () { this.hide(); };

        this.prompt.setHeader("Send Pictures or videos");
        this.prompt.setBody("<div class='small_caption'>Enter link or media embed code to share:</div><div><input type='text' class='textbox'/></div>");
        this.prompt.cfg.queueProperty("buttons", [ { 
                    text: "Send", handler : success, 
                    isDefault:true
                  },{
                    text : "Cancel", handler : cancel
                  }]);

        this.prompt.showEvent.subscribe(this.prompt.center, this.prompt, true);

        // the invisible caret fix for Gecko based browsers
        if (Y.env.ua.gecko) {
          Dom.addClass(this.prompt.body, "caretfix");
          this.prompt.showEvent.subscribe(function() {
                    Dom.setStyle(this.body, "display", "none");
                var fixDisplay = function() {
                          Dom.setStyle(this.body, "display", "block");
                          try {
                            this.body.getElementsByTagName("input")[0].focus();
                          } catch (e) {
                            // Not related to the workaround, I just try/catch focus calls
                            // do avoid testing for the various conditions in which they could
                            // fail.
                          }
                        }
                      Lang.later(0, this, fixDisplay);
              });
        }

        this.prompt.render(document.body);
      },
      
      /**
       * Executes on selecting colorboxes in color picker
       * @param {Event} e
       * @param {String} color
       */
      selectColor : function (color) {
        if(Y.env.ua.ie) {
          this.range.select();
        }
        this.execCommand("forecolor", color);        
      },
      
      /**
       * Handles rich media content posting
       */
      postRichMedia : function (el) {
        var media = el.value;

        if(media) {
          //returns an array of parsed elements and remove other non-matched characters
          this.prompt.hide();
          media = MS.Media.parse(media);
          
          if(media.length > 0) {
              media.unshift("<br />");
              this.sendMessage(media.join("<br />"));
          }
          el.value = "";
        }
  
        return false;
      }, 

      /**
       * Function to initialize smiley related actions
       * @param {String} smiley_container
       * @param {String} optional_align //obj to which the dropdown will be aligned
       */
      initSmiley : function (smiley_toolbar) {              
        var conv_id = '';//this.parentClass.getId();
        var cont  = $(smiley_toolbar + conv_id);
        var dropdown = $("smiley_dropdown" + conv_id);

        if(!cont) { return; }
          Event.on( dropdown, "click", this.showSmileyList, cont, this );
          //get all the images in smiley container and add handler to them
          var imgs = cont.getElementsByTagName('img');
  
          for (var i = 0, len = imgs.length; i < len; ++i ) {
            if (imgs[i].id != dropdown.id) {
                Event.on( imgs[i], 'click', function ( e, code ) {
                    this.onSmileyClick( code );
                }, imgs[i].title, this );

                Dom.addClass( imgs[i], "hand" );
            }
          }
      },

      /**
       * Executes on clicking of the smiley icons
       * pastes the title text in the input box.
       * @param {String} code - smiley code
       */
      onSmileyClick : function (code) {
        this.execCommand("inserthtml", '&nbsp;' + code + '&nbsp;');
      },

      /**
       * Displays the smiley dropdown box, it receives an array of arguments,
       * the first argument is EventObject and other's r additional args those
       * are passed to the function while attaching as event handler
       * @param {Array} args
       */
      showSmileyList : function (e, align_obj) {
        Event.stopEvent( e );
        
        Event.on( document.body, "click", this.hideSmileyList, null, this );
  
        var cont   = MS.Dom.create("div", {"id" : "smiley_chooser", "style" : "width:1%;overflow:visible"});
        var table = MS.Table.create({"class" : "smiley"});
        var tr     = MS.Table.addRow(table);
        var ctr   = 1;
        var last   = "";
  
        //smiley_obj is global Hash declared in application.js
        for (var p in smiley_obj) {
          if(last == smiley_obj[p]) { continue; }
          
          var td     = MS.Table.addCell(tr, {"style" : "text-align:center;width:30px;"});
          var img   = new Image();
          
          img.src       = smiley_obj[p];
          img.title     = p;
          img.className = "hand";

          Event.on(img, "click", function ( e, p ){ this.onSmileyClick( p ); }, p, this );

          td.appendChild(img);

          if(ctr == 5){
            tr = MS.Table.addRow(table);
            ctr = 1;
          }else{
            ctr++;
          }
          //store the last url
          last = smiley_obj[p];
        }
  
        cont.appendChild(table);
        align_obj = this.get(align_obj);        
        var x  = MS.Position.getPosX(align_obj);
        var y  = MS.Position.getPosY(align_obj);
        MS.Dom.addStyle(cont, "position:absolute;left:" + x + "px;top:" + (y + 25) + "px");
        document.body.appendChild(cont);
      },

      /**
       * Hides smiley list
       */
      hideSmileyList : function () {
        var sm = $("smiley_chooser");
          if(sm) {
            Element.remove(sm);
          }
      },
      
      /**
       * Executes editor realted commands
       * @param {String} cmd
       * @param {String} value
       */
      execCommand : function (cmd, value) {
        if(this.isDisable()) { return; }
          //if IE then put focus back to the editor
          if (Y.env.ua.ie) {
            this.putFocus();
          }
  
          var range    = this.getRange(),
              sel      = this.getSelection(),
              doc      = this.getDoc(),
              action  = "",
              exec    = false;
  
          switch (cmd.toLowerCase()) {
            case "bold":
              action = "bold";
              exec = true;
              break;
            case "italic":
              action = "italic";
              exec = true;
              break;
            case "underline":
              action = "underline";
              exec = true;
              break;
            case "forecolor":
              action = "forecolor";
              exec = true;
              break;
            case "fontname":
              action = "fontName";
              exec = true;
              break;
            case "fontsize":
              action = "fontsize";
              exec = true;
              break;
            case "inserthtml":
              //if gecko based or opera then use 'inserthtml' command
              if( Y.env.ua.gecko || Y.env.ua.opera ) {
                action = "inserthtml";
                exec = true;
              }
              
              //IE don't have 'inserthtml' available use 'pasteHTML' method of range object instead
              if(Y.env.ua.ie) {
                var _rng = this.getRange();
                if(_rng) {
                  _rng.pasteHTML(value);
                }
                exec = false;
              }
              break;
          }
  
          if (exec) {
            try {
              doc.execCommand(action, false, value);
            }catch (e) {
            }
          }
      },

      /**
       * Returns the selection object
       */
      getSelection : function () {
        var sel = null;
          if (this.getDoc() && this.getWindow()) {
            if (this.getDoc().selection) {
              sel = this.getDoc().selection;
            }else{
              sel = this.getWindow().getSelection();
            }
          }
        return sel;
      },

      /**
       * Creates the selection range and sets it in range variable
       */
      createSelRange : function () {
        this.range = this.getRange(); 
      },

      /**
       * Returns the text range object
       */
      getRange : function () {
        var sel = this.getSelection();
        if (sel === null) {
          return null;
        }
  
        if (Y.env.ua.webkit && !sel.getRangeAt) {
          var _range = this.getDoc().createRange();
          try {
            _range.setStart(sel.anchorNode, sel.anchorOffset);
            _range.setEnd(sel.focusNode, sel.focusOffset);
          }catch(e){
            _range = this.getWindow().getSelection() + '';
          }
          return _range;
        }
  
        if (Y.env.ua.ie || Y.env.ua.opera) {
          return sel.createRange();
        }
  
        if (sel.rangeCount > 0) {
          return sel.getRangeAt(0);
        }
        return null;
      },

      /**
       * This function requires revisit coz for HTML text it's hard to inset <wbr> in a predifined places
       */
      insertWBR : function (str) {
        var brek = 28;
        if(str.length > brek && str.indexOf(" ") == -1) {
          var arr = str.split("");
          var len = Math.floor(arr.length/brek);
          var pos = brek;
          for (var i =0; i < len; ++i) {
            arr.splice(pos, 0, "<wbr/>");
            pos += brek + i;
          }
  
          return arr.join("");
        }else {
          return str;
        }
      },
      
      /**
       * Sends message to the server
       * @param {String} message
       */
      sendMessage : function (message, nMsgObj) {
        var msg_obj = null;
            msg_obj = $H({
                          "message" : message,
                          "conversation_id" : this.getSelectedSendToConvId(),
                          "related_conversation_id" : '',
                          "type" : "LOCAL"
                        });
                    
          if(nMsgObj){
            msg_obj = msg_obj.update(nMsgObj);
          }

          if (this.getSelectedSendToConvSubType()== "R") {
            //msg_obj.related_conversation_id = this.getSelectedSendToRelatedConvId();
             msg_obj.set("related_conversation_id" , this.getSelectedSendToRelatedConvId())
          }

          try{
            //FireFox requires absolute location if you want to make a call to server from inside the iframe
            MS.showWait(this.SEND_BUTTON_ID, 'right');
            var href = location.protocol + "//" + location.host + this.SEND_MESSAGE_URI;
            var params = $H(msg_obj).toQueryString();

            ajaxCall(href, {
                    parameters : params, 
                    onComplete: function(){
                              MS.hideWait();
                              var selectFilterObj = Dom.get("chatFilterGroupName");
                               selectFilterObj.selectedIndex = 0;
                               MSChatBoard.getFilteredMessages();
                            }
              });
          }catch(e) {}

      },
      
      /**
       * Sets the design mode property of the editor
       */
      setDesignMode : function () {
        //set design mode
        this._designMode();
      },

      /**
       * Initializes input box handlers
       */
      initTextboxHandlers : function () {
        //trap enter key in editor to send messages
        Event.on(this.getDoc(), "keydown", this.onKeyPressed, this, true);
        Event.on(this.button, "click", this.send, this, true);
        Event.on(this.getDoc(), "mousedown", this.hideSmileyList, this, true);
      },

      /**
       * Private method to implement design mode 
       */
      _designMode : function () {
        try {
          var that = this;
            //simply use a timeout to set the design mode, it's a bug in FF but IE sometimes screws up also, 
            //just give a breathing space to this statement
            setTimeout(function () {
                //stores the document object of the iframe/richtext box
                that.doc = that.box.contentWindow.document;
                that.doc.designMode = "on";
                //init handlers
                that.initTextboxHandlers();
              }, 10
            );

        }catch (e) {
          if(Y.env.ua.gecko) {
            Event.on(this.getDoc(), "mousedown", this.setDesignMode, this, true);
          }
        }
      },

      /**
       * Function to create the alert dialog for fast typing
       */
      createAlert : function () {
        var that = this;
        this.alert = ConvUtil.createSimpleDialog("ALERT", {
              title : "Oops!",
              button_captions : ["Ok"],
              message : "<div style='font:normal 12px Verdana'>Hey slow down! Typing this fast could hurt your fingers <img src='/images/default/emoticons/2.gif' align='absmiddle'></div>",
              close : false,
              handleYes : function () {
                  this.hide();
                  that.putFocus();
              }
              });
},

      /**
       * Destroys the alert box object created using YUI
       */
      destroyAlert : function () {
        if(this.alert && this.alert.destroy) {
          this.alert.destroy();
        }
      },

      /**
       * Function to show the alert box for fast typing
       */
      showAlert : function () {
        //this is for simple textarea box
          this.box.blur();
          this.alert.show();
      },

      /**
       * Executes on every keydown to check for "ENTER" key if that key is pressed then it triggers
       * send() to send the message
       */
      onKeyPressed : function (e) {
        if(!e) {
          e = window.event;
        }

        var key = e.keyCode || e.which;
        var shiftPressed = e.shiftKey;
        var ctrlPressed  = e.ctrlKey;
        var source = e.target || e.srcElement;
  
        // allow newline if shift + enter key is pressed 
        if(key == 13 && shiftPressed) {
          if (this.getTextLength() >= this.max_chars) {
              MS.Event.cancel(e);
              return false;
          }else {
            return true;
          }
        }else if (key == 13 && !shiftPressed) {
          //time to send message and clear the box
          MS.Event.cancel(e);
          this.send();
          return false;
        }else {
          //if backspace and delete or arrow key then allow it
          if(key == 46 || key == 8 || $R(38, 41).include(key)) { return true; }
            //if other keys and maximum length reached then
            if (this.getTextLength() >= this.max_chars) {
              MS.Event.cancel(e);
              return false;
            }else {
              return true;
            }
        }
      },

      /**
       * This function performs some clean up action before the message can be sent to the server
       * it removes some HTML tags or replaces them with some other tags.
       * @param {String} html
       */
      cleanHTML : function (html) {
        //clean up the html change all <p> tags to span
        html = html.replace(/<p/gi, "<span");
        html = html.replace(/<\/p>/gi, "</span>");
        html = html.replace(new RegExp('<font([^>]*)face="([^>]*)">(.*?)<\/font>', 'gi'), '<span $1 style="font-family: $2">$4</span>');
        html = html.replace(/<u/gi, '<span style="text-decoration: underline;"');
        html = html.replace(/\/u>/gi, '/span>');
        html = html.replace(/<b>/gi, '<span style="font-weight: bold;">');
        html = html.replace(/<\/b>/gi, '</span>');
        html = html.replace(/<i>/gi, '<span style="font-style: italic;">');
        html = html.replace(/<\/i>/gi, '</span>');
        html = html.replace(/&nbsp;/g, ' ');
        html = html.replace(/\s{2,}/g, ' ');
        //remove <IMG> tag
        html = html.replace(Filter.pattern, "");
        
        //remove a tag
        html = html.replace(new RegExp('<a([^>]*)>(.*?)<\/a>', "gi"), "$2");
        
        //remove last <br>
        html = html.replace(/<br\/>$/, "");  
        html = html.replace(/<br>$/, ""); // + to match multiple BRs
        
        return html.trim();        
      },

      /**
       * Checks whether the message is proper to send to server
       * for example it removes all HTML tags and &npsp; and " " to ensure that
       * a blank message doesn't get sent to server
       * @param {String} html
       */
      isValidMessage : function (html) {
        //remove HTML tags first
        html = html.replace(/<\/?[^>]+>/gi, "");
        //remove HTML spaces
        html = html.replace(/&nbsp;/gi, "");
        //remove spaces if any
        html = html.replace(/\s+/g, "");
        //remove any line feeds
        html = html.replace(/\n/g, "").replace(/\r/g, "");

          //now check length to see if there are any text or not
        return (html.length > 0);
      },

      /**
       * Function to chop messages if it exceeds limit
       * @param {String} text
       */
      chopMessage : function (text) {
        //needs to be reviewed
        if(text >= this.max_chars) {
          alert("Chat messages more than 950 characters are not allowed for best "+g_event_label+" experience." + 
              " \nSo Removing formatting and sending first 950 characters");
          //remove all HTML tags
          text = text.replace(/<\/?[^>]+>/gi, "");
          //replace all HTML spaces with real space
          text = text.replace(/&nbsp;/gi, " ");
  
          text.trim();
  
          //if still exceeds limit then chop it
          if(text.length >= this.max_chars) {
            text = text.substring(0, this.max_chars - 1);
          }
          return text;
        }
  
        return text;
      },

      /**
       * Sends the message text to it's parentClass's sendMessage method to send to server RichView
       */
      send : function (e) {

        //fast typing detection
        // if((System.currentTimeMillis() - this.parentClass.getLastMessageTime()) <= 500) {            
        //if((System.currentTimeMillis() - this.getLastMessageTime()) <= 500) {
        //return this.showAlert();
        //}
  
        var text = this.getValue();

        //if not proper message then do not proceed
        if(!this.isValidMessage(text)) {
          this.clearDoc();
          return this.putFocus();
        }

        //clean the HTML text
        text = this.cleanHTML(text);

        //parse smiley codes in the text
        //text = MS.Smiley.parse(smiley_obj, text);
        //parse links in the text
        //text = MS.URL.parse(text);

        text = this.smileyParser.parse( text );

        text = this.URLParser.process( text );

        //if messages exceeds the limit then tell the user that system gonna chop the messages and unformat it
        text = this.chopMessage(text);
        //now send message
        this.sendMessage(text);
        
        //clear editor and set focus back into it
        this.clearDoc();
        this.putFocus();
      },

      /**
       * Disables the type box and send button
       */
      disable : function () {
        try{
          this.doc.designMode = "off";
          this.button.disabled = true;
        }catch(e){
        }

      },

      /**
       * Enable the type box and send button
       */
      enable : function () {
        try{
          this.setDesignMode();
          this.button.disabled = false;
        }catch(e){
        }
      },

      /**
       * Function to attach handlers to all the reply link in organizer tab
       */
      initReply : function () {
        //check if there is related_conv_id available or not
        //if there is no such id then assume that it's not organizer tab
        //coz organizer tab will have this id
        //var rel_conv_id = this.parentClass.getRelatedId();
        var rel_conv_id = this.getSelectedSendToRelatedConvId();          
  
        if (rel_conv_id) {
          //loop through all reply links to attach handler
          var tbl = document.getElementsByClassName("chat", "table", this.view)[0];
          var rpl_spans = document.getElementsByAttrib("type", "span", tbl, "RPL");
  
          if (rpl_spans.length > 0) {
            for (var i = 0, len = rpl_spans.length; i < len; ++i ) {
              MS.Event.add(rpl_spans[i], "mousedown", Function.bindArgs(this.showReply, this, rpl_spans[i]));
            }
          }
        }
      },

      /**
       * Function to show reply box
       */
      showReply : function (elem, e) {
        try{
          var reply = new Template('<div id="event_reply" style="margin-bottom:25px;"><div style="display:block" class="pad5"><input reply_to="#{reply_to}" type="text" ' + 
                              'class="textbox" style="width:90%" maxlength="100" id="reply_text" /></div>' + 
                '<div class="right" style="padding-right:10%"><input type="button" value="Cancel" id="cancel_reply" class="button_medium bold gray"/>' +
                '&nbsp;<input type="button" value="Send" id="send_reply" class="button_medium bold"/></div></div>');

          //call hide reply to make sure that only one instance of reply box visible
          this.hideReply();
  
          var felix_id = Element.readAttribute(elem, "to_user_id");
          var html = reply.evaluate({"reply_to" : felix_id});
          var pnode = elem.parentNode;
          Element.toggle(elem);
  
          //insert the HTML fragment after the reply link
          //var el_html = new Insertion.Bottom(pnode, html);
          var el_html = Element.insert(pnode,{
            bottom: html
          });
  
          var reply_box = Dom.get("reply_text");
          var event_reply_box = Dom.get("event_reply");
              event_reply_box.replyClickElem = elem;

          //MS.Event.add("send_reply", "click", Function.bindArgs(this.sendReply, this, reply_box));
          //MS.Event.add("cancel_reply", "click", Function.bindArgs(this.hideReply, this));

          YAHOO.util.Event.on( "send_reply", "click", this.sendReply, reply_box, this );
          YAHOO.util.Event.on( "cancel_reply", "click", this.hideReply, reply_box, this );

//          var keyListener = new YAHOO.util.KeyListener( reply_box, { keys:13 }, {
//              fn:function ( e ) {
//                  this.sendReply( e, reply_box );
//              },
//
//              scope : this,
//
//              currectScope : true
//          } );
//
//          keyListener.enable();

          //place cursor in the box
          Form.Element.activate(reply_box); 
        }catch(e){}
      },

      /**
       * Hides the reply box
       */
      hideReply : function () {
        try{
          var elem = Dom.get("event_reply");
          if(elem){
            var pnode = elem.parentNode;
            if(pnode) {
              //unhook/detach event handlers
              //GC.empty(elem);
              try {
                var replyClickElem = elem.replyClickElem
                //Element.toggle(pnode.getElementsByTagName("span")[0]);  
                if(replyClickElem){
                  Element.toggle(replyClickElem);
                }
              }catch (e){}
              Element.remove(elem);
            }
          }
        }catch(e){}
      },

      /**
       * Sends the reply message to the server
       * @param {Object} e
       */
      sendReply : function (e, elem) {
        try{
          var message = Filter.sanitize(elem.value);
              message = message.trim();
  
          if(message.length == 0) {
            return this.hideReply();
          }

          message = this.chopMessage(message);        
          message = MS.Smiley.parse(smiley_obj, message);
          message = MS.URL.parse(message);

          var to_id = Element.readAttribute(elem, "reply_to");

          var elemHasProperties = Dom.get("event_reply");
              elemHasProperties = elemHasProperties.replyClickElem;
              
          var is_private_conv = Element.readAttribute(elemHasProperties, "is_private_conv");
              is_private_conv = new String(is_private_conv);
              
          var related_conv_id = Element.readAttribute(elemHasProperties, "related_conv_id");
          var msgObj =  {
                          "message"       : message,
                          "to_user_email"  : Element.readAttribute(elemHasProperties, "to_email"),
                          "to_user_name"  : Element.readAttribute(elemHasProperties, "to_name"),
                          "to_user_id"    : Element.readAttribute(elemHasProperties, "to_user_id"),
                          "MST"            : "RPL"
                        };
          if("Y" == is_private_conv){
            msgObj.related_conversation_id = related_conv_id;
          }


          this.hideReply();

          this.sendMessage(message, msgObj);

        }catch(e){}
      },
      
      /**
       * Function to delete message from chat trail
       * @param {HTMLElement} elem
       * @param {HTMLElement} row
       */
      deleteMessage : function (elem, msgRowId) {
          var isDelete = confirm("Do you want to delete this message?");
          if(isDelete){
            var obj = $H({
                conv_id : Element.readAttribute(elem, "conv_id"),
                msg_created_at : Element.readAttribute(elem, "msg_created_at"),
                user_id : Element.readAttribute(elem, "user_id"),
                related_conversation_id : Element.readAttribute(elem, "related_conversation_id")
            });
            
            var href = location.protocol + "//" + location.host + this.DELETE_MESSAGE_URI;
            var params = obj.toQueryString();
            MS.showWait(elem);
            ajaxCall(href, {
                      parameters : params, 
                      onComplete: function(){
                                var msgRow = Dom.get(msgRowId);
                                    try{
                                      new Effect.Fade(msgRow);
                                      new Effect.BlindUp(msgRow);
                                    }catch(e){}
                                    MS.hideWait();
                                    YAHOO.util.Event.onDOMReady(function () { 
                                         Lang.later(1000, MSChatBoard, MSChatBoard.setHeight);
                                     });
                              }
                });
          }
      },

      /**
       * Returns text length;
       */
      getTextLength : function () {
        return this.getValue().length;
      },

      /**
       * Function to get the state of editior
       */
      isDisable : function () {
        return this.disabled;
      },

      /**
       * Returns the current target element of the event object
       * @param {Event} e
       */
      getTarget : function (e) {
        var targ = e.srcElement || e.target;
        return targ;
      },

      /**
       * Returns the element object
       */
      get : function (el) {
        return $(el);
      },

      /**
       * Returns the document object of the editor
       */
      getDoc : function () {
        return this.doc;
      },

      /**
       * Returns the window object of the editor
       */
      getWindow : function () {
        return this.box.contentWindow;
      },

      /**
       * Returns the editor's content
       */
      getValue : function () {
        return this.doc.body.innerHTML;
      },
      
      /**
       * Set the editor's content
       */
      setValue : function (htmlContent) {
        try {
          this.doc.body.innerHTML = htmlContent;
        }catch(e){YAHOO.lang.later(1000, this, this.setValue, [htmlContent]);}
      },

      /**
       * Sets the focus back to the editor
       */
      putFocus : function () {
        try {
          this.getWindow().focus();
        }catch(e){}
      },

      /**
       * Clears the editor's document
       */
      clearDoc : function () {
        this.doc.body.innerHTML = "&nbsp;";
      },

      /**
       * Returns the last message sent by the user
       */
      getLastMessageTime : function () {
        return this.lastMessageSentAt;
      },

      /**
       * Sets the last message sent by the user
      */
      setLastMessageTime : function () {
        this.lastMessageSentAt = System.currentTimeMillis();
      },

      /**
       * Returns whether the conversation is private conversation
       */
      isPrivateConv : function () {
        var conv_sub_type = this.getSelectedSendToConvSubType()
        return (conv_sub_type == "R");
      },

      /**
       * Returns whether the conversation is a Group conversation is not
       */
      isGroupConv : function () {
        var conv_sub_type = this.getSelectedSendToConvSubType()
        return (conv_sub_type == "G");
      },

      /**
       * determines whether the user is admin or not
       */
      isAdmin : function () {
        return (this.user_role == "A"); 
      },
      
      setHeight : function(){
        try{
          var msgBlock = Dom.get(this.CHAT_MESSAGE_BLOCKS_ID);
          var nHeight = msgBlock.scrollHeight > 410 ? "410px" : "auto";
              Dom.setStyle(msgBlock, 'height', nHeight);
              
        }catch(e){}
      }

    }//end chat class






    //////////////////////////////////////////////////////////////////////////
    //
    // Smiley and Hyperlink parsing modules
    //
    //////////////////////////////////////////////////////////////////////////

    if ( typeof App === 'undefined') {
        App = {};

        // create another level of namespacing
        App.util = {};

        //some shorthand for YUI modules
        App.E = YAHOO.util.Event,
        App.D = YAHOO.util.Dom,
        App.L = YAHOO.lang;
    }
    
    /**
     * @Class HyperLinkProcessor
     * Processes hyperlinks in the chat messages and formats them in HTML way
     */
    App.util.HyperlinkProcessor = function () {
        //URL match regex
        this.URIRegex  = /((?:(?:ht|f)tps?):\/\/|w{3,3}\.)[^\s<]*[^\s<\.)]/ig;
        //Email match Regex
        this.mailRegex = /([\w!.%+\-])+@([\w\-])+(?:\.[\w\-]+)+/ig;

        this.hrefTpl = "<a href='{href}' class='mango-href' target='_new'>{text}</a>";
        this.mailTpl = "<a href='mailto:{email}' class='mango-href' target='_new'>{text}</a>";
    }

    App.util.HyperlinkProcessor.prototype = {

        /**
        * Processes the specified string for link tags, if found then formats those tags and returns the formatted strings
        * @param {String} str
        * @return {void}
        */
        process : function (str) {
            //find the URls first
            var match = str.match(this.URIRegex);
            if (match) {
                for (var i = 0, ln = match.length; i < ln; ++i ) {
                    str = str.replace(match[i], this.renderLink(match[i]));
                }
            }

            //now match emails
            //find the URls first
            var match = str.match(this.mailRegex);
            if (match) {
                for (var i = 0, ln = match.length; i < ln; ++i ) {
                    str = str.replace(match[i], this.renderMail(match[i]));
                }
            }

            return str;
        },

        /**
         * Formats the specified hyperlink as a HTML anchor tag
         * @param {String} href
         */
        renderLink : function (href) {
            //check for http:// prefix in href if not present then prepend it
            var anchor = /^http:\/\//.test(href) ? href : 'http://' + href;
            return App.L.substitute(this.hrefTpl, { href : anchor, text : href } );
        },

        /**
         * Formats the specified email as a HTML anchor tag with 'mailto:'
         */
        renderMail : function (email) {
            return App.L.substitute( this.mailTpl, { email : email, text : email } );
        }
    };

    //------------------------------------------------------------------------------------------------------------


    /**
     * @class SmileyParser
     * Parses input string for emoticon codes if found then replaces it with appropriate images
     */
    App.util.SmileyParser = function ( img_location, img_extension ) {
        this.imgBase = img_location || "/images/default/emoticons";
        this.imgExt    = img_extension || ".gif";
        this.initialized = false;

        //emoticons map
        this.smileyMap = {
            ':)'  : ['\\:\\)', '2'],
            ':-)' : ['\\:\\-\\)', '2'],
            ':]'  : ['\\:\\]', '2'],
            ':))' : ['\\:\\)\\)', '18'],
            ':-))': ['\\:\\-\\)\\)', '18'],
            ';)'  : [';\\)', '4'],
            ';-)' : [';\\-\\)', '4'],
            ':)]' : ['\\:\\)\\]', '100'],
            '/:)' : ['\\/\\:\\)', '20'],
            ':D'  : ['\\:D', '5'],
            ':-D' : ['\\:\\-D', '5'],
            ':?'  : ['\\:\\?', '39'],
            ':-?' : ['\\:\\-\\?', '39'],
            ':x'  : ['\\:x', '21'],
            ':-x' : ['\\:\\-x', '21'],
            ':((' : ['\\:\\(\\(', '17'],
            ':-((': ['\\:\\-\\(\\(', '17'],
            ':P'  : ['\\:P', '8'],
            ':-P' : ['\\:\\-P', '8'],
            ':h'  : ['\\:h', '103'],
            ':-h' : ['\\:\\-h', '103'],
            ':*'  : ['\\:\\*', '7'],
            ':-*' : ['\\:\\-\\*', '7'],
            ':O'  : ['\\:O', '10'],
            ':-O' : ['\\:\\-O', '10'],
            ':">' : ['\\:"\\>', '9'],
            ':-/' : ['\\:\\-\\/', '06'],
            ':-\\': ['\\:\\-\\\\', '06'],
            ':('  : ['\\:\\(', '3'],
            ':-(' : ['\\:\\-\\(', '3'],
            'I-)' : ['I\\-\\)', '28'],
            '|-)' : ['\\|\\-\\)', '28'],
            ':$'  : ['\\:\\$', '32'],
            ':-$' : ['\\:\\-\\$', '32'],
            '[-(' : ['\\[\\-\\(', '33'],
            'X-(' : ['X\\-\\(', '35'],
            'x-(' : ['x\\-\\(', '35'],
            '=))' : ['\\=\\)\\)', '24'],
            'B-)' : ['B\\-\\)', '12'],
            '#-o' : ['\\#\\-o', '34'],
            ':-B' : ['\\:\\-B', '22'],
            '>:)' : ['\\>\\:\\)', '16']
        };

        this._init();
    }

    /**
    * Initialize the smiley processing operation
    * @scope private
    * @return {void}
    */
    App.util.SmileyParser.prototype._init = function () {
        var regarr = [];

        for (var item in this.smileyMap) {
            regarr.push(this.smileyMap[item][0]);
        }
        //create the regular expression string
        var regex='(?:^|\\s|\'|"|\\.)(' + regarr.join('|') + ')(?:\\s|\'|"|\\.|,|!|\\?|$)';

        this.regexp = new RegExp(regex);
        this.initialized = true;
    }

    /**
     * Parses the input string for emoticon codes, if found then replaces the codes with images
     * @param {String} input
     * @param {Function} fn - optional
     * @return {void}
     */
    App.util.SmileyParser.prototype.parse = function (input, fn) {
        if(typeof fn != 'function') fn = function (){};

        var s = 0;
        var substr = input.replace(/\\/g, '\\'); // replace all '\' by double '\\'
        var output = [];

        while (1) {
            var found = this.regexp.exec(substr);
            if (!found) {
                break;
            }

            var index = found.index;
            var matchArr = this.smileyMap[found[1]];
            var nextIndex = found.index + found[1].length;
            var str = substr.substr(0, found.index);

            output.push(str);

            output.push('<img class="mango-smiley" src="' + this.imgBase + "/" + matchArr[1] + this.imgExt + '">');
            substr = substr.substr(nextIndex + 1);
        }

        if(substr) output.push(substr);

        return output.join("");
    }




/*
 * Conversation Utility Class (Module)
 *
 */
var ConvUtil = function () {
    return {
        /**
         * Function to create YUI alert, confirm and prompt dialog box
         * @param {String} type [CONFIRM, ALERT, PROMPT]
         * @param {Object} options
         */
        createSimpleDialog : function (type, options) {
            var $D = YAHOO.util.Dom,
		        $E = YAHOO.util.Event,
                $L = YAHOO.lang,
		        $W = YAHOO.widget;

            // default configure options
            var data = {
                width : "30em",
                zIndex : 256,
                fixedcenter : true,
                visible : false,
                draggable : false,
                modal : true
            };

            var title = "<div class='left'>" + options.title + "</div>";
            var message = options.message;
            var but_captions = options.button_captions || [];
            var handleYes, handleNo = null;

            //now delete these two properties from options
            delete options.title;
            delete options.message;
            delete options.button_captions;

            if (but_captions.length == 0) {
                but_captions = ["Ok", "Cancel"];
            }

            /**
             * callbacks fired on clicking the buttons
             */
            if(typeof options.handleYes == "function") {
                handleYes = options.handleYes;
                delete options.handleYes;
            }else {
                handleYes = function () {
                    handleNo();
                }
            }

            if(typeof options.handleNo == "function") {
                handleNo = options.handleNo;
            }else {
                handleNo = function () {
                    this.destroy();
                }
            }

            //augment the specified object with the default object
            $L.augmentObject(data, options, true);
            //now create the dialog
            var simple_dialog = new $W.SimpleDialog("ms_simple_dialog", data);
            simple_dialog.setHeader(title);
            simple_dialog.setBody(message);

            //override default hide method if no handleNo provided
            if(typeof options.handleNo != "function") {
                simple_dialog.hide = handleNo;
            }
            simple_dialog.CSS_FOOTER = "ft center";

            var buttons = [{text : but_captions[0], handler : handleYes, isDefault : true}];
            if (type.toUpperCase() == "CONFIRM" || type.toUpperCase() == "PROMPT") {
                buttons.push( {text : but_captions[1], handler : handleNo, idDefault : true} );
            }
            simple_dialog.cfg.queueProperty("buttons", buttons);

            simple_dialog.render(document.body);

            return simple_dialog;
        },

        /**
         * Function to trap enter key on specified element, binds the callback() with the element specified
         * @param {Object} elem
         * @param {Object} callback
         */
        trapEnterKey : function (elem, callback) {
            elem = $(elem);

            if(!elem) return;
            if(typeof callback != "function") return;

            MS.Event.add(elem, "keypress", function (event){
                var elem = event.srcElement || event.target;

                var key = event.keyCode || event.which;

                if(key == 13) {
                    // apply the callback function on the elem
                    callback.apply(elem, [event]);
                    MS.Event.cancel(event);
                }
            });
        }
    }
}();
    

} )( );

/**
 * Creating chat instance when the page dom creation is completed.
 */
var is_init_called = false;

YAHOO.util.Event.onDOMReady(function () {
    MSChatBoard = new ms.chatBoard.Chat();

    if( $("chatBoard") && !is_init_called ) {
        //Initializing the chat board.
        MSChatBoard.init();
        is_init_called = true;
    }
});