/*
 * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices.
 */

L.extend(L.DomEvent, {

	_msTouches: [],
	_msDocumentListener: false,

	// Provides a touch events wrapper for msPointer events.
	// Based on changes by veproza https://github.com/CloudMade/Leaflet/pull/1019

	addMsTouchListener: function (obj, type, handler, id) {

		switch (type) {
		case 'touchstart':
			return this.addMsTouchListenerStart(obj, type, handler, id);
		case 'touchend':
			return this.addMsTouchListenerEnd(obj, type, handler, id);
		case 'touchmove':
			return this.addMsTouchListenerMove(obj, type, handler, id);
		default:
			throw 'Unknown touch event type';
		}
	},

	addMsTouchListenerStart: function (obj, type, handler, id) {
		var pre = '_leaflet_',
		    touches = this._msTouches;

		var cb = function (e) {

			var alreadyInArray = false;
			for (var i = 0; i < touches.length; i++) {
				if (touches[i].pointerId === e.pointerId) {
					alreadyInArray = true;
					break;
				}
			}
			if (!alreadyInArray) {
				touches.push(e);
			}

			e.touches = touches.slice();
			e.changedTouches = [e];

			handler(e);
		};

		obj[pre + 'touchstart' + id] = cb;
		obj.addEventListener('MSPointerDown', cb, false);

		// need to also listen for end events to keep the _msTouches list accurate
		// this needs to be on the body and never go away
		if (!this._msDocumentListener) {
			var internalCb = function (e) {
				for (var i = 0; i < touches.length; i++) {
					if (touches[i].pointerId === e.pointerId) {
						touches.splice(i, 1);
						break;
					}
				}
			};
			//We listen on the documentElement as any drags that end by moving the touch off the screen get fired there
			document.documentElement.addEventListener('MSPointerUp', internalCb, false);
			document.documentElement.addEventListener('MSPointerCancel', internalCb, false);

			this._msDocumentListener = true;
		}

		return this;
	},

	addMsTouchListenerMove: function (obj, type, handler, id) {
		var pre = '_leaflet_',
		    touches = this._msTouches;

		function cb(e) {

			// don't fire touch moves when mouse isn't down
			if (e.pointerType === e.MSPOINTER_TYPE_MOUSE && e.buttons === 0) { return; }

			for (var i = 0; i < touches.length; i++) {
				if (touches[i].pointerId === e.pointerId) {
					touches[i] = e;
					break;
				}
			}

			e.touches = touches.slice();
			e.changedTouches = [e];

			handler(e);
		}

		obj[pre + 'touchmove' + id] = cb;
		obj.addEventListener('MSPointerMove', cb, false);

		return this;
	},

	addMsTouchListenerEnd: function (obj, type, handler, id) {
		var pre = '_leaflet_',
		    touches = this._msTouches;

		var cb = function (e) {
			for (var i = 0; i < touches.length; i++) {
				if (touches[i].pointerId === e.pointerId) {
					touches.splice(i, 1);
					break;
				}
			}

			e.touches = touches.slice();
			e.changedTouches = [e];

			handler(e);
		};

		obj[pre + 'touchend' + id] = cb;
		obj.addEventListener('MSPointerUp', cb, false);
		obj.addEventListener('MSPointerCancel', cb, false);

		return this;
	},

	removeMsTouchListener: function (obj, type, id) {
		var pre = '_leaflet_',
		    cb = obj[pre + type + id];

		switch (type) {
		case 'touchstart':
			obj.removeEventListener('MSPointerDown', cb, false);
			break;
		case 'touchmove':
			obj.removeEventListener('MSPointerMove', cb, false);
			break;
		case 'touchend':
			obj.removeEventListener('MSPointerUp', cb, false);
			obj.removeEventListener('MSPointerCancel', cb, false);
			break;
		}

		return this;
	}
});
