1 define([
  2     'jquery',
  3     'underscore',
  4     'viewcontroller',
  5     'chroma',
  6     'slickformatters',
  7     'slickeditors'
  8 ], function($, _, ViewControllers, chroma, slickformatters, slickeditors) {
  9 
 10   // we only use the base attribute class, no need to get the base class
 11   /** @private */
 12   var EmperorAttributeABC = ViewControllers.EmperorAttributeABC;
 13   /**
 14    * @class VisibilityController
 15    *
 16    * Manipulates and displays the visibility of objects on screen.
 17    *
 18    * @param {UIState} uiState The shared state
 19    * @param {Node} container Container node to create the controller in.
 20    * @param {Object} decompViewDict This object is keyed by unique
 21    * identifiers and the values are DecompositionView objects referring to a
 22    * set of objects presented on screen. This dictionary will usually be shared
 23    * by all the tabs in the application. This argument is passed by reference.
 24    *
 25    * @return {VisibilityController} An instance of VisibilityController
 26    * @constructs VisibilityController
 27    * @extends EmperorAttributeABC
 28    */
 29   function VisibilityController(uiState, container, decompViewDict) {
 30     var helpmenu = 'Change the visibility of the attributes on the plot, ' +
 31                    'such as spheres, vectors and ellipsoids.';
 32     var title = 'Visibility';
 33 
 34     // Constant for width in slick-grid
 35     var SLICK_WIDTH = 25, scope = this;
 36 
 37     // Build the options dictionary
 38     var options = {'valueUpdatedCallback': function(e, args) {
 39       var visible = args.item.value;
 40       var group = args.item.plottables;
 41       var element = scope.getView();
 42       scope.setPlottableAttributes(element, visible, group);
 43     },
 44       'categorySelectionCallback': function(evt, params) {
 45         var category = scope.$select.val();
 46 
 47         var decompViewDict = scope.getView();
 48 
 49         // getting all unique values per categories
 50         var uniqueVals = decompViewDict.decomp.getUniqueValuesByCategory(
 51           category);
 52         // getting color for each uniqueVals
 53         var attributes = {};
 54         _.each(uniqueVals, function(value) {
 55           attributes[value] = true;
 56         });
 57         // fetch the slickgrid-formatted data
 58         var data = decompViewDict.setCategory(
 59           attributes, scope.setPlottableAttributes, category);
 60 
 61         scope.setSlickGridDataset(data);
 62       },
 63       'slickGridColumn': {id: 'title', name: '', field: 'value',
 64         sortable: false, maxWidth: SLICK_WIDTH,
 65         minWidth: SLICK_WIDTH,
 66         formatter: Slick.Formatters.Checkmark,
 67         editor: Slick.Editors.Checkbox}};
 68 
 69     EmperorAttributeABC.call(this, uiState, container, title, helpmenu,
 70         decompViewDict, options);
 71 
 72     this.$applyAll = $("<input type='button' value='Toggle Visible'>"
 73     ).css({
 74       'margin': '0 auto',
 75       'display': 'block'
 76     });
 77     this.$header.append(this.$applyAll);
 78 
 79     $(function() {
 80       scope.$applyAll.hide();
 81       scope.$applyAll.on('click', function() {
 82         scope.toggleVisibility();
 83       });
 84     });
 85 
 86 
 87     return this;
 88   }
 89   VisibilityController.prototype = Object.create(EmperorAttributeABC.prototype);
 90   VisibilityController.prototype.constructor = EmperorAttributeABC;
 91 
 92   /**
 93    *
 94    * Private method to reset all objects to be visible.
 95    *
 96    * @extends EmperorAttributeABC
 97    * @private
 98    *
 99    */
100   VisibilityController.prototype._resetAttribute = function() {
101     EmperorAttributeABC.prototype._resetAttribute.call(this);
102 
103     _.each(this.decompViewDict, function(view) {
104       view.setVisibility(true);
105       view.showEdgesForPlottables();
106     });
107   };
108 
109   /**
110    * Helper function to set the visibility of plottable
111    *
112    * @param {Object} scope the scope where the plottables exist
113    * @param {boolean} visible Visibility of the plottables
114    * @param {Object[]} group Array of objects that should be changed in scope
115    */
116   VisibilityController.prototype.setPlottableAttributes =
117       function(scope, visible, group) {
118     scope.setVisibility(visible, group);
119   };
120 
121   /**
122    * Sets whether or not elements in the tab can be modified.
123    *
124    * @param {Boolean} trulse option to enable elements.
125    */
126   VisibilityController.prototype.setEnabled = function(trulse) {
127     EmperorAttributeABC.prototype.setEnabled.call(this, trulse);
128 
129     // prevent errors when this method is called before the element exists
130     if (this.$applyAll) {
131       if (trulse) {
132         this.$applyAll.show();
133       }
134       else {
135         this.$applyAll.hide();
136       }
137     }
138   };
139 
140   /**
141    * Toggle visible objects
142    */
143   VisibilityController.prototype.toggleVisibility = function() {
144     var view = this.getView();
145 
146     var groups = this.getSlickGridDataset();
147     _.each(groups, function(group) {
148 
149       // toggle the value in the data container and update the view
150       group.value = Boolean(true ^ group.value);
151       view.setVisibility(group.value, group.plottables);
152     });
153 
154     // lastly, update the grid table
155     this.setSlickGridDataset(groups);
156   };
157 
158 
159   return VisibilityController;
160 });
161