var ProgressBar = function(setPositionListener, setSegmentStartListener, setSegmentEndListener) {
	var ProgressBarPub = new Object();

	function pageOffset(elem) {
		var offset = new Object;
		offset.x = 0;
		offset.y = 0;
		// Add up the offsets from this element to the document body
		while (elem && elem.nodeName != 'BODY') {
			offset.x += elem.offsetLeft;
			offset.y += elem.offsetTop;
			elem = elem.offsetParent;
		}
		return offset;
	}

	// Setup HTML elements
	var jqBar = $('<div class="progress-bar disabled" tabindex="-1" />');
	var jqLoaded = $('<div class="progress-bar-loaded" />');
	var jqPlayed = $('<div class="progress-bar-played" />');
	var jqMarker = $('<div class="progress-bar-marker"  role="slider" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" aria-valuetext="0%" />');

	var jqSegment = $('<div />');
	var jqSegmentStart = $('<div></div>');
	var jqSegmentEnd = $('<div></div>');

	jqBar.append(jqSegment, jqSegmentStart, jqSegmentEnd, jqLoaded, jqPlayed, jqMarker);


	/* ========== CLASSES ========== */

	/* ---------- MovableMarker ----------
		jqMarker:	(required) [jQuery object]  marker element
		jqBar:		(required) [jQuery object]  bar element
		keepInside:	(optional: true) [true / false]  Keep the marker inside the bar (compensates for marker width)
		alignPoint:	(optional: 0.5) [0 - 1]  How to align the marker, 0 = left, 1 = right, 0.75 = slighty to the right, etc
	*/
	function MovableMarker(jqMarker, jqBar, keepInside, alignPoint) {
		var MovableMarkerPub = new Object();

		var keepInside = (keepInside != undefined) ? keepInside : true;
		var alignPoint = (typeof(alignPoint) == 'number') ? alignPoint : 0.5;
        var bDrag = false;
        
		MovableMarkerPub.repositionFunction = function(){};
		MovableMarkerPub.moveFunction = function(){};
		MovableMarkerPub.currentAmmount = 0;
		MovableMarkerPub.boundries = {"start": 0, "end": 1};
		var mouseBoundingBoxMargin = 150;
		var startAmmount = 0;
		MovableMarkerPub.enabled = false;

		function setMarkerPosition(ammount) {
			jqMarker.css("left", (ammount * 100) + "%");
			// Compensate for marker width
            jqMarker.attr("aria-valuenow", parseInt((ammount * 100)));
            jqMarker.attr("aria-valuetext", parseInt((ammount * 100)) +" percent");
			if (keepInside) {
				jqMarker.css("margin-left", -(jqMarker[0].offsetWidth * ammount) + "px");
			} else {
				jqMarker.css("margin-left", -(jqMarker[0].offsetWidth * alignPoint) + "px");
			}
            if(jqMarker==jqSegmentStart) {
                jqMarker.css("margin-left", -51 + "px");
            }


			MovableMarkerPub.moveFunction(ammount);
			MovableMarkerPub.currentAmmount = ammount;
		}

		function beginMarkerDrag(evt) {
            bDrag = true;
			if (MovableMarkerPub.enabled) {
				startAmmount = MovableMarkerPub.currentAmmount;

				var mouseOffsetMarkerX = evt.pageX - pageOffset(jqMarker[0]).x;
				// Stop IE Draggable/Selectable
				document.body.ondrag = function () { return false; };
				document.body.onselectstart = function () { return false; };

				function stopMarkerDrag(evt) {
                    bDrag = false;
                    
					$(document).unbind("mousemove", positionMarker);
					$(document).unbind("mouseup", stopMarkerDrag);
					$(document).unbind("mouseout", leftHTML);

					// Reset IE Draggable/Selectable
					document.body.ondrag = function () {};
					document.body.onselectstart = function () {};

					// Fire reposition Event
					MovableMarkerPub.repositionFunction(MovableMarkerPub.currentAmmount);
				}

				function resetMarker(evt) {
					setMarkerPosition(startAmmount)
				}

				function positionMarker(evt) {

					var xOffset = evt.pageX - pageOffset(jqBar[0]).x;
					var yOffset = evt.pageY - pageOffset(jqBar[0]).y;

					var barWidth = jqBar[0].clientWidth;
					var barHeight = jqBar[0].clientHeight;

					var markerPosition = xOffset / barWidth;
					var mouseCompensation = mouseOffsetMarkerX / barWidth;
					markerPosition -= mouseCompensation;

					var ammountMarker = 0;

					if (keepInside) {
						// Marker width compensation
						ammountMarker = (jqMarker[0].offsetWidth * markerPosition) / jqBar[0].clientWidth;
					} else {
						ammountMarker = (jqMarker[0].offsetWidth * alignPoint) / jqBar[0].clientWidth;
					}
						markerPosition += ammountMarker;

					if (markerPosition < MovableMarkerPub.boundries.start) {
						setMarkerPosition(MovableMarkerPub.boundries.start);
					} else if (markerPosition > MovableMarkerPub.boundries.end) {
						setMarkerPosition(MovableMarkerPub.boundries.end);
					} else {
						setMarkerPosition(markerPosition);
					}

					// Reset the marker position if the mouse moves outside of the bounding box
					if (xOffset < -mouseBoundingBoxMargin) {
						resetMarker(evt);
					}
					if (xOffset - barWidth > mouseBoundingBoxMargin) {
						resetMarker(evt);
					}
					if (yOffset < -mouseBoundingBoxMargin) {
						resetMarker(evt);
					}
					if (yOffset - barHeight > mouseBoundingBoxMargin) {
						resetMarker(evt);
					}
				}

				function leftHTML(evt) {
					// Get the element the mouse moved to (mouseover)
					var movedTo = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement;

					if (!movedTo || movedTo.nodeName == "HTML") {
						// Mouse moved out of document (no movedTo)
						resetMarker(evt)
						stopMarkerDrag(evt);
					}
				}

				$(document).bind("mouseup", stopMarkerDrag);
				$(document).bind("mousemove", positionMarker);
				$(document).bind("mouseout", leftHTML); // Ideally we wouldn't do this, but we can't detect mouseups outside the document (i.e. people would get a 'stuck' mouse button)

			}

			// Stop other onmousedown events
			return false;
		}

		// Marker movement
		jqMarker.bind("mousedown", beginMarkerDrag);

		setMarkerPosition(0);

		// Return
		MovableMarkerPub.setPosition =  function(ammount) {
            if (!bDrag) {
                setMarkerPosition(ammount);
            }
        };

		MovableMarkerPub.enable = function() {
			MovableMarkerPub.enabled = true;
		}
		MovableMarkerPub.disable = function() {
			MovableMarkerPub.enabled = false;
		}

		return MovableMarkerPub;
	}




	/* ========== FUNCTIONS ========== */

	// PRIVATE

	function setSegmentBlockStart(ammount) {
		jqSegment.css("left", (ammount * 100) + "%");
		setSegmentBlockEnd(segmentEndMarker.currentAmmount);
		segmentEndMarker.boundries.start = ammount;
	}

	function setSegmentBlockEnd(ammount) {
		jqSegment.css("width",  ((ammount - segmentStartMarker.currentAmmount) * 100) + "%");
		segmentStartMarker.boundries.end = ammount;
	}


	// PUBLIC

	ProgressBarPub.setPlayed = function(ammount) {
		jqPlayed.css("width", (ammount * 100) +"%");
		positionMarker.setPosition(ammount);
        
	}

	ProgressBarPub.setLoaded = function(ammount) {
		jqLoaded.css("width", (ammount * 100)+"%")
	}

	ProgressBarPub.setSegmentStart = function(ammount) {
			setSegmentBlockStart(ammount);
			segmentStartMarker.setPosition(ammount);
	}

	ProgressBarPub.setSegmentEnd = function(ammount) {
			setSegmentBlockEnd(ammount);
			segmentEndMarker.setPosition(ammount);
	}

	ProgressBarPub.enable = function() {
		jqBar.removeClass("disabled");
		positionMarker.enable();
		segmentStartMarker.enable();
		segmentEndMarker.enable();
	}

	ProgressBarPub.disable = function() {
		jqBar.addClass("disabled");
		positionMarker.disable();
		segmentStartMarker.disable();
		segmentEndMarker.disable();
	}


	/* ========== SETUP ========== */


	// Create position marker
	var positionMarker = new MovableMarker(jqMarker, jqBar);
	positionMarker.repositionFunction = setPositionListener;

	// Create segment markers
	var segmentStartMarker = new MovableMarker(jqSegmentStart, jqBar, false, 1);
	var segmentEndMarker = new MovableMarker(jqSegmentEnd, jqBar, false, 0);

	segmentStartMarker.moveFunction = setSegmentBlockStart;
	segmentEndMarker.moveFunction = setSegmentBlockEnd;

	segmentStartMarker.repositionFunction = setSegmentStartListener;
	segmentEndMarker.repositionFunction = setSegmentEndListener;


	// Jump to point on position marker
	jqBar.bind("mousedown", function(evt) {
		if (positionMarker.enabled) {
			var xOffset = evt.pageX - pageOffset(jqBar[0]).x;
			positionMarker.setPosition(xOffset / jqBar[0].clientWidth);

			// Fire reposition Event
			positionMarker.repositionFunction(positionMarker.currentAmmount);
		}
	});

	ProgressBarPub.element = jqBar[0];


	// Return
	return ProgressBarPub;
}
