describe('<md-tabs>', function() {

  beforeEach(module('material.components.tabs'));
  beforeEach(function() {
    TestUtil.mockElementFocus(this);
    this.addMatchers({
      toBeActiveTab: function(checkFocus) {
        var fails = [];
        var actual = this.actual;
        this.message = function() {
          return 'Expected ' + angular.mock.dump(actual) + (this.isNot ? ' not ' : ' ') + 
            'to be the active tab. Failures: ' + fails.join(', ');
        };

        if (!actual.hasClass('active')) {
          fails.push('does not have active class');
        }
        if (actual.attr('aria-selected') != 'true') {
          fails.push('aria-selected is not true');
        } 
        if (actual.attr('tabindex') != '0') {
          fails.push('tabindex is not 0');
        }
        return fails.length === 0;
      }
    });
  });

  function setup(template) {
    var el; 
    inject(function($compile, $rootScope) {
      el = $compile(template)($rootScope.$new());
      $rootScope.$apply();
    });
    return el;
  }

  function triggerKeydown(el, keyCode) {
    return el.triggerHandler({
      type: 'keydown',
      keyCode: keyCode
    });
  }

  describe('activating tabs', function() {

    it('should select first tab by default', function() {
      var tabs = setup('<md-tabs>' +
            '<md-tab></md-tab>' +
            '<md-tab></md-tab>' +
            '</md-tabs>');
      expect(tabs.find('md-tab').eq(0)).toBeActiveTab();
    });

    it('should select & focus tab on click', inject(function($document) {
      var tabs = setup('<md-tabs>' +
            '<md-tab></md-tab>' +
            '<md-tab></md-tab>' +
            '<md-tab ng-disabled="true"></md-tab>' +
            '</md-tabs>');
      var tabItems = tabs.find('md-tab');

      tabs.find('md-tab').eq(1).triggerHandler('click');
      expect(tabItems.eq(1)).toBeActiveTab();
      expect($document.activeElement).toBe(tabItems[1]);
      
      tabs.find('md-tab').eq(0).triggerHandler('click');
      expect(tabItems.eq(0)).toBeActiveTab();
      expect($document.activeElement).toBe(tabItems[0]);
    }));

    it('should focus tab on arrow if tab is enabled', inject(function($document, $mdConstant) {
      var tabs = setup('<md-tabs>' +
                       '<md-tab></md-tab>' +
                       '<md-tab ng-disabled="true"></md-tab>' +
                       '<md-tab></md-tab>' +
                       '</md-tabs>');
      var tabItems = tabs.find('md-tab');
      expect(tabItems.eq(0)).toBeActiveTab();

      // Boundary case, do nothing
      triggerKeydown(tabItems.eq(0), $mdConstant.KEY_CODE.LEFT_ARROW);
      expect(tabItems.eq(0)).toBeActiveTab();

      // Tab 0 should still be active, but tab 2 focused (skip tab 1 it's disabled)
      triggerKeydown(tabItems.eq(0), $mdConstant.KEY_CODE.RIGHT_ARROW);
      expect(tabItems.eq(0)).toBeActiveTab();
      expect($document.activeElement).toBe(tabItems[2]);

      // Boundary case, do nothing
      triggerKeydown(tabItems.eq(0), $mdConstant.KEY_CODE.RIGHT_ARROW);
      expect(tabItems.eq(0)).toBeActiveTab();
      expect($document.activeElement).toBe(tabItems[2]);

      // Skip tab 1 again, it's disabled
      triggerKeydown(tabItems.eq(2), $mdConstant.KEY_CODE.LEFT_ARROW);
      expect(tabItems.eq(0)).toBeActiveTab();
      expect($document.activeElement).toBe(tabItems[0]);

    }));

    it('should select tab on space or enter', inject(function($mdConstant) {
      var tabs = setup('<md-tabs>' +
                       '<md-tab></md-tab>' +
                       '<md-tab></md-tab>' +
                       '</md-tabs>');
      var tabItems = tabs.find('md-tab');

      triggerKeydown(tabItems.eq(1), $mdConstant.KEY_CODE.ENTER);
      expect(tabItems.eq(1)).toBeActiveTab();

      triggerKeydown(tabItems.eq(0), $mdConstant.KEY_CODE.SPACE);
      expect(tabItems.eq(0)).toBeActiveTab();
    }));

    it('the active tab\'s content should always be connected', function() {
      var tabs = setup('<md-tabs>' +
                       '<md-tab label="label1!">content1!</md-tab>' +
                       '<md-tab label="label2!">content2!</md-tab>' +
                       '</md-tabs>');
      var tabItems = tabs.find('md-tab');
      var contents = angular.element(tabs[0].querySelectorAll('.md-tab-content'));

      expect(contents.eq(0).scope().$$disconnected).toBeFalsy();
      expect(contents.eq(1).scope().$$disconnected).toBeTruthy();

      tabItems.eq(1).triggerHandler('click');
      expect(contents.eq(0).scope().$$disconnected).toBeTruthy();
      expect(contents.eq(1).scope().$$disconnected).toBeFalsy();
    });

    it('should bind to selected', function() {
      var tabs = setup('<md-tabs md-selected="current">' +
                       '<md-tab></md-tab>' +
                       '<md-tab></md-tab>' +
                       '<md-tab></md-tab>' +
                       '</md-tabs>');
      var tabItems = tabs.find('md-tab');

      expect(tabItems.eq(0)).toBeActiveTab();
      expect(tabs.scope().current).toBe(0);

      tabs.scope().$apply('current = 1');
      expect(tabItems.eq(1)).toBeActiveTab();

      tabItems.eq(2).triggerHandler('click');
      expect(tabs.scope().current).toBe(2);
    });

    it('should use active binding', function() {
      var tabs = setup('<md-tabs>' +
                       '<md-tab md-active="active0"></md-tab>' +
                       '<md-tab md-active="active1"></md-tab>' +
                       '<md-tab md-active="active2"></md-tab>' +
                       '</md-tabs>');
      var tabItems = tabs.find('md-tab');

      tabs.scope().$apply('active2 = true');
      expect(tabItems.eq(2)).toBeActiveTab();
      tabs.scope().$apply('active1 = true');
      expect(tabItems.eq(1)).toBeActiveTab();
      tabs.scope().$apply('active1 = false');
      expect(tabItems.eq(1)).not.toBeActiveTab();
    });

    it('disabling active tab', function() {
      var tabs = setup('<md-tabs>' +
                       '<md-tab ng-disabled="disabled0"></md-tab>' +
                       '<md-tab ng-disabled="disabled1"></md-tab>' +
                       '</md-tabs>');
      var tabItems = tabs.find('md-tab');

      expect(tabItems.eq(0)).toBeActiveTab();

      tabs.scope().$apply('disabled0 = true');
      expect(tabItems.eq(1)).toBeActiveTab();
      expect(tabItems.eq(0).attr('aria-disabled')).toBe('true');
      expect(tabItems.eq(1).attr('aria-disabled')).not.toBe('true');

      tabs.scope().$apply('disabled0 = false; disabled1 = true');
      expect(tabItems.eq(0)).toBeActiveTab();
      expect(tabItems.eq(0).attr('aria-disabled')).not.toBe('true');
      expect(tabItems.eq(1).attr('aria-disabled')).toBe('true');
    });

    it('swiping tabs', function() {
      var tabs = setup('<md-tabs>' + 
                       '<md-tab></md-tab>' +
                       '<md-tab></md-tab>' +
                       '</md-tabs>');
      var tabItems = tabs.find('md-tab');

      tabItems.eq(0).isolateScope().onSwipe({
        type: 'swipeleft'
      });
      expect(tabItems.eq(1)).toBeActiveTab();

      tabItems.eq(1).isolateScope().onSwipe({
        type: 'swipeleft'
      });
      expect(tabItems.eq(1)).toBeActiveTab();

      tabItems.eq(1).isolateScope().onSwipe({
        type: 'swipeleft'
      });
      expect(tabItems.eq(1)).toBeActiveTab();

      tabItems.eq(1).isolateScope().onSwipe({
        type: 'swiperight'
      });
      expect(tabItems.eq(0)).toBeActiveTab();

      tabItems.eq(0).isolateScope().onSwipe({
        type: 'swiperight'
      });
      expect(tabItems.eq(0)).toBeActiveTab();
    });

  });

  describe('tab label & content DOM', function() {

    it('should support all 3 label types', function() {
      var tabs1 = setup('<md-tabs>' +
                       '<md-tab label="<b>super</b> label"></md-tab>' +
                       '</md-tabs>');
      expect(tabs1.find('md-tab-label').html()).toBe('<b>super</b> label');
      
      var tabs2 = setup('<md-tabs>' +
                   '<md-tab><b>super</b> label</md-tab>' +
                   '</md-tabs>');
      expect(tabs2.find('md-tab-label').html()).toBe('<b>super</b> label');

      var tabs3 = setup('<md-tabs>' +
                   '<md-tab><md-tab-label><b>super</b> label</md-tab-label></md-tab>' +
                   '</md-tabs>');
      expect(tabs3.find('md-tab-label').html()).toBe('<b>super</b> label');
    });

    it('should support content inside with each kind of label', function() {
      var tabs1 = setup('<md-tabs>' + 
                        '<md-tab label="label that!"><b>content</b> that!</md-tab>' +
                        '</md-tabs>');
      expect(tabs1.find('md-tab-label').html()).toBe('label that!');
      expect(tabs1[0].querySelector('.md-tabs-content .md-tab-content').innerHTML)
        .toBe('<b>content</b> that!');

      var tabs2 = setup('<md-tabs>' + 
                        '<md-tab><md-tab-label>label that!</md-tab-label><b>content</b> that!</md-tab>' +
                        '</md-tabs>');
      expect(tabs1.find('md-tab-label').html()).toBe('label that!');
      expect(tabs1[0].querySelector('.md-tabs-content .md-tab-content').innerHTML)
        .toBe('<b>content</b> that!');
    });

    it('should connect content with child of the outside scope', function() {
      var tabs = setup('<md-tabs>' +
                       '<md-tab label="label!">content!</md-tab>' +
                       '</md-tabs>');
      var content = angular.element(tabs[0].querySelector('.md-tab-content'));
      expect(content.scope().$parent.$id).toBe(tabs.find('md-tab').scope().$id);
    });

  });

  describe('aria', function() {

    it('should link tab content to tabItem with auto-generated ids', function() {
      var tabs = setup('<md-tabs>' +
                       '<md-tab label="label!">content!</md-tab>' +
                       '</md-tabs>');
      var tabItem = tabs.find('md-tab');
      var tabContent = angular.element(tabs[0].querySelector('.md-tab-content'));

      expect(tabs.attr('role')).toBe('tablist');

      expect(tabItem.attr('id')).toBeTruthy();
      expect(tabItem.attr('role')).toBe('tab');
      expect(tabItem.attr('aria-controls')).toBe(tabContent.attr('id'));

      expect(tabContent.attr('id')).toBeTruthy();
      expect(tabContent.attr('role')).toBe('tabpanel');
      expect(tabContent.attr('aria-labelledby')).toBe(tabItem.attr('id'));

      //Unique ids check
      expect(tabContent.attr('id')).not.toEqual(tabItem.attr('id'));
    });
  });

});
