describe("Dragging handles tests", function() {

	var testSlider;

	var mouseEventArguments;

    var tickOffsets;



    // Create mouse events

    function mouseEvent(type, offset) {

        var ev = document.createEvent("MouseEvents");

        mouseEventArguments[0] = type;

        mouseEventArguments[7] = offset;

        ev.initMouseEvent.apply(ev, mouseEventArguments);

        return ev;

    }



	beforeEach(function() {

		// Create slider

		testSlider = new Slider(document.getElementById("testSlider1"), {

			ticks: [0, 1, 2, 3, 4, 5, 6],

			value: [4, 5],

			step: 1,

			range: true,

		});

		// Set up default set of mouse event arguments

		mouseEventArguments = [

			'mousemove', // type

			true, // canBubble

			true, // cancelable

			document, // view,

			0, // detail

			0, // screenX

			0, // screenY

			undefined, // clientX

			testSlider.sliderElem.offsetTop, // clientY,

			false, // ctrlKey

			false, // altKey

			false, // shiftKey

			false, // metaKey,

			0, // button

			null // relatedTarget

		];

		// Calculate and store the 'clientX' for each tick in the slider

		tickOffsets = testSlider.ticks.map(function (tick) {

			return tick.offsetLeft + testSlider.sliderElem.offsetLeft;

		});

	});



	afterEach(function() {

		if(testSlider) {

			if(testSlider instanceof Slider) { testSlider.destroy(); }

			testSlider = null;

		}

	});



	describe("Dragging handles over each other", function() {

		it("should swap reliably given imprecision", function() {

			// Create mouse event with position to the left of problem tick

			var mouseLeft = document.createEvent('MouseEvents');

			mouseEventArguments[7] = tickOffsets[4]; // clientX

			mouseLeft.initMouseEvent.apply(mouseLeft, mouseEventArguments);

			// Create mouse event with position on problem tick

			var mouseOverlap = document.createEvent('MouseEvents');

			mouseEventArguments[7] = tickOffsets[5]; // clientX

			mouseOverlap.initMouseEvent.apply(mouseOverlap, mouseEventArguments);

			// Create mouse event with position to the right of problem tick

			var mouseRight = document.createEvent('MouseEvents');

			mouseEventArguments[7] = tickOffsets[6]; // clientX

			mouseRight.initMouseEvent.apply(mouseRight, mouseEventArguments);

			// Same offset as 'mouseLeft'

			var mouseUp = document.createEvent('MouseEvents');

			mouseEventArguments[7] = testSlider.ticks[4].offsetLeft + testSlider.sliderElem.offsetLeft; // clientX

			mouseUp.initMouseEvent.apply(mouseUp, mouseEventArguments);

			// Simulate drag without swapping

			testSlider.mousedown(mouseLeft);

			expect(testSlider._state.dragged).toBe(0);

			expect(testSlider.getValue()).toEqual([4, 5]);

			// Simulate handle overlap

			testSlider.mousemove(mouseOverlap);

			expect(testSlider._state.dragged).toBe(0);

			expect(testSlider.getValue()).toEqual([5, 5]);

			// Simulate left over right drag with imprecision in reported percentage

			testSlider.mousemove(mouseRight);

			expect(testSlider._state.dragged).toBe(1);

			expect(testSlider.getValue()).toEqual([5, 6]);

			// Simulate handle overlap

			testSlider.mousemove(mouseOverlap);

			expect(testSlider._state.dragged).toBe(1);

			expect(testSlider.getValue()).toEqual([5, 5]);

			// Simulator handle overlap with click

			testSlider.mousemove(mouseOverlap);

			testSlider.mousedown(mouseLeft);

			expect(testSlider._state.dragged).toBe(0);

			expect(testSlider.getValue()).toEqual([4, 5]);

			// Simulate right over left drag with imprecision in reported percentage

			testSlider.mousemove(mouseLeft);

			expect(testSlider._state.dragged).toBe(0);

			expect(testSlider.getValue()).toEqual([4, 5]);

			// End with mouse up

			testSlider.mouseup(mouseUp);

			expect(testSlider._state.dragged).toBeNull();

			expect(testSlider.getValue()).toEqual([4, 5]);

		});

	});



	describe("Drag handles over each other and use keyboard to move handles over each other", function() {

		var keyboardEvent;



		function createMouseEvent(type, tickIdx) {

			var mouseEvent = document.createEvent('MouseEvent');

			mouseEventArguments[0] = type;

			mouseEventArguments[7] = tickOffsets[tickIdx];

			mouseEvent.initMouseEvent.apply(mouseEvent, mouseEventArguments);

			return mouseEvent;

		}



		beforeEach(function() {

			// Create keyboard event

			keyboardEvent = document.createEvent('Event');

			keyboardEvent.initEvent('keydown', true, true);

		});



		afterEach(function() {

			keyboardEvent = null;

		});



		it("should drag and keydown handles properly to the right then back to the left", function() {

			// Simulate drag without swapping

			testSlider.mousedown(createMouseEvent('mousedown', 4));

			expect(testSlider._state.dragged).toBe(0);

			expect(testSlider.getValue()).toEqual([4, 5]);



			// Simulate handle overlap

			testSlider.mousemove(createMouseEvent('mousemove', 5));

			expect(testSlider._state.dragged).toBe(0);

			expect(testSlider.getValue()).toEqual([5, 5]);



			// Simulate left over right drag

			testSlider.mousemove(createMouseEvent('mousemove', 6));

			expect(testSlider._state.dragged).toBe(1);

			expect(testSlider.getValue()).toEqual([5, 6]);



			// End with mouse up

			testSlider.mouseup(createMouseEvent('mouseup', 6));

			expect(testSlider._state.dragged).toBeNull();

			expect(testSlider.getValue()).toEqual([5, 6]);



			// Now move the handles past each other with the Left arrow key

			keyboardEvent.keyCode = keyboardEvent.which = 37;



			// Move handle2 to the left with keyboard

			testSlider.handle2Keydown(keyboardEvent);

			expect(testSlider._state.keyCtrl).toBeUndefined();

			expect(testSlider.getValue()).toEqual([5, 5]);



			// Move handle2 to the left again

			testSlider.handle2Keydown(keyboardEvent);

			expect(testSlider._state.keyCtrl).toBeUndefined();

			expect(testSlider.getValue()).toEqual([4, 5]);

		});



		it("should drag and keydown handles properly to the left then back to the right", function() {

			// Simulate drag without swapping

			testSlider.mousedown(createMouseEvent('mousedown', 5));

			expect(testSlider._state.dragged).toBe(1);

			expect(testSlider.getValue()).toEqual([4, 5]);



			// Simulate handle overlap

			testSlider.mousemove(createMouseEvent('mousemove', 4));

			expect(testSlider._state.dragged).toBe(1);

			expect(testSlider.getValue()).toEqual([4, 4]);



			// Simulate left over right drag

			testSlider.mousemove(createMouseEvent('mousemove', 3));

			expect(testSlider._state.dragged).toBe(0);

			expect(testSlider.getValue()).toEqual([3, 4]);



			// End with mouse up

			testSlider.mouseup(createMouseEvent('mouseup', 3));

			expect(testSlider._state.dragged).toBeNull();

			expect(testSlider.getValue()).toEqual([3, 4]);



			// Now move the handles past each other with the Right arrow key

			keyboardEvent.keyCode = keyboardEvent.which = 39;



			// Move handle1 to the right with keyboard

			testSlider.handle1Keydown(keyboardEvent);

			expect(testSlider._state.keyCtrl).toBeUndefined();

			expect(testSlider.getValue()).toEqual([4, 4]);



			// Move handle1 to the right again

			testSlider.handle1Keydown(keyboardEvent);

			expect(testSlider._state.keyCtrl).toBeUndefined();

			expect(testSlider.getValue()).toEqual([4, 5]);

		});

    });



    it("Should snap to a tick within tick bounds when using the mouse navigation", function() {



        testSlider.setAttribute('range', true);

        testSlider.setAttribute('ticks_snap_bounds', 0.45);

        testSlider.setAttribute('step', 0.1);

        testSlider.refresh();



		// Create mouse events

        var mouseDown = document.createEvent("MouseEvents");

        mouseEventArguments[7] = tickOffsets[1];

        mouseDown.initMouseEvent.apply(mouseDown, mouseEventArguments);



        var mouseRight = document.createEvent("MouseEvents");

        mouseEventArguments[7] = tickOffsets[2] - 2;

        mouseRight.initMouseEvent.apply(mouseRight, mouseEventArguments);



        testSlider.mousedown(mouseDown);

		expect(testSlider.getValue()).toEqual([0.7, 5]);



        testSlider.mousemove(mouseRight);

        expect(testSlider.getValue()).toEqual([2, 5]);



		// FIXME: Use 'mouseup' event type

        // End with mouse up

        testSlider.mouseup(mouseRight);

        expect(testSlider.getValue()).toEqual([2, 5]);

    });



    it("Should trigger change on mouseup", function(done) {

        var changes = 0;



        testSlider.on('slideStop', function(){

            expect(changes).toBe(1);

			expect(testSlider.getValue()).toEqual([2, 5]);

			done();

        });



        testSlider.mousedown(mouseEvent('mousedown', tickOffsets[1]));

        expect(testSlider.getValue()).toEqual([1, 5]);



        testSlider.on('change', function(){

            changes++;

        });



        testSlider.mouseup(mouseEvent('mouseup', tickOffsets[2]));

	});



	describe("Test 'mousemove' and 'mouseup' produces correct results", function() {

		var $mySlider;

		var $handle1;



		function arraysEqual(a, b) {

			if (a === b) { return true; }

			if (a == null || b == null) { return false; }

			if (a.length !== b.length) { return false; }



			for (var i = 0; i < a.length; ++i) {

				if (a[i] !== b[i]) { return false; }

			}

			return true;

		}



		it("Last value changed in 'change' event should equal 'mouseup' event value for slider", function(done) {

			// Change attributes for 'testSlider'

			testSlider.setAttribute('value', 3);

			testSlider.setAttribute('range', false);

			testSlider.refresh();



			$mySlider = $('#testSlider1');



			function createMouseEvent(type, tickIdx) {

				var mouseEvent = document.createEvent('MouseEvent');

				mouseEventArguments[0] = type;

				mouseEventArguments[7] = tickOffsets[tickIdx];

				mouseEvent.initMouseEvent.apply(mouseEvent, mouseEventArguments);

				return mouseEvent;

			}



			var lastValue = 99;  // Dummy value

			$mySlider.on('change', function(eventData) {

				lastValue = eventData.value.newValue;

			});



			$mySlider.on('slideStop', function(eventData) {

				var value = eventData.value;

				var isEqual = Array.isArray(value) ? arraysEqual(lastValue, value) : value === lastValue;

				expect(isEqual).toBe(true);

				done();

			});



			// Simulate drag and release from tick[1] to tick[4]

			$handle1 = testSlider.$sliderElem.find('.slider-handle:first');

			$handle1[0].dispatchEvent(createMouseEvent('mousedown', 1));

			$handle1[0].dispatchEvent(createMouseEvent('mousemove', 4));

			$handle1[0].dispatchEvent(createMouseEvent('mouseup', 4));

		});

	});

});

