/**
 * $.fn.concreteConversation
 * Functions for conversation handling
 *
 * Events:
 *    beforeInitializeConversation         : Before Conversation Initialized
 *    initializeConversation               : Conversation Initialized
 *    conversationLoaded                   : Conversation Loaded
 *    conversationPostError                : Error posting message
 *    conversationBeforeDeleteMessage      : Before deleting message
 *    conversationDeleteMessage            : Deleting message
 *    conversationDeleteMessageError       : Error deleting message
 *    conversationBeforeAddMessageFromJSON : Before adding message from json
 *    conversationAddMessageFromJSON       : After adding message from json
 *    conversationBeforeUpdateCount        : Before updating message count
 *    conversationUpdateCount              : After updating message count
 *    conversationBeforeSubmitForm         : Before submitting form
 *    conversationSubmitForm               : After submitting form
 */

/* jshint unused:vars, undef:true, browser:true, jquery:true, -W041 */
/* global CCM_TOOLS_PATH, ConcreteEvent */

(function($,window){
  "use strict";
  $.extend($.fn,{
    concreteConversation:function(options) {
      return this.each(function() {
        var $obj = $(this);
        var data = $obj.data('concreteConversation');
        if (!data) {
          $obj.data('concreteConversation', (data = new ConcreteConversation($obj, options)));
        }
      });
    }
  });

  var i18n = {
    Confirm_remove_message: 'Remove this message? Replies to it will not be removed.',
    Confirm_mark_as_spam: 'Are you sure you want to flag this message as spam?',
    Warn_currently_editing: 'Please complete or cancel the current message editing session before editing this message.',
    Unspecified_error_occurred: 'An unspecified error occurred.',
    Error_deleting_message: 'Something went wrong while deleting this message, please refresh and try again.',
    Error_flagging_message: 'Something went wrong while flagging this message, please refresh and try again.'
    // Please add new translatable strings to the getConversationsJavascript of /concrete/controllers/frontend/assets_localization.php
  };
  $.fn.concreteConversation.localize = function(dictionary) {
    $.extend(true, i18n, dictionary);
  };

  var ConcreteConversation = function(element, options) {
    this.publish("beforeInitializeConversation",{element:element,options:options});
    this.init(element,options);
    this.publish("initializeConversation",{element:element,options:options});
  };
  ConcreteConversation.fn = ConcreteConversation.prototype = {
    publish: function(t,f) {
      f = f || {};
      f.ConcreteConversation = this;
      window.ConcreteEvent.publish(t,f);
    },
    init: function(element,options) {
      var obj = this;

      obj.$element = element;
      obj.options = $.extend({
        method:        'ajax',
        paginate:      false,
        displayMode:   'threaded',
        itemsPerPage:  -1,
        activeUsers:   [],
        uninitialized: true
      }, options);

      var enablePosting      = (obj.options.posttoken != '') ? 1 : 0;
      var paginate           = (obj.options.paginate) ? 1 : 0;
      var orderBy            = (obj.options.orderBy);
      var enableOrdering     = (obj.options.enableOrdering);
      var displayPostingForm = (obj.options.displayPostingForm);
      var enableCommentRating = (obj.options.enableCommentRating);
      var commentRatingUserID = (obj.options.commentRatingUserID);
      var commentRatingIP = (obj.options.commentRatingIP);
      var addMessageLabel = (obj.options.addMessageLabel) ? obj.options.addMessageLabel : '';
      var dateFormat = (obj.options.dateFormat);
      var customDateFormat = (obj.options.customDateFormat);
      var blockAreaHandle = (obj.options.blockAreaHandle);
      var maxFiles = (obj.options.maxFiles); // unused
      var maxFileSize = (obj.options.maxFileSize); // unused
      var fileExtensions = (obj.options.fileExtensions); // unused
      var attachmentsEnabled = (obj.options.attachmentsEnabled);
      var attachmentOverridesEnabled = (obj.options.attachmentOverridesEnabled);

      if (obj.options.method == 'ajax') {
        $.post(CCM_TOOLS_PATH + '/conversations/view_ajax', {
          'cnvID':               obj.options.cnvID,
          'cID':                 obj.options.cID,
          'blockID':             obj.options.blockID,
          'enablePosting':       enablePosting,
          'itemsPerPage':        obj.options.itemsPerPage,
          'addMessageLabel':     addMessageLabel,
          'paginate':            paginate,
          'displayMode':         obj.options.displayMode,
          'orderBy':             orderBy,
          'enableOrdering':      enableOrdering,
          'displayPostingForm':  displayPostingForm,
          'enableCommentRating': enableCommentRating,
          'commentRatingUserID': commentRatingUserID,
          'commentRatingIP':     commentRatingIP,
          'dateFormat':          dateFormat,
          'customDateFormat':    customDateFormat,
          'blockAreaHandle' :    blockAreaHandle,
          'attachmentsEnabled':  attachmentsEnabled,
          'attachmentOverridesEnabled' : attachmentOverridesEnabled

        }, function(r) {
          var oldobj = window.obj;
          window.obj = obj;
          obj.$element.empty().append(r);
          var hash = window.location.hash.match(/^#cnv([0-9]+)Message[0-9]+$/);
          if (hash !== null && hash[1] == obj.options.cnvID) {
            var target = $('a' + window.location.hash).offset();
            $('html, body').animate({scrollTop: target.top}, 800, 'linear');
          }
          window.obj = oldobj;
          obj.attachBindings();
          obj.publish('conversationLoaded');
        });
      } else {
        obj.attachBindings();
        obj.finishSetup();
        obj.publish('conversationLoaded');
      }
    },
    mentionList: function(items, coordinates, bindTo) {
      var obj = this;
      if (!coordinates) return;
      obj.dropdown.parent.css({top:coordinates.y,left:coordinates.x});
      if (items.length == 0) {
        obj.dropdown.handle.dropdown('toggle');
        obj.dropdown.parent.remove();
        obj.dropdown.active = false;
        obj.dropdown.activeItem = -1;
        return;
      }

      obj.dropdown.list.empty();
      items.slice(0,20).map(function(item){
        var listitem = $('<li/>');
        var anchor = $('<a/>').appendTo(listitem).text(item.getName());
        anchor.click(function(){ConcreteEvent.fire('ConversationMentionSelect',{obj:obj,item:item},bindTo);});
        listitem.appendTo(obj.dropdown.list);
      });
      if (!obj.dropdown.active) {
        obj.dropdown.active = true;
        obj.dropdown.activeItem = -1;
        obj.dropdown.parent.appendTo(obj.$element);
        obj.dropdown.handle.dropdown('toggle');
      }
      if (obj.dropdown.activeItem >= 0)
        obj.dropdown.list.children().eq(obj.dropdown.activeItem).addClass('active');
    },
    attachSubscriptionBindings: function() {
      $('a[data-conversation-subscribe]').magnificPopup({
        type: 'ajax',
        callbacks: {
          updateStatus: function(data) {
            if (data.status == 'ready') {
              var $form = $('form[data-conversation-form=subscribe]');
              $('button').on('click', $form, function(e) {
                e.preventDefault();
                e.stopPropagation();
                $.ajax({
                  url: $form.attr('action'),
                  dataType: 'json',
                  success: function(r) {
                    if (r.subscribed) {
                      $('[data-conversation-subscribe=subscribe]').hide();
                      $('[data-conversation-subscribe=unsubscribe]').show();
                    } else {
                      $('[data-conversation-subscribe=unsubscribe]').hide();
                      $('[data-conversation-subscribe=subscribe]').show();
                    }
                    $.magnificPopup.close();
                  }
                });
              });
            }
          },

          beforeOpen: function () {
            // just a hack that adds mfp-anim class to markup
            this.st.mainClass = 'mfp-zoom-in';
          }
        },
        closeOnContentClick: true,
        midClick: true // allow opening popup on middle mouse click. Always set it to true if you don't provide alternative source.
      });
    },

    attachBindings: function() {
      var obj = this;
      obj.$element.unbind('.cnv');
      if (obj.options.uninitialized) {
        obj.options.uninitialized = false;
        ConcreteEvent.bind('ConversationMention',function(e, data){
            obj.mentionList(data.items, data.coordinates || false, data.bindTo || obj.$element.get(0));
          },
          obj.$element.get(0) // Bind to this conversation only.
        );
        obj.dropdown = {};
        obj.dropdown.parent = $('<div/>').css({
          position:'absolute',
          height:0,
          width:0
        });
        obj.dropdown.active = false;
        obj.dropdown.handle = $('<a/>').appendTo(obj.dropdown.parent);
        obj.dropdown.list = $('<ul/>').addClass('dropdown-menu').appendTo(obj.dropdown.parent);
        obj.dropdown.handle.dropdown();
        ConcreteEvent.bind('ConversationTextareaKeydownUp',function(e){
          if (obj.dropdown.activeItem == -1) obj.dropdown.activeItem = obj.dropdown.list.children().length;
          obj.dropdown.activeItem -= 1;
          obj.dropdown.activeItem += obj.dropdown.list.children().length;
          obj.dropdown.activeItem %= obj.dropdown.list.children().length;
          obj.dropdown.list.children().filter('.active').removeClass('active').end().eq(obj.dropdown.activeItem).addClass('active');
        }, obj.$element.get(0));
        ConcreteEvent.bind('ConversationTextareaKeydownDown',function(e){
          obj.dropdown.activeItem += 1;
          obj.dropdown.activeItem += obj.dropdown.list.children().length;
          obj.dropdown.activeItem %= obj.dropdown.list.children().length;
          obj.dropdown.list.children().filter('.active').removeClass('active').end().eq(obj.dropdown.activeItem).addClass('active');
        }, obj.$element.get(0));
        ConcreteEvent.bind('ConversationTextareaKeydownEnter',function(e){
          obj.dropdown.list.children().filter('.active').children('a').click();
        }, obj.$element.get(0));
        ConcreteEvent.bind('ConversationPostError',function(e, data){
          var $form = data.form,
            messages = data.messages;
          var s = '';
          $.each(messages, function(i, m) {
            s += m + '<br>';
          });
          $form.find('div.ccm-conversation-errors').html(s).show();
        });
        ConcreteEvent.bind('ConversationSubmitForm',function(e, data){
          data.form.find('div.ccm-conversation-errors').hide();
        });
      }
      var paginate = (obj.options.paginate) ? 1 : 0;
      var enablePosting = (obj.options.posttoken != '') ? 1 : 0;
      var addMessageLabel = (obj.options.addMessageLabel) ? obj.options.addMessageLabel : '';

      obj.$replyholder = obj.$element.find('div.ccm-conversation-add-reply');
      obj.$newmessageform = obj.$element.find('div.ccm-conversation-add-new-message form');
      obj.$deleteholder = obj.$element.find('div.ccm-conversation-delete-message');
      obj.$attachmentdeleteholder = obj.$element.find('div.ccm-conversation-delete-attachment');
      obj.$permalinkholder = obj.$element.find('div.ccm-conversation-message-permalink');
      obj.$messagelist = obj.$element.find('div.ccm-conversation-message-list');
      obj.$messagecnt = obj.$element.find('.ccm-conversation-message-count');
      obj.$postbuttons = obj.$element.find('[data-submit=conversation-message]');
      obj.$sortselect = obj.$element.find('select[data-sort=conversation-message-list]');
      obj.$loadmore = obj.$element.find('[data-load-page=conversation-message-list]');
      obj.$messages = obj.$element.find('div.ccm-conversation-messages');
      obj.$messagerating = obj.$element.find('span.ccm-conversation-message-rating');

      obj.$element.on('click.cnv', '[data-submit=conversation-message]', function(e) {
        e.preventDefault();
        obj.submitForm($(this));
      });
      obj.$element.on('click.cnv', '[data-submit=update-conversation-message]', function() {
        obj.submitUpdateForm($(this));
        return false;
      });
      this.attachSubscriptionBindings();
      var replyIterator = 1;
      obj.$element.on('click.cnv', 'a[data-toggle=conversation-reply]', function(event) {
        event.preventDefault();
        $('.ccm-conversation-attachment-container').each(function() {
          if($(this).is(':visible')) {
            $(this).toggle();
          }
        });
        var $replyform = obj.$replyholder.appendTo($(this).closest('div[data-conversation-message-id]'));
        $replyform.attr('data-form', 'conversation-reply').show();
        $replyform.find('[data-submit=conversation-message]').attr('data-post-parent-id', $(this).attr('data-post-parent-id'));

        $replyform.attr('rel', 'new-reply' + replyIterator);
        replyIterator++;  // this may not be necessary, but might come in handy if we need to know how many times a new reply box has been triggered.
        return false;
      });

      $('.ccm-conversation-attachment-container').hide();
      $('.ccm-conversation-add-new-message .ccm-conversation-attachment-toggle').off('click.cnv').on('click.cnv', function(event){
        event.preventDefault();
        if($('.ccm-conversation-add-reply .ccm-conversation-attachment-container').is(':visible')) {
          $('.ccm-conversation-add-reply .ccm-conversation-attachment-container').toggle();
        }
        $('.ccm-conversation-add-new-message .ccm-conversation-attachment-container').toggle();
      });
      $('.ccm-conversation-add-reply .ccm-conversation-attachment-toggle').off('click.cnv').on('click.cnv', function(event){
        event.preventDefault();
        if($('.ccm-conversation-add-new-message .ccm-conversation-attachment-container').is(':visible')) {
          $('.ccm-conversation-add-new-message .ccm-conversation-attachment-container').toggle();
        }
        $('.ccm-conversation-add-reply .ccm-conversation-attachment-container').toggle();
      });

      obj.$element.on('click.cnv', 'a[data-submit=delete-conversation-message]', function() {
        var $link = $(this);
        obj.$deletedialog = obj.$deleteholder.clone();
        if (obj.$deletedialog.dialog) {
          obj.$deletedialog.dialog({
            modal: true,
            dialogClass: 'ccm-conversation-dialog',
            title: obj.$deleteholder.attr('data-dialog-title'),
            buttons: [
              {
                'text': obj.$deleteholder.attr('data-cancel-button-title'),
                'class': 'btn pull-left',
                'click': function() {
                  obj.$deletedialog.dialog('close');
                }
              },
              {
                'text': obj.$deleteholder.attr('data-confirm-button-title'),
                'class': 'btn pull-right btn-danger',
                'click': function() {
                  obj.deleteMessage($link.attr('data-conversation-message-id'));
                }
              }
            ]
          });
        } else {
          if (window.confirm(i18n.Confirm_remove_message)) {
            obj.deleteMessage($link.attr('data-conversation-message-id'));
          }
        }
        return false;
      });
      obj.$element.on('click.cnv', 'a[data-submit=flag-conversation-message]', function() {
        var $link = $(this);
        if (window.confirm(i18n.Confirm_mark_as_spam)) {
          obj.flagMessage($link.attr('data-conversation-message-id'));
        }
        return false;
      });
      obj.$element.on('click.cnv', 'a[data-load=edit-conversation-message]', function() {
        if($('.ccm-conversation-edit-message').is(':visible')) {
          window.alert(i18n.Warn_currently_editing);
          return false;
        }
        var $link = $(this);
        obj.editMessage($link.attr('data-conversation-message-id'));
      });
      obj.$element.on('change.cnv', 'select[data-sort=conversation-message-list]', function() {
        obj.$messagelist.load(CCM_TOOLS_PATH + '/conversations/view_ajax', {
          'cnvID':               obj.options.cnvID,
          'task':                'get_messages',
          'cID':                 obj.options.cID,
          'blockID':             obj.options.blockID,
          'enablePosting':       enablePosting,
          'displayMode':         obj.options.displayMode,
          'itemsPerPage':        obj.options.itemsPerPage,
          'paginate':            paginate,
          'addMessageLabel':     addMessageLabel,
          'orderBy':             $(this).val(),
          'enableOrdering':      obj.options.enableOrdering,
          'displayPostingForm':  obj.options.displayPostingForm,
          'enableCommentRating': obj.options.enableCommentRating,
          'dateFormat':          obj.options.dateFormat,
          'customDateFormat':    obj.options.customDateFormat,
          'blockAreaHandle':     obj.options.blockAreaHandle,
          'attachmentsEnabled':  obj.options.attachmentsEnabled,
          'attachmentOverridesEnabled': obj.options.attachmentOverridesEnabled

        }, function(r) {
          obj.$replyholder.appendTo(obj.$element);
          $('.ccm-conversation-messages .dropdown-toggle').dropdown();
          obj.attachBindings();
        });
      });

      obj.$element.on('click.cnv', '.image-popover-hover', function() {
        $.magnificPopup.open({
          items: {
            src: $(this).attr('data-full-image'), // can be a HTML string, jQuery object, or CSS selector
            type: 'image',
            verticalFit: true
          }
        });
      });



      obj.$element.on('click.cnv', '[data-load-page=conversation-message-list]', function() {
        var nextPage = parseInt(obj.$loadmore.attr('data-next-page'));
        var totalPages = parseInt(obj.$loadmore.attr('data-total-pages'));
        var data = {
          'cnvID':               obj.options.cnvID,
          'cID':                 obj.options.cID,
          'blockID':             obj.options.blockID,
          'itemsPerPage':        obj.options.itemsPerPage,
          'displayMode':         obj.options.displayMode,
          'blockAreaHandle':     obj.options.blockAreaHandle,
          'enablePosting':       enablePosting,
          'addMessageLabel':     addMessageLabel,
          'page':                nextPage,
          'orderBy':             obj.$sortselect.val(),
          'enableCommentRating': obj.options.enableCommentRating,
          'dateFormat':          obj.options.dateFormat,
          'customDateFormat':    obj.options.customDateFormat,
          'attachmentsEnabled':  obj.options.attachmentsEnabled,
          'attachmentOverridesEnabled': obj.options.attachmentOverridesEnabled
        };

        $.ajax({
          type: 'post',
          data: data,
          url: CCM_TOOLS_PATH + '/conversations/message_page',
          success: function(html) {
            obj.$messages.append(html);
            $('.ccm-conversation-messages .dropdown-toggle').dropdown();
            if ((nextPage + 1) > totalPages) {
              obj.$loadmore.hide();
            } else {
              obj.$loadmore.attr('data-next-page', nextPage + 1);
            }
          }
        });
      });

      obj.$element.on('click.cnv', '.conversation-rate-message', function() {
        var cnvMessageID = $(this).closest('[data-conversation-message-id]').attr('data-conversation-message-id');
        var cnvRatingTypeHandle = $(this).attr('data-conversation-rating-type');
        obj.$messagerating.load(CCM_TOOLS_PATH + '/conversations/rate');
        var data = {
          'cnvID':               obj.options.cnvID,
          'cID':                 obj.options.cID,
          'blockID':             obj.options.blockID,
          'cnvMessageID':        cnvMessageID,
          'cnvRatingTypeHandle': cnvRatingTypeHandle,
          'commentRatingUserID': obj.options.commentRatingUserID,
          'commentRatingIP':     obj.options.commentRatingIP
        };
        $.ajax({
          type: 'post',
          data: data,
          url: CCM_TOOLS_PATH + '/conversations/rate',
          success: function(html) {
            $('span[data-message-rating="' + cnvMessageID + '"]').load(CCM_TOOLS_PATH + '/conversations/get_rating', {
              'cnvMessageID':        cnvMessageID
            });
          }
        });
      });
      obj.$element.on('click.cnv', 'a.share-popup', function() {
        var dualScreenLeft = window.screenLeft != undefined ? window.screenLeft : screen.left;
        var dualScreenTop = window.screenTop != undefined ? window.screenTop : screen.top;
        var width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
        var height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height;
        var left = ((width / 2) - (300)) + dualScreenLeft;
        var top = ((height / 2) - (125)) + dualScreenTop;
        window.open($(this).attr('href'), 'cnvSocialShare','left:' + left + ',top:' + top + ',height=250,width=600,toolbar=no,status=no');

        return false;
      });
      obj.$element.on('click.cnv', 'a.share-permalink', function() {
        var $link = $(this);
        var permalink = $link.attr('rel');
        obj.$permalinkdialog = obj.$permalinkholder.clone();
        var $textarea = $('<textarea readonly>').text(decodeURIComponent(permalink));
        obj.$permalinkdialog.append($textarea);
        $textarea.click(function() {
          var $this = $(this);
          $this.select();
          window.setTimeout(function() {
            $this.select();
          }, 1);
          $this.mouseup(function() {
            $this.unbind("mouseup");
            return false;
          });
        });
        if (obj.$permalinkdialog.dialog) {
          obj.$permalinkdialog.dialog({
            modal: true,
            dialogClass: 'ccm-conversation-dialog',
            title: obj.$permalinkholder.attr('data-dialog-title'),
            buttons: [
              {
                'text': obj.$permalinkholder.attr('data-cancel-button-title'),
                'class': 'btn pull-left',
                'click': function() {
                  obj.$permalinkdialog.dialog('close');
                }
              }
            ]
          });
        }
        return false;
      });
      if(obj.options.attachmentsEnabled > 0) {
        obj.$element.concreteConversationAttachments(obj);
      }
      $('.dropdown-toggle').dropdown();
    },
    handlePostError: function($form, messages) {
      if (!messages) {
        messages = [i18n.Unspecified_error_occurred];
      }
      this.publish('conversationPostError',{form:$form,messages:messages});
    },
    deleteMessage: function(msgID) {

      var obj = this;
      obj.publish('conversationBeforeDeleteMessage',{msgID:msgID});
      var formArray = [{
        'name': 'cnvMessageID',
        'value': msgID
      }];

      $.ajax({
        type: 'post',
        data: formArray,
        url: CCM_TOOLS_PATH + '/conversations/delete_message',
        success: function(html) {
          var $parent = $('div[data-conversation-message-id=' + msgID + ']');

          if ($parent.length) {
            $parent.after(html).remove();
          }
          obj.updateCount();
          if (obj.$deletedialog.dialog)
            obj.$deletedialog.dialog('close');
          obj.publish('conversationDeleteMessage',{msgID:msgID});
        },
        error: function(e) {
          obj.publish('conversationDeleteMessageError',{msgID:msgID,error:arguments});
          window.alert(i18n.Error_deleting_message);
        }
      });
    },
    editMessage: function(msgID) {
      var obj = this;
      var formArray = [
        {
          'name': 'cnvMessageID',
          'value': msgID
        },
        {
          'name': 'cID',
          'value': this.options.cID
        },
        {
          'name': 'blockAreaHandle',
          'value': this.options.blockAreaHandle
        },
        {
          'name': 'bID',
          'value': this.options.blockID
        }
      ];
      $.ajax({
        type: 'post',
        data: formArray,
        url: CCM_TOOLS_PATH + '/conversations/edit_message',
        success: function(html) {
          var $parent = $('div[data-conversation-message-id=' + msgID + ']');
          var $previousContents = $parent;
          $parent.after(html).remove();
          $('.ccm-conversation-attachment-container').hide();
          $('.ccm-conversation-edit-message .ccm-conversation-attachment-toggle').off('click.cnv').on('click.cnv', function(event){
            event.preventDefault();
            $('.ccm-conversation-edit-message .ccm-conversation-attachment-container').toggle();
          });
          obj.$editMessageHolder = obj.$element.find('div.ccm-conversation-edit-message');
          obj.$element.concreteConversationAttachments(obj);
          $('button.cancel-update').on('click.cnv', function(){
            $('.ccm-conversation-edit-message').replaceWith($previousContents);
          });

        },
        error: function(e) {
          obj.publish('conversationEditMessageError',{msgID:msgID,error:arguments});
        }
      });
    },
    flagMessage: function(msgID) {

      var obj = this;
      obj.publish('conversationBeforeFlagMessage',{msgID:msgID});
      var formArray = [{
        'name': 'cnvMessageID',
        'value': msgID
      }];

      $.ajax({
        type: 'post',
        data: formArray,
        url: CCM_TOOLS_PATH + '/conversations/flag_message',
        success: function(html) {
          var $parent = $('div[data-conversation-message-id=' + msgID + ']');

          if ($parent.length) {
            $parent.after(html).remove();
          }
          obj.updateCount();
          obj.publish('conversationFlagMessage',{msgID:msgID});
        },
        error: function(e) {
          obj.publish('conversationFlagMessageError',{msgID:msgID,error:arguments});
          window.alert(i18n.Error_flagging_message);
        }
      });
    },
    addMessageFromJSON: function($form, json) {
      var obj = this;
      obj.publish('conversationBeforeAddMessageFromJSON',{json:json,form:$form});
      var enablePosting = (obj.options.posttoken != '') ? 1 : 0;
      var formArray = [{
        'name': 'cnvMessageID',
        'value': json.cnvMessageID
      }, {
        'name': 'enablePosting',
        'value': enablePosting
      }, {
        'name': 'displayMode',
        'value': obj.options.displayMode
      }, {
        'name': 'enableCommentRating',
        'value': obj.options.enableCommentRating
      }];

      $.ajax({
        type: 'post',
        data: formArray,
        url: CCM_TOOLS_PATH + '/conversations/message_detail',
        success: function(html) {
          var $parent = $('div[data-conversation-message-id=' + json.cnvMessageParentID + ']');

          if ($parent.length) {
            $parent.after(html);
            obj.$replyholder.appendTo(obj.$element);
            obj.$replyholder.hide();
            obj.$replyholder.find(".conversation-editor").val('');
            try {
              obj.$replyholder.find(".redactor_conversation_editor_" + obj.options.cnvID).redactor('set', '');
            } catch(e) {}
          } else {
            if (obj.options.orderBy == 'date_desc') {
              obj.$messages.prepend(html);
            } else {
              obj.$messages.append(html);
            }
            obj.$element.find('.ccm-conversation-no-messages').hide();
            obj.$newmessageform.find(".conversation-editor").val('');
            try {
              obj.$newmessageform.find(".redactor_conversation_editor_" + obj.options.cnvID).redactor('set', '');
            } catch(e) {}

          }
          obj.publish('conversationAddMessageFromJSON',{json:json,form:$form});
          obj.updateCount();
          var target = $('a#cnv' + obj.options.cnvID + 'Message' + json.cnvMessageID).offset();
          $('.dropdown-toggle').dropdown();
          $('html, body').animate({scrollTop: target.top}, 800, 'linear');
        }
      });
    },
    updateMessageFromJSON: function($form, json) {
      var obj = this;
      var enablePosting = (obj.options.posttoken != '') ? 1 : 0;
      var formArray = [{
        'name': 'cnvMessageID',
        'value': json.cnvMessageID
      }, {
        'name': 'enablePosting',
        'value': enablePosting
      }, {
        'name': 'displayMode',
        'value': obj.options.displayMode
      }, {
        'name': 'enableCommentRating',
        'value': obj.options.enableCommentRating
      }];

      $.ajax({
        type: 'post',
        data: formArray,
        url: CCM_TOOLS_PATH + '/conversations/message_detail',
        success: function(html) {
          var $parent = $('div[data-conversation-message-id=' + json.cnvMessageID + ']');
          $parent.after(html).remove();
          $('.dropdown-toggle').dropdown();
        }
      });
    },
    updateCount: function() {
      var obj = this;
      obj.publish('conversationBeforeUpdateCount');
      obj.$messagecnt.load(CCM_TOOLS_PATH + '/conversations/count_header', {
        'cnvID': obj.options.cnvID
      },function(){
        obj.publish('conversationUpdateCount');
      });
    },
    submitForm: function($btn) {
      var obj = this;
      obj.publish('conversationBeforeSubmitForm');
      var $form = $btn.closest('form');

      $btn.prop('disabled', true);
      $form.parent().addClass('ccm-conversation-form-submitted');
      var formArray = $form.serializeArray();
      var parentID = $btn.attr('data-post-parent-id');

      formArray.push({
        'name': 'token',
        'value': obj.options.posttoken
      }, {
        'name': 'cnvID',
        'value': obj.options.cnvID
      }, {
        'name': 'cnvMessageParentID',
        'value': parentID
      },{
        'name': 'enableRating',
        'value': parentID
      });
      $.ajax({
        dataType: 'json',
        type: 'post',
        data: formArray,
        url: CCM_TOOLS_PATH + '/conversations/add_message',
        success: function(r) {
          if (!r) {
            obj.handlePostError($form);
            return false;
          }
          if (r.error) {
            obj.handlePostError($form, r.errors);
            return false;
          }
          $('.preview.processing').each(function(){
            $('input[rel="'+ $(this).attr('rel') +'"]').remove();
          });
          $('form.dropzone').each(function(){
            var d = $(this).data('dropzone');
            $.each(d.files,function(k,v){
              d.removeFile(v);
            });
          });
          obj.addMessageFromJSON($form, r);
          obj.publish('conversationSubmitForm',{form:$form,response:r});
        },
        error: function(r) {
          obj.handlePostError($form);
          return false;
        },
        complete: function(r) {
          $btn.prop('disabled', false);
          $form.parent().closest('.ccm-conversation-form-submitted').removeClass('ccm-conversation-form-submitted');
        }
      });
    },
    submitUpdateForm: function($btn) {
      var obj = this;
      obj.publish('conversationBeforeSubmitForm');
      var $form = $btn.closest('form');

      $btn.prop('disabled', true);
      $form.parent().addClass('ccm-conversation-form-submitted');
      var formArray = $form.serializeArray();
      var cnvMessageID = $btn.attr('data-post-message-id');

      formArray.push({
        'name': 'token',
        'value': obj.options.posttoken
      }, {
        'name': 'cnvMessageID',
        'value': cnvMessageID
      });
      $.ajax({
        dataType: 'json',
        type: 'post',
        data: formArray,
        url: CCM_TOOLS_PATH + '/conversations/update_message',
        success: function(r) {
          if (!r) {
            obj.handlePostError($form);
            return false;
          }
          if (r.error) {
            obj.handlePostError($form, r.errors);
            return false;
          }
          $('.preview.processing').each(function(){
            $('input[rel="'+ $(this).attr('rel') +'"]').remove();
          });
          /*
           $('form.dropzone').each(function(){
           var d = $(this).data('dropzone');
           $.each(d.files,function(k,v){
           d.removeFile(v);
           });
           });
           */
          obj.updateMessageFromJSON($form, r);
          obj.publish('conversationSubmitForm',{form:$form,response:r});
        },
        error: function(r) {
          obj.handlePostError($form);
          return false;
        },
        complete: function(r) {
          $btn.prop('disabled', false);
          $form.parent().closest('.ccm-conversation-form-submitted').removeClass('ccm-conversation-form-submitted');
        }
      });
    },
    tool:{
      setCaretPosition:function(elem, caretPos) {
        // http://stackoverflow.com/a/512542/950669
        if(elem != null) {
          if(elem.createTextRange) {
            var range = elem.createTextRange();
            range.move('character', caretPos);
            range.select();
          }
          else {
            if(elem.selectionStart) {
              elem.focus();
              elem.setSelectionRange(caretPos, caretPos);
            }
            else
              elem.focus();
          }
        }
      },
      getCaretPosition: function(elem) {
        // http://stackoverflow.com/a/263796/950669
        if (elem.selectionStart) {
          return elem.selectionStart;
        } else if (document.selection) {
          elem.focus();

          var r = document.selection.createRange();
          if (r == null) {
            return 0;
          }

          var re = elem.createTextRange(),
            rc = re.duplicate();
          re.moveToBookmark(r.getBookmark());
          rc.setEndPoint('EndToStart', re);

          return rc.text.length;
        }
        return 0;
      },
      testMentionString: function(s) {
        return /^@[a-z0-9]+$/.test(s);
      },
      getMentionMatches: function(s,u) {
        return u.filter(function(d){return(d.indexOf(s)>=0);});
      },
      isSameConversation: function(o,n) {
        return (o.options.blockID === n.options.blockID && o.options.cnvID === n.options.cnvID);
      },

      // MentionUser class, use this to pass around data with your @mention names.
      MentionUser: function(name) {
        this.getName = function() { return name; };
      }
    }
  };
})(jQuery,window);