# Source: ui/segmented-bar.reel/segmented-bar.js

    /*global require, exports, console, MontageElement */
    "use strict";

    /**
     * @module "montage/ui/segmented-bar.reel"
     * @requires montage/ui/base/abstract-button
     * @requires montage/core/range-controller
     * @requires montage/core/tree-controller
     */
    var AbstractButton = require("ui/base/abstract-button").AbstractButton,
        RangeController = require("core/range-controller").RangeController,
        TreeController = require("core/tree-controller").TreeController;

    /**
     * @class SegmentedBar
     *
     * A bar consisted of {@link Segment} components. Commonly used to visualize data, such as disk space usage.
     * Will accept an array of objects, `RangeController` or `TreeController` as data source.
     * `SegmentedBar` subclasses `AbstractButton` because of `AbstractButton`'s desired `PressComposer` behavior.
     *
     * @see {@link https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes}
     * for FlexBox usage
     *
     * @extends AbstractButton
     */
    var SegmentedBar = exports.SegmentedBar = AbstractButton.specialize( /** @lends SegmentedBar.prototype */ {
        /**
         * Dispatches by default based on the `enabled` property.
         *
         * @event SegmentedBar#action
         * @property {Dict} detail - selected segment's data
         * @property {String} detail.get("data").label
         * @property {Number} detail.get("data").length
         *
         * @example To access passed data, do `event.detail.get('data')` in event handler
         */

        /**
         * @private
         */
        _data: {value: null},

        /**
         * @property {Object[]}
         * @default null
         */
        data: {
            get: function () {return this._repetitionDataController.content;},
            set: function (data) {
                if (data !== this._data) {
                    this._data = data;

                    if (data) {
                        this._dataController = null;
                        this._repetitionDataController = new RangeController(data);
                    }

                    this.needsDraw = true;
                }
            }
        },

        /**
         * @private
         */
        _dataController: {value: null},

        /**
         * If `TreeController` is used, it will be flattened and only leaves without `children` will be rendered.
         *
         * @property {RangeController|TreeController} value
         * @default null
         */
        dataController: {
            get: function () {return this._dataController;},
            set: function (dataController) {
                if (dataController !== this._dataController) {
                    this._data = null;
                    this._dataController = dataController;

                    if (dataController instanceof TreeController) {
                        // Ensure TreeController always flattens
                        //dataController.initiallyExpanded = true;
                        //dataController.expandAll = true;

                        // Repetition only accepts RangeController;
                        // cannot do `new RangeController(dataController.iterations)`, need a binding,
                        // as TreeController may still be in isDeserializing state & TreeController.iterations is null here.
                        this._repetitionDataController = new RangeController();

                        // Even if TreeControllerNode has no children, it still has a .children property,
                        // hence need to check if its length is 0
                        this.defineBinding(
                            "_repetitionDataController.content", {
                                "<-": "iterations.filter{this.children.length == 0}",
                                source: dataController
                            }
                        );

                    } else { // RangeController
                        this._repetitionDataController = dataController;
                    }

                    this.needsDraw = true;
                }
            }
        },

        /**
         * Used to bind to Repetition as Repetition only accepts RangeController.
         *
         * @private
         * @property {RangeController} value - range of `Object`s or `TreeControllerNode`s,
         * depending on the type of `dataController`.
         */
        _repetitionDataController: {value: null},

        /**
         * @private
         */
        _orientation: {value: null},

        /**
         * Orientation of the bar will always be horizontal by default,
         * can be overridden by setting this property,
         * isn't auto-responsive due to inability to react to parent container dimension changes.
         *
         * @property {String} orientation
         */
        orientation: {
            get: function () {
                return this._orientation;
            },
            set: function (orientation) {
                if (this._orientation !== orientation) {
                    this._orientation = orientation;
                    this.needsDraw = true;
                }
            }
        },

        /**
         * @private
         * @function
         * @param {Event} event
         */
        _setComponentDataFromEvent: {
            value: function (event) {
                // User may click on Segment or its label
                var component = event.targetElement.className === "montage-Segment" ?
                    event.targetElement.component : event.targetElement.parentElement.component;

                // Inherited AbstractControl.detail is a Collections.js Dict
                if (this.detail.get("label") !== component.label || this.detail.get("length") !== component.length) {
                    this.detail.set("data", {
                        label: component.label,
                        length: component.length,
                    });
                }
            }
        },

        /**
         * Below event handlers augment superclass' by setting this.detail with selected segment's data.
         */

        handlePress: {
            value: function (event) {
                this._setComponentDataFromEvent(event);
                AbstractButton.prototype.handlePress.call(this);
            }
        },

        handleKeyup: {
            value: function (event) {
                this._setComponentDataFromEvent(event);
                AbstractButton.prototype.handleKeyup.call(this);
            }
        },

        handleLongPress: {
            value: function (event) {
                this._setComponentDataFromEvent(event);
                AbstractButton.prototype.handleLongPress.call(this);
            }
        },

        /**
         * Redraw based on data or orientation change.
         *
         * @function
         */
        draw: {
            value: function () {
                // Autoprefixer > 1%, last 2 versions, Firefox ESR, Opera 12.1

                if (this.orientation === "vertical" &&
                    this.templateObjects.repetition.element.style.flexDirection !== "column") {

                    this.templateObjects.repetition.element.style.webkitBoxOrient = "vertical";
                    this.templateObjects.repetition.element.style.webkitFlexDirection = "column";
                    this.templateObjects.repetition.element.style.msFlexDirection = "column";
                    this.templateObjects.repetition.element.style.flexDirection = "column";

                } else if (this.orientation === "horizontal" &&
                    this.templateObjects.repetition.element.style.flexDirection !== "row" &&
                    this.templateObjects.repetition.element.style.flexDirection) {
                    // SegmentedBar instantiates with no flex-direction value as default is "row",
                    // no need to set it at that point.

                    this.templateObjects.repetition.element.style.webkitBoxOrient = "horizontal";
                    this.templateObjects.repetition.element.style.webkitFlexDirection = "row";
                    this.templateObjects.repetition.element.style.msFlexDirection = "row";
                    this.templateObjects.repetition.element.style.flexDirection = "row";
                }
            }
        },

        /**
         * Cancel bindings for performance, while ensuring to not cancel bindings
         * SegmentedBar didn't define by not doing `repetition.cancelBindings()`;
         * doing so will break Repetition after SegmentedBar enterDocument again.
         *
         * @function
         */
        exitDocument: {
            value: function () {
                this.cancelBindings();

                if (this.templateObjects.repetition.getBinding("contentController")) {
                    this.templateObjects.repetition.cancelBinding("contentController");
                }
            }
        }
    });

    if (window.MontageElement) {
        MontageElement.define("montage-segmented-bar", SegmentedBar);
    }