var expect = require('chai').expect;
var cytoscape = require('../build/cytoscape.js', cytoscape);

describe('Collection style', function(){

  var cy;

  // test setup
  beforeEach(function(){
    cy = cytoscape({
      styleEnabled: true,

      elements: {
        nodes: [
            { data: { id: 'n1' } },
            { data: { id: 'n2' } },
            { data: { id: 'n3' } }
        ],

        edges: [
            { data: { id: 'n1n2', source: 'n1', target: 'n2' } },
            { data: { id: 'n2n3', source: 'n2', target: 'n3' } }
        ]
      }
    });
  });

  afterEach(function(){
    cy.destroy();
  });


  describe('eles.css() etc', function(){

    it('eles.css() gets a name-value pair object', function(){
      var css = cy.$('#n1').css();

      expect( css ).to.be.an('object');
      expect( css ).to.have.property('background-color');
      expect( css['background-color'] ).to.be.defined;
    });

    it('eles.css(name, val) gets and sets the specified property', function(){
      var n1 = cy.$('#n1');

      n1.css('width', '10px');

      expect( n1.css('width') ).to.equal('10px');
    });

    it('eles.css({}) sets the specified properties', function(){
      var n1 = cy.$('#n1');

      n1.css({
        height: '10px',
        width: '20px'
      });

      expect( n1.css('height') ).to.equal('10px');
      expect( n1.css('width') ).to.equal('20px');
    });

    it('eles.removeCss() clears bypassed style', function(){
      var n1 = cy.$('#n1');

      n1.css({
        height: '999px'
      });

      n1.removeCss();

      expect( n1.css('height') ).to.not.equal('999px');
    });

    it('eles.show() sets `display: element`', function(){
      var n1 = cy.$('#n1');

      n1.show();

      expect( n1.css('display') ).to.equal('element');
      expect( n1.visible() ).to.be.true;
    });

    it('eles.hide() sets `display: none`', function(){
      var n1 = cy.$('#n1');

      n1.hide();

      expect( n1.css('display') ).to.equal('none');
      expect( n1.hidden() ).to.be.true;
    });

    it('ele.effectiveOpacity() is correct for child', function(){
      cy.add([
        { group: 'nodes', data: { id: 'p' } },
        { group: 'nodes', data: { id: 'c', parent: 'p' } }
      ]);

      cy.$('#p').css('opacity', 0.5);
      cy.$('#c').css('opacity', 0.5);

      expect( cy.$('#c').effectiveOpacity() ).to.equal(0.25);
      expect( cy.$('#p').transparent() ).to.be.false;

      cy.$('#p').css('opacity', 0);

      expect( cy.$('#p').effectiveOpacity() ).to.equal(0);
      expect( cy.$('#p').transparent() ).to.be.true;
    });

  });

  describe('eles.addClass() etc', function(){

    var n1;
    var n2;

    beforeEach(function(){
      n1 = cy.$('#n1');
      n2 = cy.$('#n2');
    });

    it('eles.addClass() adds class', function(){
      n1.addClass('foo');

      expect( n1.hasClass('foo') ).to.be.true;
    });

    it('eles.addClass() adds classes', function(){
      n1.addClass('foo bar');

      expect( n1.hasClass('foo') ).to.be.true;
      expect( n1.hasClass('bar') ).to.be.true;
    });

    it('eles.removeClass() removes class', function(){
      n1.addClass('foo');
      n1.removeClass('foo');

      expect( n1.hasClass('foo') ).to.be.false;
    });

    it('eles.removeClass() removes classes', function(){
      n1.addClass('foo bar');
      n1.removeClass('foo bar');

      expect( n1.hasClass('foo') ).to.be.false;
      expect( n1.hasClass('bar') ).to.be.false;
    });

    it('eles.toggleClass() toggles class', function(){
      n1.addClass('foo');
      n1.toggleClass('foo');

      expect( n1.hasClass('foo') ).to.be.false;
    });

    it('eles.toggleClass() toggles classes', function(){
      n1.addClass('foo bar');
      n1.toggleClass('foo bar');

      expect( n1.hasClass('foo') ).to.be.false;
      expect( n1.hasClass('bar') ).to.be.false;
    });

    it('eles.toggleClass() forces class', function(){
      n1.addClass('foo');
      n1.toggleClass('foo', false);

      expect( n1.hasClass('foo') ).to.be.false;
    });

    it('eles.toggleClass() forces classes', function(){
      n1.addClass('foo bar');
      n1.toggleClass('foo bar', false);

      expect( n1.hasClass('foo') ).to.be.false;
      expect( n1.hasClass('bar') ).to.be.false;
    });

  });

  describe('eles.animate() etc', function(){

    var n1;
    var n2;

    beforeEach(function(){
      n1 = cy.$('#n1');
      n2 = cy.$('#n2');
    });

    it('ele.animate() results in end style', function( next ){
      n1.animate({
        style: { width: 200 },
        complete: function(){
          expect( parseFloat(n1.style().width) ).to.equal(200);
          next();
        },
        duration: 100
      });
    });

    it('eles.animate() results in end style', function( next ){
      var c = 0;
      function complete(){
        c++;

        if( c === 2 ){
          expect( parseFloat(n1.style().width) ).to.equal(200);
          expect( parseFloat(n2.style().width) ).to.equal(200);
          next();
        }
      }

      n1.add(n2).animate({
        style: { width: 200 },
        complete: complete,
        duration: 100
      });
    });

    it('ele.animation() results in end style', function( next ){
      n1.animation({
        style: { width: 200 },
        duration: 100
      }).play().promise().then(function(){
        expect( parseFloat(n1.style().width) ).to.equal(200);
        next();
      });
    });

    it('ani.playing()', function(){
      var ani = n1.animation({
        style: { width: 200 },
        duration: 100
      });

      expect( ani.playing() ).to.be.false;

      ani.play();

      expect( ani.playing() ).to.be.true;

      return ani.promise().then(function(){
        expect( ani.playing() ).to.be.false;
      });
    });

    it('ani.pause()', function( next ){
      var ani = n1.animation({
        style: { width: 200 },
        duration: 200
      });

      ani.play();

      var w;

      setTimeout(function(){
        ani.pause();

        w = n1.style('width');
      }, 100);

      setTimeout(function(){
        expect( ani.playing() ).to.be.false;

        expect( n1.style('width') ).to.equal(w);

        next();
      }, 200);
    });

    it('ani.pause() then ani.play()', function(next){
      var ani = n1.animation({
        style: { width: 200 },
        duration: 200
      });

      setTimeout(function(){
        ani.pause();
      }, 100);

      setTimeout(function(){
        ani.play().promise().then( next );
      }, 100);
    });

    it('ele.animation() x2 results in end style', function( next ){
      var d = 0;
      var done = function(){
        d++;

        if( d === 2 ){ next(); }
      };

      n1.animation({
        style: { width: 200 },
        duration: 100
      }).play().promise().then(function(){
        expect( parseFloat(n1.style().width) ).to.equal(200);

        done();
      });

      n2.animation({
        style: { width: 200 },
        duration: 100
      }).play().promise().then(function(){
        expect( parseFloat(n2.style().width) ).to.equal(200);

        done();
      });
    });

    it('ani progresses from 0 to 1', function( next ){
      var ani = n1.animation({
        style: { width: 200 },
        duration: 100
      });

      expect( ani.progress() ).to.equal(0);

      ani.play().promise().then(function(){
        expect( ani.progress() ).to.equal(1);

        next();
      });
    });

    it('ani.rewind() works', function( next ){
      var ani = n1.style({
        width: 100
      }).animation({
        style: { width: 200 },
        duration: 100
      });

      ani.play().promise().then(function(){
        expect( ani.progress() ).to.equal(1);
        expect( parseFloat(n1.style().width) ).to.equal(200);

        ani.rewind();

        expect( ani.progress() ).to.equal(0);

        next();
      });
    });

    it('ani.rewind() plays again from start', function( next ){
      var ani = n1.style({
        width: 100
      }).animation({
        style: { width: 200 },
        duration: 100
      });

      ani.play().promise().then(function(){
        expect( ani.progress() ).to.equal(1);
        expect( parseFloat(n1.style().width) ).to.equal(200);

        ani.rewind();

        expect( ani.progress() ).to.equal(0);

        return ani.play().promise();
      }).then(function(){
        expect( ani.progress() ).to.equal(1);
        expect( parseFloat(n1.style().width) ).to.equal(200);

        next();
      });
    });

    it('ani.reverse()', function(next){
      var ani = n1.style({
        width: 100
      }).animation({
        style: { width: 200 },
        duration: 100
      });

      ani.play().promise().then(function(){
        expect( ani.progress() ).to.equal(1);
        expect( parseFloat(n1.style().width) ).to.equal(200);

        ani.reverse();

        return ani.play().promise();
      }).then(function(){
        expect( ani.progress() ).to.equal(1);
        expect( parseFloat(n1.style().width) ).to.equal(100);

         next();
      });
    });

    it('ani.apply()', function(next){
      var ani = n1.style({
        width: 100
      }).animation({
        style: { width: 200 },
        duration: 100
      });

      ani.progress(0.5).apply().promise('frame').then(function(){
        expect( parseFloat(n1.style('width')) ).to.equal(150);

        next();
      });

    });

    it('ani.stop()', function( next ){
      var ani = n1.animation({
        style: { width: 200 },
        duration: 200
      });

      ani.play();

      setTimeout(function(){
        ani.stop().promise('frame').then(function(){
          expect( n1.animated() ).to.be.false;
          next();
        });
      }, 100);

    });

  });

});
