/*
 *
 * (c) Copyright Ascensio System Limited 2010-2017
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
*/
/**
 *  Comments.js
 *
 *  Created by Alexey Musinov on 16.01.14
 *  Copyright (c) 2014 Ascensio System SIA. All rights reserved.
 *
 */

if (Common === undefined)
    var Common = {};
Common.Controllers = Common.Controllers || {};

define([
    'core',
    'common/main/lib/model/Comment',
    'common/main/lib/collection/Comments',
    'common/main/lib/view/Comments'
], function () {
    'use strict';

    // NOTE: временное решение

    function buildCommentData () {
        if (typeof Asc.asc_CCommentDataWord !== 'undefined') {
            return new Asc.asc_CCommentDataWord(null);
        }

        return new Asc.asc_CCommentData(null);
    }

    Common.Controllers.Comments = Backbone.Controller.extend(_.extend({
        models : [],
        collections : [
            'Common.Collections.Comments'
        ],
        views : [
            'Common.Views.Comments',
            'Common.Views.CommentsPopover'
        ],
        sdkViewName : '#id_main',
        subEditStrings : {},
        filter : undefined,
        hintmode : false,
        previewmode: false,
        isSelectedComment : false,
        uids : [],
        oldUids : [],
        isDummyComment : false,

        initialize: function () {

            this.addListeners({
                'Common.Views.Comments': {

                    // comments handlers

                    'comment:add':              _.bind(this.onCreateComment, this),
                    'comment:change':           _.bind(this.onChangeComment, this),
                    'comment:remove':           _.bind(this.onRemoveComment, this),
                    'comment:resolve':          _.bind(this.onResolveComment, this),
                    'comment:show':             _.bind(this.onShowComment, this),

                    // reply handlers

                    'comment:addReply':         _.bind(this.onAddReplyComment, this),
                    'comment:changeReply':      _.bind(this.onChangeReplyComment, this),
                    'comment:removeReply':      _.bind(this.onRemoveReplyComment, this),
                    'comment:editReply':        _.bind(this.onShowEditReplyComment, this),

                    // work handlers

                    'comment:closeEditing':     _.bind(this.closeEditing, this),
                    'comment:disableHint':      _.bind(this.disableHint, this),
                    'comment:addDummyComment':  _.bind(this.onAddDummyComment, this)
                }
            });

            Common.NotificationCenter.on('comments:updatefilter',   _.bind(this.onUpdateFilter, this));
            Common.NotificationCenter.on('app:comment:add',         _.bind(this.onAppAddComment, this));
            Common.NotificationCenter.on('layout:changed', function(area){
                Common.Utils.asyncCall(function(e) {
                    if ( e == 'toolbar' && this.view.$el.is(':visible') ) {
                        this.onAfterShow();
                    }
                }, this, area);
            }.bind(this));
        },
        onLaunch: function () {
            this.collection                     =   this.getApplication().getCollection('Common.Collections.Comments');
            if (this.collection) {
                this.collection.comparator      =   function (collection) { return -collection.get('time'); };
            }

            this.popoverComments                =   new Common.Collections.Comments();
            if (this.popoverComments) {
                this.popoverComments.comparator =   function (collection) { return -collection.get('time'); };
            }

            this.view                           =   this.createView('Common.Views.Comments', {
                store           :   this.collection,
                popoverComments :   this.popoverComments
            });
            this.view.render();

            this.bindViewEvents(this.view, this.events);
        },
        setConfig: function (data, api) {
            this.setApi(api);

            if (data) {
                this.currentUserId      =   data.config.user.id;
                this.currentUserName    =   data.config.user.fullname;
                this.sdkViewName        =   data['sdkviewname'] || this.sdkViewName;
                this.hintmode           =   data['hintmode'] || false;
                this.previewmode        =   data['previewmode'] || false;
            }
        },
        setApi: function (api) {
            if (api) {
                this.api = api;

                this.api.asc_registerCallback('asc_onAddComment', _.bind(this.onApiAddComment, this));
                this.api.asc_registerCallback('asc_onAddComments', _.bind(this.onApiAddComments, this));
                this.api.asc_registerCallback('asc_onRemoveComment', _.bind(this.onApiRemoveComment, this));
                this.api.asc_registerCallback('asc_onChangeComments', _.bind(this.onChangeComments, this));
                this.api.asc_registerCallback('asc_onRemoveComments', _.bind(this.onRemoveComments, this));
                this.api.asc_registerCallback('asc_onChangeCommentData', _.bind(this.onApiChangeCommentData, this));
                this.api.asc_registerCallback('asc_onLockComment', _.bind(this.onApiLockComment, this));
                this.api.asc_registerCallback('asc_onUnLockComment', _.bind(this.onApiUnLockComment, this));
                this.api.asc_registerCallback('asc_onShowComment', _.bind(this.onApiShowComment, this));
                this.api.asc_registerCallback('asc_onHideComment', _.bind(this.onApiHideComment, this));
                this.api.asc_registerCallback('asc_onUpdateCommentPosition', _.bind(this.onApiUpdateCommentPosition, this));

                this.api.asc_registerCallback('asc_onDocumentPlaceChanged', _.bind(this.onDocumentPlaceChanged, this));
            }
        },

        setMode: function(mode) {
            this.mode = mode;
            this.isModeChanged = true; // change show-comment mode from/to hint mode using canComments flag
            return this;
        },
        //

        onCreateComment: function (panel, commentVal, editMode, hidereply, documentFlag) {
            if (this.api && commentVal && commentVal.length > 0) {
                var comment = buildCommentData();   //  new asc_CCommentData(null);
                if (comment) {
                    this.showPopover        =   true;
                    this.editPopover        =   editMode ? true : false;
                    this.hidereply          =   hidereply;
                    this.isSelectedComment  =   false;
                    this.uids               =   [];

                    comment.asc_putText(commentVal);
                    comment.asc_putTime(this.utcDateToString(new Date()));
                    comment.asc_putOnlyOfficeTime(this.ooDateToString(new Date()));
                    comment.asc_putUserId(this.currentUserId);
                    comment.asc_putUserName(this.currentUserName);
                    comment.asc_putSolved(false);

                    if (!_.isUndefined(comment.asc_putDocumentFlag)) {
                        comment.asc_putDocumentFlag(documentFlag);
                    }

                    this.api.asc_addComment(comment);
                    this.view.showEditContainer(false);
                }
            }

            this.view.txtComment.focus();
        },
        onRemoveComment: function (id) {
            if (this.api && id) {
                this.api.asc_removeComment(id);
            }
        },
        onResolveComment: function (uid, id) {
            var t = this,
                reply = null,
                addReply = null,
                ascComment = buildCommentData(),   //  new asc_CCommentData(null),
                comment = t.findComment(uid, id);

            if (_.isUndefined(uid)) {
                uid = comment.get('uid');
            }

            if (ascComment && comment) {
                ascComment.asc_putText(comment.get('comment'));
                ascComment.asc_putQuoteText(comment.get('quote'));
                ascComment.asc_putTime(t.utcDateToString(new Date(comment.get('time'))));
                ascComment.asc_putOnlyOfficeTime(t.ooDateToString(new Date(comment.get('time'))));
                ascComment.asc_putUserId(comment.get('userid'));
                ascComment.asc_putUserName(comment.get('username'));
                ascComment.asc_putSolved(!comment.get('resolved'));

                if (!_.isUndefined(ascComment.asc_putDocumentFlag)) {
                    ascComment.asc_putDocumentFlag(comment.get('unattached'));
                }

                reply = comment.get('replys');
                if (reply && reply.length) {
                    reply.forEach(function (reply) {
                        addReply = buildCommentData();   //  new asc_CCommentData(null);
                        if (addReply) {
                            addReply.asc_putText(reply.get('reply'));
                            addReply.asc_putTime(t.utcDateToString(new Date(reply.get('time'))));
                            addReply.asc_putOnlyOfficeTime(t.ooDateToString(new Date(reply.get('time'))));
                            addReply.asc_putUserId(reply.get('userid'));
                            addReply.asc_putUserName(reply.get('username'));

                            ascComment.asc_addReply(addReply);
                        }
                    });
                }

                t.api.asc_changeComment(uid, ascComment);

                return true;
            }

            return false;
        },
        onShowComment: function (id, selected) {
            if (this.previewmode) return;

            var comment = this.findComment(id, undefined);
            if (comment) {
                if (null !== comment.get('quote')) {
                    if (this.api) {

                        if (this.hintmode) {
                            this.animate = true;

                            if (comment.get('unattached')) {
                                if (this.getPopover()) {
                                    this.getPopover().hide();
                                    return;
                                }
                            }
                        } else {
                            var model = this.popoverComments.findWhere({uid: id});
                            if (model) {
                                return;
                            }
                        }

                        if (!_.isUndefined(selected) && this.hintmode) {
                            this.isSelectedComment = selected;
                        }

                        this.api.asc_selectComment(id);
                        this._dontScrollToComment = true;
                        this.api.asc_showComment(id,false);
                    }
                } else {

                    if (this.hintmode) {
                        this.api.asc_selectComment(id);
                    }

                    if (this.getPopover()) {
                        this.getPopover().hide();
                    }

                    this.isSelectedComment = false;
                    this.uids = [];
                }
            }
        },
        onChangeComment: function (id, commentVal) {
            if (commentVal && commentVal.length > 0) {
                var t = this,
                    comment2 = null,
                    reply = null,
                    addReply = null,
                    ascComment = buildCommentData(),   //  new asc_CCommentData(null),
                    comment = t.findComment(id);

                if (comment && ascComment) {
                    ascComment.asc_putText(commentVal);
                    ascComment.asc_putQuoteText(comment.get('quote'));
                    ascComment.asc_putTime(t.utcDateToString(new Date(comment.get('time'))));
                    ascComment.asc_putOnlyOfficeTime(t.ooDateToString(new Date(comment.get('time'))));
                    ascComment.asc_putUserId(t.currentUserId);
                    ascComment.asc_putUserName(t.currentUserName);
                    ascComment.asc_putSolved(comment.get('resolved'));

                    if (!_.isUndefined(ascComment.asc_putDocumentFlag)) {
                        ascComment.asc_putDocumentFlag(comment.get('unattached'));
                    }

                    comment.set('editTextInPopover', false);

                    comment2 = t.findPopupComment(id);
                    if (comment2) {
                        comment2.set('editTextInPopover', false);
                    }

                    if (t.subEditStrings[id]) { delete t.subEditStrings[id]; }
                    if (t.subEditStrings[id + '-R']) { delete t.subEditStrings[id + '-R']; }

                    reply = comment.get('replys');

                    if (reply && reply.length) {
                        reply.forEach(function (reply) {
                            addReply = buildCommentData();   //  new asc_CCommentData(null);
                            if (addReply) {
                                addReply.asc_putText(reply.get('reply'));
                                addReply.asc_putTime(t.utcDateToString(new Date(reply.get('time'))));
                                addReply.asc_putOnlyOfficeTime(t.ooDateToString(new Date(reply.get('time'))));
                                addReply.asc_putUserId(reply.get('userid'));
                                addReply.asc_putUserName(reply.get('username'));

                                ascComment.asc_addReply(addReply);
                            }
                        });
                    }

                    t.api.asc_changeComment(id, ascComment);

                    return true;
                }
            }

            return false;
        },
        onChangeReplyComment: function (id, replyId, replyVal) {
            if (replyVal && replyVal.length > 0) {
                var me = this,
                    reply = null,
                    addReply = null,
                    ascComment = buildCommentData(),   //  new asc_CCommentData(null),
                    comment = me.findComment(id);

                if (ascComment && comment) {
                    ascComment.asc_putText(comment.get('comment'));
                    ascComment.asc_putQuoteText(comment.get('quote'));
                    ascComment.asc_putTime(me.utcDateToString(new Date(comment.get('time'))));
                    ascComment.asc_putOnlyOfficeTime(me.ooDateToString(new Date(comment.get('time'))));
                    ascComment.asc_putUserId(comment.get('userid'));
                    ascComment.asc_putUserName(comment.get('username'));
                    ascComment.asc_putSolved(comment.get('resolved'));

                    if (!_.isUndefined(ascComment.asc_putDocumentFlag)) {
                        ascComment.asc_putDocumentFlag(comment.get('unattached'));
                    }

                    reply = comment.get('replys');

                    if (reply && reply.length) {
                        reply.forEach(function (reply) {
                            addReply = buildCommentData();   //  new asc_CCommentData();
                            if (addReply) {
                                if (reply.get('id') === replyId && !_.isUndefined(replyVal)) {
                                    addReply.asc_putText(replyVal);
                                    addReply.asc_putUserId(me.currentUserId);
                                    addReply.asc_putUserName(me.currentUserName);
                                } else {
                                    addReply.asc_putText(reply.get('reply'));
                                    addReply.asc_putUserId(reply.get('userid'));
                                    addReply.asc_putUserName(reply.get('username'));
                                }

                                addReply.asc_putTime(me.utcDateToString(new Date(reply.get('time'))));
                                addReply.asc_putOnlyOfficeTime(me.ooDateToString(new Date(reply.get('time'))));

                                ascComment.asc_addReply(addReply);
                            }
                        });
                    }

                    me.api.asc_changeComment(id, ascComment);

                    return true;
                }
            }

            return false;
        },
        onAddReplyComment: function (id, replyVal) {
            if (replyVal.length > 0) {
                var me = this,
                    uid = null,
                    reply = null,
                    addReply = null,
                    ascComment = buildCommentData(),   //  new asc_CCommentData(null),
                    comment = me.findComment(id);

                if (ascComment && comment) {

                    uid = comment.get('uid');
                    if (uid) {
                        if (me.subEditStrings[uid]) { delete me.subEditStrings[uid]; }
                        if (me.subEditStrings[uid + '-R']) { delete me.subEditStrings[uid + '-R']; }
                        comment.set('showReplyInPopover', false);
                    }

                    ascComment.asc_putText(comment.get('comment'));
                    ascComment.asc_putQuoteText(comment.get('quote'));
                    ascComment.asc_putTime(me.utcDateToString(new Date(comment.get('time'))));
                    ascComment.asc_putOnlyOfficeTime(me.ooDateToString(new Date(comment.get('time'))));
                    ascComment.asc_putUserId(comment.get('userid'));
                    ascComment.asc_putUserName(comment.get('username'));
                    ascComment.asc_putSolved(comment.get('resolved'));

                    if (!_.isUndefined(ascComment.asc_putDocumentFlag)) {
                        ascComment.asc_putDocumentFlag(comment.get('unattached'));
                    }

                    reply = comment.get('replys');
                    if (reply && reply.length) {
                        reply.forEach(function (reply) {

                            addReply = buildCommentData();   //  new asc_CCommentData(null);
                            if (addReply) {
                                addReply.asc_putText(reply.get('reply'));
                                addReply.asc_putTime(me.utcDateToString(new Date(reply.get('time'))));
                                addReply.asc_putOnlyOfficeTime(me.ooDateToString(new Date(reply.get('time'))));
                                addReply.asc_putUserId(reply.get('userid'));
                                addReply.asc_putUserName(reply.get('username'));

                                ascComment.asc_addReply(addReply);
                            }
                        });
                    }

                    addReply = buildCommentData();   //  new asc_CCommentData(null);
                    if (addReply) {
                        addReply.asc_putText(replyVal);
                        addReply.asc_putTime(me.utcDateToString(new Date()));
                        addReply.asc_putOnlyOfficeTime(me.ooDateToString(new Date()));
                        addReply.asc_putUserId(me.currentUserId);
                        addReply.asc_putUserName(me.currentUserName);

                        ascComment.asc_addReply(addReply);

                        me.api.asc_changeComment(id, ascComment);

                        return true;
                    }
                }
            }

            return false;
        },
        onRemoveReplyComment: function (id, replyId) {
            if (!_.isUndefined(id) && !_.isUndefined(replyId)) {
                var me = this,
                    replies = null,
                    addReply = null,
                    ascComment = buildCommentData(),   //  new asc_CCommentData(null),
                    comment = me.findComment(id);

                if (ascComment && comment) {
                    ascComment.asc_putText(comment.get('comment'));
                    ascComment.asc_putQuoteText(comment.get('quote'));
                    ascComment.asc_putTime(me.utcDateToString(new Date(comment.get('time'))));
                    ascComment.asc_putOnlyOfficeTime(me.ooDateToString(new Date(comment.get('time'))));
                    ascComment.asc_putUserId(comment.get('userid'));
                    ascComment.asc_putUserName(comment.get('username'));
                    ascComment.asc_putSolved(comment.get('resolved'));

                    if (!_.isUndefined(ascComment.asc_putDocumentFlag)) {
                        ascComment.asc_putDocumentFlag(comment.get('unattached'));
                    }

                    replies = comment.get('replys');
                    if (replies && replies.length) {
                        replies.forEach(function (reply) {
                            if (reply.get('id') !== replyId) {
                                addReply = buildCommentData();   //  new asc_CCommentData(null);
                                if (addReply) {
                                    addReply.asc_putText(reply.get('reply'));
                                    addReply.asc_putTime(me.utcDateToString(new Date(reply.get('time'))));
                                    addReply.asc_putOnlyOfficeTime(me.ooDateToString(new Date(reply.get('time'))));
                                    addReply.asc_putUserId(reply.get('userid'));
                                    addReply.asc_putUserName(reply.get('username'));

                                    ascComment.asc_addReply(addReply);
                                }
                            }
                        });
                    }

                    me.api.asc_changeComment(id, ascComment);

                    return true;
                }
            }

            return false;
        },
        onShowEditReplyComment: function (id, replyId, inpopover) {
            var i, model, repliesSrc, repliesCopy;

            if (!_.isUndefined(id) && !_.isUndefined(replyId)) {
                if (inpopover) {
                    model = this.popoverComments.findWhere({uid: id});
                    if (model) {
                        repliesSrc = model.get('replys');
                        repliesCopy = _.clone(model.get('replys'));
                        if (repliesCopy) {
                            for (i = 0; i < repliesCopy.length; ++i) {
                                if (replyId === repliesCopy[i].get('id')) {
                                    repliesCopy[i].set('editTextInPopover', true);

                                    repliesSrc.length = 0;
                                    model.set('replys', repliesCopy);

                                    return true;
                                }
                            }
                        }
                    }
                } else {
                    model = this.collection.findWhere({uid: id});
                    if (model) {
                        repliesSrc = model.get('replys');
                        repliesCopy = _.clone(model.get('replys'));
                        if (repliesCopy) {
                            for (i = 0; i < repliesCopy.length; ++i) {
                                if (replyId === repliesCopy[i].get('id')) {
                                    repliesCopy[i].set('editText', true);

                                    repliesSrc.length = 0;
                                    model.set('replys', repliesCopy);

                                    return true;
                                }
                            }
                        }
                    }
                }
            }

            return false;
        },

        onUpdateFilter: function (filter, applyOnly) {
            if (filter && !this.view.isVisible()) {
                this.view.needUpdateFilter = filter;
                this.filter = {
                    property    :   filter.property,
                    value       :   filter.value
                };
                return;
            }
            this.view.needUpdateFilter = false;

            if (filter) {

                this.filter = {
                    property    :   filter.property,
                    value       :   filter.value
                };

                if (!applyOnly) {
                    if (this.getPopover()) {
                        this.getPopover().hide();
                    }
                }

                var t = this, endComment = null;

                this.collection.each(function (model) {
                    var prop = model.get(t.filter.property);
                    if (prop) {
                        model.set('hide', (null === prop.match(t.filter.value)), {silent: !!applyOnly});
                    }

                    if (model.get('last')) {
                        model.set('last', false, {silent:!!applyOnly});
                    }

                    if (!model.get('hide')) {
                        endComment = model;
                    }
                });

                if (endComment) {
                    endComment.set('last', true, {silent: !!applyOnly});
                }
                if (!applyOnly)
                    this.view.update();
            }
        },
        onAppAddComment: function (sender, to_doc) {
            if ( !!this.api.can_AddQuotedComment && this.api.can_AddQuotedComment() === false || to_doc) return;
            this.addDummyComment();
        },

        // SDK

        onApiAddComment: function (id, data) {
            var comment = this.readSDKComment(id, data);
            if (comment) {
                this.collection.push(comment);

                this.updateComments(true);

                if (this.showPopover) {
                    if (null !== data.asc_getQuoteText()) {
                        this.api.asc_selectComment(id);
                        this._dontScrollToComment = true;
                        this.api.asc_showComment(id, true);
                    }

                    this.showPopover = undefined;
                    this.editPopover = false;
                }
            }
        },
        onApiAddComments: function (data) {
            for (var i = 0; i < data.length; ++i) {
                var comment = this.readSDKComment(data[i].asc_getId(), data[i]);
                this.collection.push(comment);
            }

            this.updateComments(true);
        },
        onApiRemoveComment: function (id, silentUpdate) {
            if (this.collection.length) {
                var model = this.collection.findWhere({uid: id});
                if (model) {
                    this.collection.remove(model);
                    if (!silentUpdate) {
                        this.updateComments(true);
                    }
                }

                if (this.popoverComments.length) {
                    model = this.popoverComments.findWhere({uid: id});
                    if (model) {
                        this.popoverComments.remove(model);
                        if (0 === this.popoverComments.length) {
                            if (this.getPopover()) {
                                this.getPopover().hide();
                            }
                        }
                    }
                }
            }
        },
        onChangeComments: function (data) {
            for (var i = 0; i < data.length; ++i) {
                this.onApiChangeCommentData(data[i].Comment.Id, data[i].Comment, true);
            }

            this.updateComments(true);
        },
        onRemoveComments: function (data) {
            for (var i = 0; i < data.length; ++i) {
                this.onApiRemoveComment(data[i], true);
            }

            this.updateComments(true);
        },
        onApiChangeCommentData: function (id, data, silentUpdate) {
            var t = this,
                i = 0,
                date = null,
                replies = null,
                repliesCount = 0,
                dateReply = null,
                comment = this.findComment(id);

            if (comment) {
                t = this;

                date = (data.asc_getOnlyOfficeTime()) ? new Date(this.stringOOToLocalDate(data.asc_getOnlyOfficeTime())) :
                       ((data.asc_getTime() == '') ? new Date() : new Date(this.stringUtcToLocalDate(data.asc_getTime())));

                comment.set('comment',  data.asc_getText());
                comment.set('userid',   data.asc_getUserId());
                comment.set('username', data.asc_getUserName());
                comment.set('resolved', data.asc_getSolved());
                comment.set('quote',    data.asc_getQuoteText());
                comment.set('time',     date.getTime());
                comment.set('date',     t.dateToLocaleTimeString(date));

                replies = _.clone(comment.get('replys'));

                replies.length = 0;

                repliesCount = data.asc_getRepliesCount();
                for (i = 0; i < repliesCount; ++i) {

                    dateReply = (data.asc_getReply(i).asc_getOnlyOfficeTime()) ? new Date(this.stringOOToLocalDate(data.asc_getReply(i).asc_getOnlyOfficeTime())) :
                                ((data.asc_getReply(i).asc_getTime() == '') ? new Date() : new Date(this.stringUtcToLocalDate(data.asc_getReply(i).asc_getTime())));

                    replies.push(new Common.Models.Reply({
                        id                  : Common.UI.getId(),
                        userid              : data.asc_getReply(i).asc_getUserId(),
                        username            : data.asc_getReply(i).asc_getUserName(),
                        date                : t.dateToLocaleTimeString(dateReply),
                        reply               : data.asc_getReply(i).asc_getText(),
                        time                : dateReply.getTime(),
                        editText            : false,
                        editTextInPopover   : false,
                        showReplyInPopover  : false,
                        scope               : t.view,
                        editable            : t.mode.canEditComments || (data.asc_getReply(i).asc_getUserId() == t.currentUserId)
                    }));
                }

                replies.sort(function (a,b) { return a.get('time') - b.get('time');});
                comment.set('replys', replies);

                if (!silentUpdate) {
                    this.updateComments(false, true);

                    if (this.getPopover() && this.getPopover().isVisible()) {
                        this._dontScrollToComment = true;
                        this.api.asc_showComment(id, true);
                    }
                }
            }
        },
        onApiLockComment: function (id,userId) {
            var cur = this.findComment(id),
                usersStore = null,
                user = null;

            if (cur) {
                usersStore = this.getApplication().getCollection('Common.Collections.Users');
                if (usersStore) {
                    user = usersStore.findWhere({id: userId});
                    if (user) {
                        this.getPopover() && this.getPopover().saveText();
                        cur.set('lock', true);
                        cur.set('lockuserid', this.view.getUserName(user.get('username')));
                    }
                }
            }
        },
        onApiUnLockComment: function (id) {
            var cur = this.findComment(id);
            if (cur) {
                cur.set('lock', false);
                this.getPopover() && this.getPopover().loadText();
            }
        },
        onApiShowComment: function (uids, posX, posY, leftX, opts, hint) {
            if (this.previewmode) return;
            this.isModeChanged = false;
            
            if (hint && this.isSelectedComment && (0 === _.difference(this.uids, uids).length)) {
                // хотим показать тот же коментарий что был и выбран
                return;
            }
            if (this.mode && !this.mode.canComments)
                hint = true;

            var popover = this.getPopover();
            if (popover) {
                this.clearDummyComment();

                if (this.isSelectedComment && (0 === _.difference(this.uids, uids).length)) {
                    //NOTE: click to sdk view ?
                    if (this.api) {
                        //this.view.txtComment.blur();
                        popover.commentsView && popover.commentsView.setFocusToTextBox(true);
                        this.api.asc_enableKeyEvents(true);
                    }

                    return;
                }

                var i = 0,
                    saveTxtId = '',
                    saveTxtReplyId = '',
                    comment = null,
                    text = '',
                    animate = true;

                this.popoverComments.reset();

                for (i = 0; i < uids.length; ++i) {
                    saveTxtId = uids[i];
                    saveTxtReplyId = uids[i] + '-R';
                    comment = this.findComment(saveTxtId);

                    if (!comment) continue;

                    if (this.subEditStrings[saveTxtId] && !hint) {
                        comment.set('editTextInPopover', true);
                        text = this.subEditStrings[saveTxtId];
                    }
                    else if (this.subEditStrings[saveTxtReplyId] && !hint) {
                        comment.set('showReplyInPopover', true);
                        text = this.subEditStrings[saveTxtReplyId];
                    }

                    comment.set('hint', !_.isUndefined(hint) ? hint : false);

                    if (!hint && this.hintmode) {
                        if (0 === _.difference(this.uids, uids).length && (this.uids.length === 0))
                            animate = false;

                        if (this.oldUids.length && (0 === _.difference(this.oldUids, uids).length)) {
                            animate = false;
                            this.oldUids = [];
                        }
                    }

                    if (this.animate) {
                        animate = this.animate;
                        this.animate = false;
                    }

                    this.isSelectedComment = !hint || !this.hintmode;
                    this.uids = _.clone(uids);

                    this.popoverComments.push(comment);
                    if (!this._dontScrollToComment)
                        this.view.commentsView.scrollToRecord(comment);
                    this._dontScrollToComment = false;
                }

                if (popover.isVisible()) {
                    popover.hide();
                }

                popover.setLeftTop(posX, posY, leftX);
                popover.show(animate, false, true, text);
            }
        },
        onApiHideComment: function (hint) {
            var t = this;

            if (this.getPopover()) {
                if (this.isSelectedComment && hint) {
                    return;
                }

                if (hint && this.getPopover().isCommentsViewMouseOver()) return;

                this.popoverComments.each(function (model) {
                    if (model.get('editTextInPopover')) {
                        t.subEditStrings[model.get('uid')] = t.getPopover().getEditText();
                    }

                    if (model.get('showReplyInPopover')) {
                        t.subEditStrings[model.get('uid') + '-R'] = t.getPopover().getEditText();
                    }
                });

                this.getPopover().saveText(true);
                this.getPopover().hide();

                this.collection.clearEditing();
                this.popoverComments.clearEditing();

                this.oldUids = _.clone(this.uids);
                this.isSelectedComment = false;
                this.uids = [];

                this.popoverComments.reset();
            }
        },
        onApiUpdateCommentPosition: function (uids, posX, posY, leftX) {
            if (this.previewmode) return;

            var i, useAnimation = false,
                comment = null,
                text = undefined,
                saveTxtId = '',
                saveTxtReplyId = '';

            if (this.getPopover()) {
                this.getPopover().saveText();
                this.getPopover().hideTips();

                if (posY < 0 || this.getPopover().sdkBounds.height < posY || (!_.isUndefined(leftX) && this.getPopover().sdkBounds.width < leftX)) {
                    this.getPopover().hide();
                } else {
                    if (this.isModeChanged)
                        this.onApiShowComment(uids, posX, posY, leftX);
                    if (0 === this.popoverComments.length) {

                        this.popoverComments.reset();

                        for (i = 0; i < uids.length; ++i) {
                            saveTxtId = uids[i];
                            saveTxtReplyId = uids[i] + '-R';
                            comment = this.findComment(saveTxtId);

                            if (!comment) continue;

                            if (this.subEditStrings[saveTxtId]) {
                                comment.set('editTextInPopover', true);
                                text = this.subEditStrings[saveTxtId];
                            }
                            else if (this.subEditStrings[saveTxtReplyId]) {
                                comment.set('showReplyInPopover', true);
                                text = this.subEditStrings[saveTxtReplyId];
                            }

                            this.popoverComments.push(comment);
                        }

                        useAnimation = true;
                        this.getPopover().show(useAnimation, undefined, undefined, text);
                    } else if (!this.getPopover().isVisible()) {
                        this.getPopover().show(false, undefined, undefined, text);
                    }

                    this.getPopover().setLeftTop(posX, posY, leftX, undefined, true);

//                    if (this.isSelectedComment && (0 === _.difference(this.uids, uids).length)) {
                        //NOTE: click to sdk view ?
//                        if (this.api) {
//                            this.view.txtComment.blur();
//                            this.getPopover().commentsView.setFocusToTextBox(true);
//                            this.api.asc_enableKeyEvents(true);
//                        }
//                    }
                }
            }
        },
        onDocumentPlaceChanged: function () {
            if (this.isDummyComment && this.getPopover()) {
                if (this.getPopover().isVisible()) {
                    var anchor = this.api.asc_getAnchorPosition();
                    if (anchor) {
                        this.getPopover().setLeftTop(anchor.asc_getX() + anchor.asc_getWidth(),
                            anchor.asc_getY(),
                            this.hintmode ? anchor.asc_getX() : undefined);
                    }
                }
            }
        },

        // internal

        updateComments: function (needRender, disableSort) {
            if (needRender && !this.view.isVisible()) {
                this.view.needRender = needRender;
                return;
            }
            this.view.needRender = false;

            var me = this;
            me.updateCommentsTime = new Date();
            if (me.timerUpdateComments===undefined)
                me.timerUpdateComments = setInterval(function(){
                    if ((new Date()) - me.updateCommentsTime>100) {
                        clearInterval(me.timerUpdateComments);
                        me.timerUpdateComments = undefined;
                        me.updateCommentsView(needRender, disableSort);
                    }
               }, 25);
        },

        updateCommentsView: function (needRender, disableSort) {
            var i, end = true;

            if (_.isUndefined(disableSort)) {
                this.collection.sort();
            }

            if (needRender) {
                for (i = this.collection.length - 1; i >= 0; --i) {
                    if (end) {
                        this.collection.at(i).set('last', true, {silent: true});
                    } else {
                        if (this.collection.at(i).get('last')) {
                            this.collection.at(i).set('last', false, {silent: true});
                        }
                    }
                    end = false;
                }

                this.onUpdateFilter(this.filter, true);

                this.view.render();
            }

            this.view.update();
        },
        findComment: function (uid, id) {
            if (_.isUndefined(uid)) {
                return this.collection.findWhere({id: id});
            }

            return this.collection.findWhere({uid: uid});
        },
        findPopupComment: function (id) {
            return this.popoverComments.findWhere({id: id});
        },

        closeEditing: function (id) {
            var t = this;

            if (!_.isUndefined(id)) {
                var comment2 = this.findPopupComment(id);
                if (comment2) {
                    comment2.set('editTextInPopover', false);
                    comment2.set('showReplyInPopover', false);
                }

                if (this.subEditStrings[id]) { delete this.subEditStrings[id]; }
                if (this.subEditStrings[id + '-R']) { delete this.subEditStrings[id + '-R']; }
            }

            this.collection.clearEditing();
            this.collection.each(function (model) {
                var replies = _.clone(model.get('replys'));
                model.get('replys').length = 0;

                replies.forEach(function (reply) {
                    if (reply.get('editText'))
                        reply.set('editText', false);
                    if (reply.get('editTextInPopover'))
                        reply.set('editTextInPopover', false);
                });

                model.set('replys', replies);
            });

            this.view.showEditContainer(false);
            this.view.update();
        },
        disableHint: function (comment) {
            if (comment && this.mode.canComments) {
                comment.set('hint', false);
                this.api.asc_showComment(comment.get('uid'), false);

                this.isSelectedComment = true;
            }
        },
        blockPopover: function (flag) {
            this.isSelectedComment = flag;
            if (flag) {
                if (this.getPopover().isVisible()) {
                    this.getPopover().hide();
                }
            }
        },
        getPopover: function () {
            return this.view.getPopover(this.sdkViewName);
        },

        // helpers

        readSDKComment: function (id, data) {
            var date = (data.asc_getOnlyOfficeTime()) ? new Date(this.stringOOToLocalDate(data.asc_getOnlyOfficeTime())) :
                ((data.asc_getTime() == '') ? new Date() : new Date(this.stringUtcToLocalDate(data.asc_getTime())));
            var comment = new Common.Models.Comment({
                uid                 : id,
                userid              : data.asc_getUserId(),
                username            : data.asc_getUserName(),
                date                : this.dateToLocaleTimeString(date),
                quote               : data.asc_getQuoteText(),
                comment             : data.asc_getText(),
                resolved            : data.asc_getSolved(),
                unattached          : !_.isUndefined(data.asc_getDocumentFlag) ? data.asc_getDocumentFlag() : false,
                id                  : Common.UI.getId(),
                time                : date.getTime(),
                showReply           : false,
                editText            : false,
                last                : undefined,
                editTextInPopover   : (this.editPopover ? true : false),
                showReplyInPopover  : false,
                hideAddReply        : !_.isUndefined(this.hidereply) ? this.hidereply : (this.showPopover ? true : false),
                scope               : this.view,
                editable            : this.mode.canEditComments || (data.asc_getUserId() == this.currentUserId)
            });
            if (comment) {
                var replies = this.readSDKReplies(data);
                if (replies.length) {
                    comment.set('replys', replies);
                }
            }

            return comment;
        },
        readSDKReplies: function (data) {
            var i = 0,
                replies = [],
                date = null;
            var repliesCount = data.asc_getRepliesCount();
            if (repliesCount) {
                for (i = 0; i < repliesCount; ++i) {
                    date = (data.asc_getReply(i).asc_getOnlyOfficeTime()) ? new Date(this.stringOOToLocalDate(data.asc_getReply(i).asc_getOnlyOfficeTime())) :
                        ((data.asc_getReply(i).asc_getTime() == '') ? new Date() : new Date(this.stringUtcToLocalDate(data.asc_getReply(i).asc_getTime())));

                    replies.push(new Common.Models.Reply({
                        id                  : Common.UI.getId(),
                        userid              : data.asc_getReply(i).asc_getUserId(),
                        username            : data.asc_getReply(i).asc_getUserName(),
                        date                : this.dateToLocaleTimeString(date),
                        reply               : data.asc_getReply(i).asc_getText(),
                        time                : date.getTime(),
                        editText            : false,
                        editTextInPopover   : false,
                        showReplyInPopover  : false,
                        scope               : this.view,
                        editable            : this.mode.canEditComments || (data.asc_getReply(i).asc_getUserId() == this.currentUserId)
                    }));
                }

                replies.sort(function (a, b) {
                    return a.get('time') - b.get('time');
                });
            }

            return replies;
        },

        // dummy comment

        addDummyComment: function () {
            if (this.api) {
                var me = this, anchor = null, date = new Date(), dialog = this.getPopover();
                if (dialog) {
                    if (this.popoverComments.length) {
                        _.delay(function() {
                            dialog.commentsView.setFocusToTextBox();
                        }, 200);
                        return;
                    }

                    var comment = new Common.Models.Comment({
                        id: -1,
                        time: date.getTime(),
                        date: this.dateToLocaleTimeString(date),
                        userid: this.currentUserId,
                        username: this.currentUserName,
                        editTextInPopover: true,
                        showReplyInPopover: false,
                        hideAddReply: true,
                        scope: this.view,
                        dummy: true
                    });

                    this.popoverComments.reset();
                    this.popoverComments.push(comment);

                    this.uids = [];
                    this.isSelectedComment = true;
                    this.isDummyComment = true;

                    if (!_.isUndefined(this.api.asc_SetDocumentPlaceChangedEnabled)) {
                        me.api.asc_SetDocumentPlaceChangedEnabled(true);
                    }

                    dialog.handlerHide = (function () {
                    });

                    if (dialog.isVisible()) {
                        dialog.hide();
                    }

                    dialog.handlerHide = (function () {
                        me.clearDummyComment();
                    });

                    anchor = this.api.asc_getAnchorPosition();
                    if (anchor) {
                        dialog.setLeftTop(anchor.asc_getX() + anchor.asc_getWidth(),
                            anchor.asc_getY(),
                            this.hintmode ? anchor.asc_getX() : undefined);

                        dialog.show(true, false, true);
                    }
                }
            }
        },
        onAddDummyComment: function (commentVal) {
            if (this.api && commentVal && commentVal.length > 0) {
                var comment = buildCommentData();   //  new asc_CCommentData(null);
                if (comment) {
                    this.showPopover        = true;
                    this.editPopover        = false;
                    this.hidereply          = false;
                    this.isSelectedComment  = false;
                    this.uids               = [];
                    this.isDummyComment     = false;

                    this.popoverComments.reset();
                    if (this.getPopover().isVisible()) {
                       this.getPopover().hide();
                    }
                    comment.asc_putText(commentVal);
                    comment.asc_putTime(this.utcDateToString(new Date()));
                    comment.asc_putOnlyOfficeTime(this.ooDateToString(new Date()));
                    comment.asc_putUserId(this.currentUserId);
                    comment.asc_putUserName(this.currentUserName);
                    comment.asc_putSolved(false);

                    if (!_.isUndefined(comment.asc_putDocumentFlag))
                        comment.asc_putDocumentFlag(false);

                    this.api.asc_addComment(comment);
                    this.view.showEditContainer(false);

                    if (!_.isUndefined(this.api.asc_SetDocumentPlaceChangedEnabled)) {
                        this.api.asc_SetDocumentPlaceChangedEnabled(false);
                    }
                }
            }
        },
        clearDummyComment: function () {
            if (this.isDummyComment) {
                this.isDummyComment     = false;

                this.showPopover        = true;
                this.editPopover        = false;
                this.hidereply          = false;
                this.isSelectedComment  = false;
                this.uids               = [];

                var dialog = this.getPopover();
                if (dialog) {
                    dialog.handlerHide = (function () {
                    });

                    if (dialog.isVisible()) {
                        dialog.hide();
                    }
                }

                this.popoverComments.reset();

                if (!_.isUndefined(this.api.asc_SetDocumentPlaceChangedEnabled)) {
                    this.api.asc_SetDocumentPlaceChangedEnabled(false);
                }
            }
        },

        //

        onEditComments: function(comments) {
            if (this.api) {

                var i = 0,
                    t = this,
                    comment = null;

                var anchor = this.api.asc_getAnchorPosition();
                if (anchor) {

                    this.isSelectedComment = true;

                    this.popoverComments.reset();

                    for (i = 0; i < comments.length; ++i) {
                        comment = this.findComment(comments[i].asc_getId());
                        if (comment) {
                            comment.set('editTextInPopover', t.mode.canEditComments);// dont't edit comment when customization->commentAuthorOnly is true
                            comment.set('hint', false);
                            this.popoverComments.push(comment);
                        }
                    }

                    if (this.getPopover() && this.popoverComments.length>0) {
                        if (this.getPopover().isVisible()) {
                            this.getPopover().hide();
                        }
                        this.getPopover().setLeftTop(anchor.asc_getX() + anchor.asc_getWidth(),
                            anchor.asc_getY(),
                            this.hintmode ? anchor.asc_getX() : undefined);

                        this.getPopover().show(true, false, true);
                    }
                }
            }
        },

        onAfterShow: function () {
            if (this.view && this.api) {
                var panel = $('.new-comment-ct', this.view.el);
                if (panel && panel.length) {
                    if ('none' !== panel.css('display')) {
                        this.view.txtComment.focus();
                    }
                    if (this.view.needRender)
                        this.updateComments(true);
                    else if (this.view.needUpdateFilter)
                        this.onUpdateFilter(this.view.needUpdateFilter);
                    this.view.update();
                }
            }
        },

        onBeforeHide: function () {
            if (this.view) {
                this.view.showEditContainer(false);
            }
        },

        // utils

        timeZoneOffsetInMs: (new Date()).getTimezoneOffset() * 60000,

        stringOOToLocalDate: function (date) {
            if (typeof date === 'string')
                return parseInt(date);

            return 0;
        },
        ooDateToString: function (date) {
            if (Object.prototype.toString.call(date) === '[object Date]')
                return (date.getTime()).toString();

            return '';
        },

        stringUtcToLocalDate: function (date) {
            if (typeof date === 'string')
                return parseInt(date) + this.timeZoneOffsetInMs;

            return 0;
        },
        utcDateToString: function (date) {
            if (Object.prototype.toString.call(date) === '[object Date]')
                return (date.getTime() - this.timeZoneOffsetInMs).toString();

            return '';
        },

        dateToLocaleTimeString: function (date) {

            function format(date) {
                var strTime,
                    hours = date.getHours(),
                    minutes = date.getMinutes(),
                    ampm = hours >= 12 ? 'pm' : 'am';

                hours = hours % 12;
                hours = hours ? hours : 12; // the hour '0' should be '12'
                minutes = minutes < 10 ? '0'+minutes : minutes;
                strTime = hours + ':' + minutes + ' ' + ampm;

                return strTime;
            }

            // MM/dd/yyyy hh:mm AM

            return (date.getMonth() + 1) + '/' + (date.getDate()) + '/' + date.getFullYear() + ' ' + format(date);
        },

        getView: function(name) {
            return !name && this.view ?
                this.view : Backbone.Controller.prototype.getView.call(this, name);
        },

        setPreviewMode: function(mode) {
            this.previewmode = mode;
            if (this.getPopover())
                this.getPopover().hide();
        }

    }, Common.Controllers.Comments || {}));
});