text: var specHelper = require('../spec-helper');
  var WidgetModel = require('../../../../javascripts/deep-insights/widgets/widget-model');
  var Backbone = require('backbone');
  var _ = require('underscore');
  
  describe('widgets/widget-model', function () {
    describe('dataview enabled', function () {
      var dataviewModel;
      var layerModel;
  
      beforeEach(function () {
        var vis = specHelper.createDefaultVis();
        var source = vis.analysis.findNodeById('a0');
  
        // Use a category dataview as example
        dataviewModel = vis.dataviews.createCategoryModel({
          column: 'col',
          source: source
        });
  
        layerModel = new Backbone.Model({
          id: 'first-layer',
          type: 'torque',
          visible: false
        });
  
        this.model = new WidgetModel(null, {
          dataviewModel: dataviewModel,
          layerModel: layerModel
        });
      });
  
      it('should be enabled always although layer is not visible', function () {
        expect(dataviewModel.get('enabled')).toBeTruthy();
      });
  
      it('should not change enable attribute although layer visibility changes', function () {
        layerModel.set('visible', true);
        expect(dataviewModel.get('enabled')).toBeTruthy();
        layerModel.set('visible', false);
        expect(dataviewModel.get('enabled')).toBeTruthy();
      });
    });
  
    describe('when autostyle options is enabled', function () {
      var dataviewModel;
      var layerModel;
  
      beforeEach(function () {
        var vis = specHelper.createDefaultVis();
        var source = vis.analysis.findNodeById('a0');
  
        // Use a category dataview as example
        dataviewModel = vis.dataviews.createCategoryModel({
          column: 'col',
          source: source
        });
        dataviewModel.remove = spyOn(dataviewModel, 'remove');
        layerModel = new Backbone.Model({
          id: 'first-layer',
          type: 'torque',
          visible: true
        });
  
        this.model = new WidgetModel(null, {
          dataviewModel: dataviewModel,
          layerModel: layerModel
        }, {autoStyleEnabled: true});
      });
  
      describe('.update', function () {
        beforeEach(function () {
          this.widgetChangeSpy = jasmine.createSpy('widgetModel change');
          this.model.on('change', this.widgetChangeSpy);
        });
  
        describe('when given empty object', function () {
          beforeEach(function () {
            this.result = this.model.update();
            this.result = this.model.update({}) || this.result;
          });
  
          it('should return false since did not change anything', function () {
            expect(this.result).toBe(false);
          });
  
          it('should not change anything', function () {
            expect(this.widgetChangeSpy).not.toHaveBeenCalled();
            expect(this.model.dataviewModel.changedAttributes()).toBe(false);
          });
        });
  
        describe('when there are some attrsNames but no dataview attrs names defined', function () {
          beforeEach(function () {
            this.model.set({
              attrsNames: ['title']
            }, { silent: true });
            this.result = this.model.update({
              title: 'new title',
              column: 'col',
              aggregation: 'count',
              invalid: 'attr, should not be set'
            });
          });
  
          it('should return true since attrs were changed', function () {
            expect(this.result).toBe(true);
          });
  
          it('should update widget', function () {
            expect(this.widgetChangeSpy).toHaveBeenCalled();
          });
  
          it('should have changed the valid attrs and leave the rest', function () {
            expect(this.model.hasChanged('title')).toBe(true);
          });
  
          it('should not change existing attrs', function () {
            expect(this.model.hasChanged('collapsed')).toBe(false);
          });
  
          it('should not set any invalid attrs', function () {
            expect(this.model.get('invalid')).toBeUndefined();
          });
  
          it('should not update dataviewModel', function () {
            expect(this.model.dataviewModel.changedAttributes()).toBe(false);
          });
        });
  
        describe('when there are both widget and dataview attrs names defined', function () {
          beforeEach(function () {
            this.model.set({
              attrsNames: ['title']
            }, { silent: true });
            this.result = this.model.update({
              title: 'new title',
              column: 'other',
              aggregation: 'sum',
              foo: 'attr, should not be set'
            });
          });
  
          it('should return true since attrs were changed', function () {
            expect(this.result).toBe(true);
          });
  
          it('should update the widget', function () {
            expect(this.model.changedAttributes()).toEqual({
              title: 'new title'
            });
          });
  
          it('should update the dataview model attrs', function () {
            expect(this.model.dataviewModel.changedAttributes()).toEqual({
              column: 'other',
              aggregation: 'sum'
            });
          });
        });
      });
  
      describe('.remove', function () {
        beforeEach(function () {
          this.removeSpy = jasmine.createSpy('remove');
          spyOn(this.model, 'stopListening');
          this.model.on('destroy', this.removeSpy);
          this.model.remove();
        });
  
        it('should remove the model', function () {
          expect(this.removeSpy).toHaveBeenCalledWith(this.model);
        });
  
        it('should remove dataviewModel', function () {
          expect(this.model.dataviewModel.remove).toHaveBeenCalled();
        });
  
        it('should call stop listening to events', function () {
          expect(this.model.stopListening).toHaveBeenCalled();
        });
      });
  
      describe('getState', function () {
        it('should only return states different from default', function () {
          this.model.setState({
            collapsed: true
          });
          expect(this.model.getState()).toEqual({collapsed: true});
        });
      });
  
      describe('isAutoStyleEnabled', function () {
        beforeEach(function () {
          this.model.set('type', 'category');
        });
  
        it('should return true without style options', function () {
          expect(this.model.isAutoStyleEnabled()).toBe(true);
        });
  
        it('should return true with empty object style options', function () {
          this.model.set('style', {});
          expect(this.model.isAutoStyleEnabled()).toBe(true);
        });
  
        it('should return true with style options', function () {
          var style = {
            auto_style: {
              allowed: true
            }
          };
          this.model.set('style', style);
          expect(this.model.isAutoStyleEnabled()).toBe(true);
        });
  
        it('should return false with style options', function () {
          var style = {
            auto_style: {
              allowed: false
            }
          };
          this.model.set('style', style);
          expect(this.model.isAutoStyleEnabled()).toBe(false);
        });
  
        it('should be false if type is not category or histogram', function () {
          var model = new WidgetModel(null, {
            dataviewModel: dataviewModel,
            layerModel: layerModel,
            type: 'time-series'
          }, {autoStyleEnabled: true});
  
          expect(model.isAutoStyleEnabled()).toBeFalsy();
        });
      });
  
      describe('.getAutoStyle', function () {
        it('should not provide any info if auto-style is not enabled', function () {
          spyOn(this.model, 'isAutoStyleEnabled').and.returnValue(false);
          var data = this.model.getAutoStyle();
          expect(data).toEqual({});
        });
  
        it('should not provide any info if autoStyler is not defined', function () {
          spyOn(this.model, 'isAutoStyleEnabled').and.returnValue(true);
          this.model.autoStyler = undefined;
          var data = this.model.getAutoStyle();
          expect(data).toEqual({});
        });
  
        it('should return proper definition and cartocss when no style model present', function () {
          var definition = 'a definition';
          var cartocss = 'some cartocss';
          spyOn(this.model, 'isAutoStyleEnabled').and.returnValue(true);
          this.model.autoStyler = {
            getDef: function () {
              return definition;
            }
          };
          layerModel.set('cartocss', cartocss);
          var expectedData = {
            definition: definition,
            cartocss: cartocss
          };
  
          var data = this.model.getAutoStyle();
  
          expect(_.isEqual(data, expectedData)).toBe(true);
        });
  
        it('should return proper definition and cartocss when auto_style property already present', function () {
          var definition = 'a definition';
          var cartocss = 'some cartocss';
          var style = {
            auto_style: {
              definition: 'other definition',
              cartocss: 'other cartocss',
              anotherProperty: 'another property'
            }
          };
          spyOn(this.model, 'isAutoStyleEnabled').and.returnValue(true);
          this.model.set('style', style);
          this.model.autoStyler = {
            getDef: function () {
              return definition;
            }
          };
          layerModel.set('cartocss', cartocss);
          var expectedData = {
            definition: definition,
            cartocss: cartocss,
            anotherProperty: 'another property'
          };
  
          var data = this.model.getAutoStyle();
  
          expect(_.isEqual(data, expectedData)).toBe(true);
        });
      });
  
      describe('.hasColorsAutoStyle', function () {
        it('should return false if autostyle or auto-style definition is empty', function () {
          spyOn(this.model, 'getAutoStyle').and.returnValue({
            cartocss: '#dummy {}',
            definition: {}
          });
          expect(this.model.hasColorsAutoStyle()).toBe(false);
          this.model.getAutoStyle.and.returnValue({});
          expect(this.model.hasColorsAutoStyle()).toBe(false);
        });
  
        it('should return false if color or range doesn\'t exist', function () {
          spyOn(this.model, 'getAutoStyle').and.returnValue({
            cartocss: '#dummy {}',
            definition: {
              point: {}
            }
          });
          expect(this.model.hasColorsAutoStyle()).toBe(false);
          this.model.getAutoStyle.and.returnValue({
            cartocss: '#dummy {}',
            definition: {
              point: {
                color: {}
              }
            }
          });
          expect(this.model.hasColorsAutoStyle()).toBe(false);
        });
  
        it('should return false if there is no colors defined', function () {
          spyOn(this.model, 'getAutoStyle').and.returnValue({
            cartocss: '#dummy {}',
            definition: {
              point: {
                color: {
                  range: []
                }
              }
            }
          });
          expect(this.model.hasColorsAutoStyle()).toBe(false);
  
          this.model.getAutoStyle.and.returnValue({
            cartocss: '#dummy {}',
            definition: {
              point: {
                color: {
                  range: {}
                }
              },
              line: {
                color: {
                  range: {}
                }
              },
              polygon: {
                color: {
                  range: {}
                }
              }
            }
          });
          expect(this.model.hasColorsAutoStyle()).toBe(false);
        });
  
        it('should return true if autostyle return any color', function () {
          spyOn(this.model, 'getAutoStyle').and.returnValue({
            cartocss: '#dummy {}',
            definition: {
              point: {
                color: {
                  range: ['#red']
                }
              }
            }
          });
          expect(this.model.hasColorsAutoStyle()).toBe(true);
        });
      });
  
      describe('.autoStyle', function () {
        beforeEach(function () {
          spyOn(this.model, 'isAutoStyleEnabled').and.returnValue(true);
          this.model.autoStyler = {
            getStyle: jasmine.createSpy('getStyle')
          };
  
          layerModel.set('initialStyle', 'foo');
          layerModel.set('cartocss', 'wadus');
        });
  
        it('should generate autostyle styles when dataview has data', function () {
          this.model.dataviewModel.set('data', [{
            name: 'foo'
          }, {
            name: 'bar'
          }]);
          this.model.autoStyle();
  
          expect(this.model.autoStyler.getStyle).toHaveBeenCalled();
          expect(layerModel.get('initialStyle')).toBe('wadus');
        });
  
        it('should not generate autostyle styles when dataview has data', function () {
          this.model.dataviewModel.set('data', []);
          this.model.autoStyle();
  
          expect(this.model.autoStyler.getStyle).not.toHaveBeenCalled();
          expect(layerModel.get('initialStyle')).toBe('foo');
        });
      });
    });
  
    describe('when autostyle option is disabled', function () {
      beforeEach(function () {
        var vis = specHelper.createDefaultVis();
        this.layerModel = vis.map.layers.first();
        var source = vis.analysis.findNodeById('a0');
        // Use a category dataview as example
        this.dataviewModel = vis.dataviews.createCategoryModel({
          column: 'col',
          source: source
        });
        this.dataviewModel.remove = spyOn(this.dataviewModel, 'remove');
      });
  
      describe('isAutoStyleEnabled', function () {
        it('should be true if without autostyle option', function () {
          var model = new WidgetModel(null, {
            dataviewModel: this.dataviewModel,
            layerModel: this.layerModel
          });
  
          model.set('type', 'category');
  
          expect(model.isAutoStyleEnabled()).toBe(true);
        });
  
        it('should be false if passed autostyle option as false', function () {
          var model = new WidgetModel(null, {
            dataviewModel: this.dataviewModel,
            layerModel: this.layerModel
          }, {autoStyleEnabled: false});
  
          model.set('type', 'category');
  
          expect(model.isAutoStyleEnabled()).toBe(false);
        });
  
        it('should be true if passed autostyle option as true', function () {
          var model = new WidgetModel(null, {
            dataviewModel: this.dataviewModel,
            layerModel: this.layerModel
          }, {autoStyleEnabled: true});
  
          model.set('type', 'category');
  
          expect(model.isAutoStyleEnabled()).toBe(true);
        });
      });
    });
  
    describe('.getWidgetColor', function () {
      beforeEach(function () {
        var vis = specHelper.createDefaultVis();
        this.layerModel = vis.map.layers.first();
        var source = vis.analysis.findNodeById('a0');
        // Use a category dataview as example
        this.dataviewModel = vis.dataviews.createCategoryModel({
          column: 'col',
          source: source
        });
  
        this.model = new WidgetModel(null, {
          dataviewModel: this.dataviewModel,
          layerModel: this.layerModel
        }, {autoStyleEnabled: false});
      });
  
      describe('when widget_color_changed is true', function () {
        it('should return color', function () {
          var style = {
            widget_style: {
              definition: {
                color: {
                  fixed: '#fabada'
                }
              },
              widget_color_changed: true
            }
          };
          this.model.set('style', style);
  
          expect(this.model.getWidgetColor()).toBe('#fabada');
        });
      });
  
      describe('when widget_color_changed is false', function () {
        it('should not return color', function () {
          var style = {
            widget_style: {
              definition: {
                color: {
                  fixed: '#9DE0AD'
                }
              },
              widget_color_changed: false
            }
          };
          this.model.set('style', style);
  
          expect(this.model.getWidgetColor()).toBe(false);
        });
  
        describe('and widget color value has changed', function () { // this is the case for existing widgets
          it('should return color', function () {
            var style = {
              widget_style: {
                definition: {
                  color: {
                    fixed: '#fabada',
                    opacity: 1
                  }
                }
              }
            };
            this.model.set('style', style);
  
            expect(this.model.getWidgetColor()).toBe('#fabada');
          });
        });
      });
    });
  
    describe('forceResize', function () {
      beforeEach(function () {
        this.model = new WidgetModel(null, {
          dataviewModel: new Backbone.Model(),
          layerModel: new Backbone.Model()
        });
      });
  
      it('should trigger forceResize event if it is a time-series', function () {
        spyOn(this.model, 'trigger');
        this.model.set('type', 'time-series');
        this.model.forceResize();
  
        expect(this.model.trigger).toHaveBeenCalledWith('forceResize');
      });
  
      it('should not trigger force Resize event if it is not a time-series', function () {
        spyOn(this.model, 'trigger');
        this.model.set('type', 'category');
        this.model.forceResize();
  
        expect(this.model.trigger).not.toHaveBeenCalledWith('forceResize');
      });
    });
  });
  