// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var widget_1 = require('./widget');
var widget_box_1 = require('./widget_box');
var tabbar_1 = require('phosphor/lib/ui/tabbar');
var title_1 = require('phosphor/lib/ui/title');
var widget_2 = require('phosphor/lib/ui/widget');
var _ = require('underscore');
var utils = require('./utils');
var $ = require('jquery');
var SelectionContainerModel = (function (_super) {
    __extends(SelectionContainerModel, _super);
    function SelectionContainerModel() {
        _super.apply(this, arguments);
    }
    SelectionContainerModel.prototype.defaults = function () {
        return _.extend(_super.prototype.defaults.call(this), {
            _model_name: 'SelectionContainerModel',
            selected_index: 0,
            _titles: {}
        });
    };
    return SelectionContainerModel;
}(widget_box_1.BoxModel));
exports.SelectionContainerModel = SelectionContainerModel;
var AccordionModel = (function (_super) {
    __extends(AccordionModel, _super);
    function AccordionModel() {
        _super.apply(this, arguments);
    }
    AccordionModel.prototype.defaults = function () {
        return _.extend(_super.prototype.defaults.call(this), {
            _model_name: 'AccordionModel',
            _view_name: 'AccordionView'
        });
    };
    return AccordionModel;
}(SelectionContainerModel));
exports.AccordionModel = AccordionModel;
var AccordionView = (function (_super) {
    __extends(AccordionView, _super);
    function AccordionView() {
        _super.apply(this, arguments);
        this.pages = [];
        this.view_pages = Object.create(null);
    }
    AccordionView.prototype.initialize = function (parameters) {
        var _this = this;
        _super.prototype.initialize.call(this, parameters);
        this.children_views = new widget_1.ViewList(this.add_child_view, this.remove_child_view, this);
        this.listenTo(this.model, 'change:children', function (model, value, options) {
            _this.children_views.update(value);
        });
    };
    /**
     * Called when view is rendered.
     */
    AccordionView.prototype.render = function () {
        this.el.className = 'jupyter-widgets widget-container widget-accordion';
        this.listenTo(this.model, 'change:selected_index', function (model, value, options) {
            this.update_selected_index(options);
        });
        this.listenTo(this.model, 'change:_titles', function (model, value, options) {
            this.update_titles(options);
        });
        this.children_views.update(this.model.get('children'));
        this.update_titles();
        this.update_selected_index();
    };
    /**
     * Set header titles
     */
    AccordionView.prototype.update_titles = function () {
        var titles = this.model.get('_titles');
        for (var i = 0; i < this.pages.length; i++) {
            if (titles[i] !== void 0) {
                this.pages[i].firstChild.textContent = titles[i];
            }
        }
    };
    /**
     * Make the rendering and selected index consistent.
     */
    AccordionView.prototype.update_selected_index = function (options) {
        var new_index = this.model.get('selected_index');
        this.pages.forEach(function (page, index) {
            if (index === new_index) {
                page.classList.add('accordion-active');
                // TODO: use CSS transitions?
                $(page.lastElementChild).slideDown('fast');
            }
            else {
                page.classList.remove('accordion-active');
                $(page.lastElementChild).slideUp('fast');
            }
        });
    };
    /**
     * Called when a child is removed from children list.
     */
    AccordionView.prototype.remove_child_view = function (view) {
        var page = this.view_pages[view.cid];
        this.pages.splice(this.pages.indexOf(page), 1);
        delete this.view_pages[view.cid];
        page.parentNode.removeChild(page);
        view.remove();
    };
    /**
     * Called when a child is added to children list.
     */
    AccordionView.prototype.add_child_view = function (model) {
        var _this = this;
        var page = document.createElement('div');
        page.classList.add('accordion-page');
        var header = document.createElement('div');
        header.classList.add('accordion-header');
        header.textContent = "Page " + this.pages.length;
        header.onclick = function () {
            var index = _this.pages.indexOf(page);
            _this.model.set('selected_index', index);
            _this.touch();
        };
        var content = document.createElement('div');
        content.classList.add('accordion-content');
        page.appendChild(header);
        page.appendChild(content);
        this.pages.push(page);
        this.el.appendChild(page);
        this.update_titles();
        this.update_selected_index;
        return this.create_child_view(model).then(function (view) {
            _this.view_pages[view.cid] = page;
            content.appendChild(view.el);
            // Trigger the displayed event of the child view.
            _this.displayed.then(function () {
                view.trigger('displayed', _this);
            });
            return view;
        }).catch(utils.reject('Could not add child view to box', true));
    };
    /**
     * We remove this widget before removing the children as an optimization
     * we want to remove the entire container from the DOM first before
     * removing each individual child separately.
     */
    AccordionView.prototype.remove = function () {
        _super.prototype.remove.call(this);
        this.children_views.remove();
    };
    return AccordionView;
}(widget_1.DOMWidgetView));
exports.AccordionView = AccordionView;
var TabModel = (function (_super) {
    __extends(TabModel, _super);
    function TabModel() {
        _super.apply(this, arguments);
    }
    TabModel.prototype.defaults = function () {
        return _.extend(_super.prototype.defaults.call(this), {
            _model_name: 'TabModel',
            _view_name: 'TabView'
        });
    };
    return TabModel;
}(SelectionContainerModel));
exports.TabModel = TabModel;
var TabView = (function (_super) {
    __extends(TabView, _super);
    function TabView() {
        _super.apply(this, arguments);
    }
    /**
     * Public constructor.
     */
    TabView.prototype.initialize = function (parameters) {
        _super.prototype.initialize.call(this, parameters);
        this.childrenViews = new widget_1.ViewList(this.addChildView, this.removeChildView, this);
        this.listenTo(this.model, 'change:children', function (model, value) { this.childrenViews.update(value); });
        this.listenTo(this.model, 'change:_titles', function (model, value, options) { this.updateTitles(options); });
    };
    /**
     * Called when view is rendered.
     */
    TabView.prototype.render = function () {
        var parent = this;
        this.el.className = 'jupyter-widgets widget-container widget-tab';
        this.tabBar = new tabbar_1.TabBar();
        this.tabBar.tabsMovable = false;
        this.tabBar.addClass('widget-tab-bar');
        this.tabBar.currentChanged.connect(this._onTabChanged, this);
        this.tabBar.tabCloseRequested.connect(this._onTabCloseRequested, this);
        this.tabContents = document.createElement('div');
        this.tabContents.className = 'widget-tab-contents';
        this.childrenViews.update(this.model.get('children'));
        this.displayed.then(function () {
            widget_2.Widget.attach(parent.tabBar, parent.el);
            parent.el.appendChild(parent.tabContents);
        });
    };
    /**
     * Called when a child is added to children list.
     */
    TabView.prototype.addChildView = function (model) {
        var parent = this;
        return this.create_child_view(model).then(function (child) {
            var current = parent.el.querySelector('.mod-active');
            if (current) {
                current.classList.add('mod-active');
                current.classList.add('mod-hidden');
            }
            child.el.classList.add('widget-tab-child');
            child.el.classList.add('mod-active');
            child.el.classList.remove('mod-hidden');
            // TODO: add a child widget, rather than DOM nodes
            parent.tabContents.appendChild(child.el);
            var title = new title_1.Title({ label: '', closable: true });
            parent.tabBar.addTab(title);
            parent.displayed.then(function () {
                child.trigger('displayed', parent);
                parent.update();
            });
            child.on('remove', function () { parent.tabBar.removeTab(title); });
            return child;
        }).catch(utils.reject('Could not add child view to box', true));
    };
    TabView.prototype.removeChildView = function (child) { child.remove(); };
    /**
     * Update the contents of this view
     *
     * Called when the model is changed.  The model may have been
     * changed by another view or by a state update from the back-end.
     */
    TabView.prototype.update = function (options) {
        this.updateTitles();
        this.updateSelectedIndex(options);
        return _super.prototype.update.call(this);
    };
    /**
     * Updates the tab page titles.
     */
    TabView.prototype.updateTitles = function () {
        var titles = this.model.get('_titles') || {};
        for (var i = 0, len = this.tabBar.titles.length; i < len; i++) {
            this.tabBar.titles.at(i).label = titles[i] || (i + 1).toString();
        }
    };
    /**
     * Updates the selected index.
     */
    TabView.prototype.updateSelectedIndex = function (options) {
        if (options === undefined || options.updated_view !== this) {
            var index = this.model.get('selected_index');
            if (typeof index === 'undefined') {
                index = 0;
            }
            if (0 <= index && index < this.tabBar.titles.length) {
                this.selectPage(index);
            }
        }
    };
    /**
     * Select a page.
     */
    TabView.prototype.selectPage = function (index) {
        this.tabBar.currentIndex = index;
        var actives = this.el.querySelectorAll('.mod-active');
        if (actives.length) {
            for (var i = 0, len = actives.length; i < len; i++) {
                actives[i].classList.remove('mod-active');
                actives[i].classList.add('mod-hidden');
            }
        }
        var active = this.el.querySelectorAll('.widget-tab-child')[index];
        if (active) {
            active.classList.add('mod-active');
            active.classList.remove('mod-hidden');
        }
    };
    TabView.prototype.remove = function () {
        /*
         * The tab bar needs to be disposed before its node is removed by the
         * super call, otherwise phosphor's Widget.detach will throw an error.
         */
        this.tabBar.dispose();
        /*
         * We remove this widget before removing the children as an optimization
         * we want to remove the entire container from the DOM first before
         * removing each individual child separately.
         */
        _super.prototype.remove.call(this);
        this.childrenViews.remove();
    };
    TabView.prototype._onTabChanged = function (sender, args) {
        this.model.set('selected_index', args.currentIndex, { updated_view: this });
        this.touch();
    };
    TabView.prototype._onTabCloseRequested = function (sender, args) {
        /*
         * When a tab is removed, the titles dictionary must be reset for all
         * indices that are larger than the index of the tab that was removed.
         */
        var len = this.model.get('children').length;
        var titles = _.extend({}, this.model.get('_titles')) || {};
        delete titles[args.index];
        for (var i = args.index + 1; i < len; i++) {
            titles[i - 1] = titles[i];
        }
        delete titles[len - 1];
        var children = _.filter(this.model.get('children'), function (child, index) { return index !== args.index; });
        this.model.set({ 'children': children, '_titles': titles }, { updated_view: this });
        this.touch();
    };
    return TabView;
}(widget_1.DOMWidgetView));
exports.TabView = TabView;
