odoo.define('mail/static/src/models/thread_viewer/thread_viewer.js', function (require) {
'use strict';

const { registerNewModel } = require('mail/static/src/model/model_core.js');
const { attr, many2one, one2one } = require('mail/static/src/model/model_field.js');

function factory(dependencies) {

    class ThreadViewer extends dependencies['mail.model'] {

        //----------------------------------------------------------------------
        // Public
        //----------------------------------------------------------------------

        /**
         * @param {integer} scrollHeight
         */
        saveThreadCacheScrollHeightAsInitial(scrollHeight) {
            if (!this.threadCache) {
                return;
            }
            if (this.chatter) {
                // Initial scroll height is disabled for chatter because it is
                // too complex to handle correctly and less important
                // functionally.
                return;
            }
            this.update({
                threadCacheInitialScrollHeights: Object.assign({}, this.threadCacheInitialScrollHeights, {
                    [this.threadCache.localId]: scrollHeight,
                }),
            });
        }

        /**
         * @param {integer} scrollTop
         */
        saveThreadCacheScrollPositionsAsInitial(scrollTop) {
            if (!this.threadCache) {
                return;
            }
            if (this.chatter) {
                // Initial scroll position is disabled for chatter because it is
                // too complex to handle correctly and less important
                // functionally.
                return;
            }
            this.update({
                threadCacheInitialScrollPositions: Object.assign({}, this.threadCacheInitialScrollPositions, {
                    [this.threadCache.localId]: scrollTop,
                }),
            });
        }

        //----------------------------------------------------------------------
        // Private
        //----------------------------------------------------------------------

        /**
         * @private
         * @returns {boolean}
         */
        _computeHasThreadView() {
            if (this.chatter) {
                return this.chatter.hasThreadView;
            }
            if (this.chatWindow) {
                return this.chatWindow.hasThreadView;
            }
            if (this.discuss) {
                return this.discuss.hasThreadView;
            }
            return this.hasThreadView;
        }

        /**
         * @private
         * @returns {string}
         */
        _computeStringifiedDomain() {
            if (this.chatter) {
                return '[]';
            }
            if (this.chatWindow) {
                return '[]';
            }
            if (this.discuss) {
                return this.discuss.stringifiedDomain;
            }
            return this.stringifiedDomain;
        }

        /**
         * @private
         * @returns {mail.thread|undefined}
         */
         _computeThread() {
            if (this.chatter) {
                if (!this.chatter.thread) {
                    return [['unlink']];
                }
                return [['link', this.chatter.thread]];
            }
            if (this.chatWindow) {
                if (!this.chatWindow.thread) {
                    return [['unlink']];
                }
                return [['link', this.chatWindow.thread]];
            }
            if (this.discuss) {
                if (!this.discuss.thread) {
                    return [['unlink']];
                }
                return [['link', this.discuss.thread]];
            }
            return [];
        }

        /**
         * @private
         * @returns {mail.thread_cache|undefined}
         */
        _computeThreadCache() {
            if (!this.thread) {
                return [['unlink']];
            }
            return [['link', this.thread.cache(this.stringifiedDomain)]];
        }

        /**
         * @private
         * @returns {mail.thread_viewer|undefined}
         */
        _computeThreadView() {
            if (!this.hasThreadView) {
                return [['unlink']];
            }
            if (this.threadView) {
                return [];
            }
            return [['create']];
        }

    }

    ThreadViewer.fields = {
        /**
         * States the `mail.chatter` managing `this`. This field is computed
         * through the inverse relation and should be considered read-only.
         */
        chatter: one2one('mail.chatter', {
            inverse: 'threadViewer',
        }),
        /**
         * Serves as compute dependency.
         */
        chatterHasThreadView: attr({
            related: 'chatter.hasThreadView',
        }),
        /**
         * Serves as compute dependency.
         */
        chatterThread: many2one('mail.thread', {
            related: 'chatter.thread',
        }),
        /**
         * States the `mail.chat_window` managing `this`. This field is computed
         * through the inverse relation and should be considered read-only.
         */
        chatWindow: one2one('mail.chat_window', {
            inverse: 'threadViewer',
        }),
        /**
         * Serves as compute dependency.
         */
        chatWindowHasThreadView: attr({
            related: 'chatWindow.hasThreadView',
        }),
        /**
         * Serves as compute dependency.
         */
        chatWindowThread: many2one('mail.thread', {
            related: 'chatWindow.thread',
        }),
        /**
         * States the `mail.discuss` managing `this`. This field is computed
         * through the inverse relation and should be considered read-only.
         */
        discuss: one2one('mail.discuss', {
            inverse: 'threadViewer',
        }),
        /**
         * Serves as compute dependency.
         */
        discussHasThreadView: attr({
            related: 'discuss.hasThreadView',
        }),
        /**
         * Serves as compute dependency.
         */
        discussStringifiedDomain: attr({
            related: 'discuss.stringifiedDomain',
        }),
        /**
         * Serves as compute dependency.
         */
        discussThread: many2one('mail.thread', {
            related: 'discuss.thread',
        }),
        /**
         * Determines whether `this.thread` should be displayed.
         */
        hasThreadView: attr({
            compute: '_computeHasThreadView',
            default: false,
            dependencies: [
                'chatterHasThreadView',
                'chatWindowHasThreadView',
                'discussHasThreadView',
            ],
        }),
        /**
         * Determines the domain to apply when fetching messages for `this.thread`.
         */
        stringifiedDomain: attr({
            compute: '_computeStringifiedDomain',
            default: '[]',
            dependencies: [
                'discussStringifiedDomain',
            ],
        }),
        /**
         * Determines the `mail.thread` that should be displayed by `this`.
         */
        thread: many2one('mail.thread', {
            compute: '_computeThread',
            dependencies: [
                'chatterThread',
                'chatWindowThread',
                'discussThread',
            ],
        }),
        /**
         * States the `mail.thread_cache` that should be displayed by `this`.
         */
        threadCache: many2one('mail.thread_cache', {
            compute: '_computeThreadCache',
            dependencies: [
                'stringifiedDomain',
                'thread',
            ],
        }),
        /**
         * Determines the initial scroll height of thread caches, which is the
         * scroll height at the time the last scroll position was saved.
         * Useful to only restore scroll position when the corresponding height
         * is available, otherwise the restore makes no sense.
         */
        threadCacheInitialScrollHeights: attr({
            default: {},
        }),
        /**
         * Determines the initial scroll positions of thread caches.
         * Useful to restore scroll position on changing back to this
         * thread cache. Note that this is only applied when opening
         * the thread cache, because scroll position may change fast so
         * save is already throttled.
         */
        threadCacheInitialScrollPositions: attr({
            default: {},
        }),
        /**
         * States the `mail.thread_view` currently displayed and managed by `this`.
         */
        threadView: one2one('mail.thread_view', {
            compute: '_computeThreadView',
            dependencies: [
                'hasThreadView',
            ],
            inverse: 'threadViewer',
            isCausal: true,
        }),
    };

    ThreadViewer.modelName = 'mail.thread_viewer';

    return ThreadViewer;
}

registerNewModel('mail.thread_viewer', factory);

});
