var ToolMan = {
	events : function() {
		if (!ToolMan._eventsFactory) throw "ToolMan Events module isn't loaded";
		return ToolMan._eventsFactory
	},

	css : function() {
		if (!ToolMan._cssFactory) throw "ToolMan CSS module isn't loaded";
		return ToolMan._cssFactory
	},

	coordinates : function() {
		if (!ToolMan._coordinatesFactory) throw "ToolMan Coordinates module isn't loaded";
		return ToolMan._coordinatesFactory
	},

	drag : function() {
		if (!ToolMan._dragFactory) throw "ToolMan Drag module isn't loaded";
		return ToolMan._dragFactory
	},

	dragsort : function() {
		if (!ToolMan._dragsortFactory) throw "ToolMan DragSort module isn't loaded";
		return ToolMan._dragsortFactory
	},

	helpers : function() {
		return ToolMan._helpers
	},

	cookies : function() {
		if (!ToolMan._cookieOven) throw "ToolMan Cookie module isn't loaded";
		return ToolMan._cookieOven
	},

	junkdrawer : function() {
		return ToolMan._junkdrawer
	}

}

ToolMan._helpers = {
	map : function(array, func) {
		for (var i = 0, n = array.length; i < n; i++) func(array[i])
	},

	nextItem : function(item, nodeName) {
		if (item == null) return
		var next = item.nextSibling
		while (next != null) {
			if (next.nodeName == nodeName) return next
			next = next.nextSibling
		}
		return null
	},

	previousItem : function(item, nodeName) {
		var previous = item.previousSibling
		while (previous != null) {
			if (previous.nodeName == nodeName) return previous
			previous = previous.previousSibling
		}
		return null
	},

	moveBefore : function(item1, item2) {
		var parent = item1.parentNode
		parent.removeChild(item1)
		parent.insertBefore(item1, item2)
	},

	moveAfter : function(item1, item2) {
		var parent = item1.parentNode
		parent.removeChild(item1)
		parent.insertBefore(item1, item2 ? item2.nextSibling : null)
	}
}

ToolMan._junkdrawer = {
	serializeList : function(list) {
		var items = list.getElementsByTagName("li")
		var array = new Array()
		for (var i = 0, n = items.length; i < n; i++) {
			var item = items[i]

			array.push(ToolMan.junkdrawer()._identifier(item))
		}
		return array.join('|')
	},

	inspectListOrder : function(id) {
		alert(ToolMan.junkdrawer().serializeList(document.getElementById(id)))
	},

	restoreListOrder : function(listID) {
		var list = document.getElementById(listID)
		if (list == null) return

		var cookie = ToolMan.cookies().get("list-" + listID)
		if (!cookie) return;

		var IDs = cookie.split('|')
		var items = ToolMan.junkdrawer()._itemsByID(list)

		for (var i = 0, n = IDs.length; i < n; i++) {
			var itemID = IDs[i]
			if (itemID in items) {
				var item = items[itemID]
				list.removeChild(item)
				list.insertBefore(item, null)
			}
		}
	},

	_identifier : function(item) {
		var trim = ToolMan.junkdrawer().trim
		var identifier

		identifier = trim(item.getAttribute("id"))
		if (identifier != null && identifier.length > 0) return identifier;
		
		identifier = trim(item.getAttribute("itemID"))
		if (identifier != null && identifier.length > 0) return identifier;
		
		// FIXME: strip out special chars or make this an MD5 hash or something
		return trim(item.innerHTML)
	},

	_itemsByID : function(list) {
		var array = new Array()
		var items = list.getElementsByTagName('li')
		for (var i = 0, n = items.length; i < n; i++) {
			var item = items[i]
			array[ToolMan.junkdrawer()._identifier(item)] = item
		}
		return array
	},

	trim : function(text) {
		if (text == null) return null
		return text.replace(/^(\s+)?(.*\S)(\s+)?$/, '$2')
	}
}


ToolMan._eventsFactory = {
	fix : function(event) {
		if (!event) event = window.event

		if (event.target) {
			if (event.target.nodeType == 3) event.target = event.target.parentNode
		} else if (event.srcElement) {
			event.target = event.srcElement
		}

		return event
	},

	register : function(element, type, func) {
		if (element.addEventListener) {
			element.addEventListener(type, func, false)
		} else if (element.attachEvent) {
			if (!element._listeners) element._listeners = new Array()
			if (!element._listeners[type]) element._listeners[type] = new Array()
			var workaroundFunc = function() {
				func.apply(element, new Array())
			}
			element._listeners[type][func] = workaroundFunc
			element.attachEvent('on' + type, workaroundFunc)
		}
	},

	unregister : function(element, type, func) {
		if (element.removeEventListener) {
			element.removeEventListener(type, func, false)
		} else if (element.detachEvent) {
			if (element._listeners 
					&& element._listeners[type] 
					&& element._listeners[type][func]) {

				element.detachEvent('on' + type, 
						element._listeners[type][func])
			}
		}
	}
}

ToolMan._cssFactory = {
	readStyle : function(element, property) {
		if (element.style[property]) {
			return element.style[property]
		} else if (element.currentStyle) {
			return element.currentStyle[property]
		} else if (document.defaultView && document.defaultView.getComputedStyle) {
			var style = document.defaultView.getComputedStyle(element, null)
			return style.getPropertyValue(property)
		} else {
			return null
		}
	}
}

ToolMan._coordinatesFactory = {

	create : function(x, y) {
		return new _ToolManCoordinate(this, x, y)
	},

	origin : function() {
		return this.create(0, 0)
	},

	topLeftPosition : function(element) {
		var left = parseInt(ToolMan.css().readStyle(element, "left"))
		var left = isNaN(left) ? 0 : left
		var top = parseInt(ToolMan.css().readStyle(element, "top"))
		var top = isNaN(top) ? 0 : top

		return this.create(left, top)
	},

	bottomRightPosition : function(element) {
		return this.topLeftPosition(element).plus(this._size(element))
	},

	topLeftOffset : function(element) {
		var offset = this._offset(element) 

		var parent = element.offsetParent
		while (parent) {
			offset = offset.plus(this._offset(parent))
			parent = parent.offsetParent
		}
		return offset
	},

	bottomRightOffset : function(element) {
		return this.topLeftOffset(element).plus(
				this.create(element.offsetWidth, element.offsetHeight))
	},

	scrollOffset : function() {
		if (window.pageXOffset) {
			return this.create(window.pageXOffset, window.pageYOffset)
		} else if (document.documentElement) {
			return this.create(
					document.body.scrollLeft + document.documentElement.scrollLeft, 
					document.body.scrollTop + document.documentElement.scrollTop)
		} else if (document.body.scrollLeft >= 0) {
			return this.create(document.body.scrollLeft, document.body.scrollTop)
		} else {
			return this.create(0, 0)
		}
	},

	clientSize : function() {
		if (window.innerHeight >= 0) {
			return this.create(window.innerWidth, window.innerHeight)
		} else if (document.documentElement) {
			return this.create(document.documentElement.clientWidth,
					document.documentElement.clientHeight)
		} else if (document.body.clientHeight >= 0) {
			return this.create(document.body.clientWidth,
					document.body.clientHeight)
		} else {
			return this.create(0, 0)
		}
	},

	mousePosition : function(event) {
		event = ToolMan.events().fix(event)
		return this.create(event.clientX, event.clientY)
	},

	mouseOffset : function(event) {
		event = ToolMan.events().fix(event)
		if (event.pageX >= 0 || event.pageX < 0) {
			return this.create(event.pageX, event.pageY)
		} else if (event.clientX >= 0 || event.clientX < 0) {
			return this.mousePosition(event).plus(this.scrollOffset())
		}
	},

	_size : function(element) {
		return this.create(element.offsetWidth, element.offsetHeight)
	},

	_offset : function(element) {
		return this.create(element.offsetLeft, element.offsetTop)
	}
}

function _ToolManCoordinate(factory, x, y) {
	this.factory = factory
	this.x = isNaN(x) ? 0 : x
	this.y = isNaN(y) ? 0 : y
}

_ToolManCoordinate.prototype = {
	toString : function() {
		return "(" + this.x + "," + this.y + ")"
	},

	plus : function(that) {
		return this.factory.create(this.x + that.x, this.y + that.y)
	},

	minus : function(that) {
		return this.factory.create(this.x - that.x, this.y - that.y)
	},

	min : function(that) {
		return this.factory.create(
				Math.min(this.x , that.x), Math.min(this.y , that.y))
	},

	max : function(that) {
		return this.factory.create(
				Math.max(this.x , that.x), Math.max(this.y , that.y))
	},

	constrainTo : function (one, two) {
		var min = one.min(two)
		var max = one.max(two)

		return this.max(min).min(max)
	},

	distance : function (that) {
		return Math.sqrt(Math.pow(this.x - that.x, 2) + Math.pow(this.y - that.y, 2))
	},

	reposition : function(element) {
		element.style["top"] = this.y + "px"
		element.style["left"] = this.x + "px"
	}
}

ToolMan._dragFactory = {
  createSimpleGroup : function(element, handle) {
    handle = handle ? handle : element
    var group = this.createGroup(element)
    group.setHandle(handle)
    group.transparentDrag()
    group.onTopWhileDragging()
    return group
  },

  createGroup : function(element) {
    var group = new _ToolManDragGroup(this, element)

    var position = ToolMan.css().readStyle(element, 'position')
    if (position == 'static') {
      element.style["position"] = 'relative'
    } else if (position == 'absolute') {
      /* for Safari 1.2 */
      ToolMan.coordinates().topLeftOffset(element).reposition(element)
    }

    group.register('draginit', this._showDragEventStatus)
    group.register('dragmove', this._showDragEventStatus)
    group.register('dragend', this._showDragEventStatus)

    return group
  },

  _showDragEventStatus : function(dragEvent) {
		fl_TopOffset = dragEvent.topLeftOffset.y - document.body.scrollTop;
		fl_LeftOffset = dragEvent.topLeftOffset.x - document.body.scrollLeft;
  },

  constraints : function() {
    return this._constraintFactory
  },

  _createEvent : function(type, event, group) {
    return new _ToolManDragEvent(type, event, group)
  }
}

function _ToolManDragGroup(factory, element) {
  this.factory = factory
  this.element = element
  this._handle = null
  this._thresholdDistance = 0
  this._transforms = new Array()
  this._listeners = new Array()
  this._listeners['draginit'] = new Array()
  this._listeners['dragstart'] = new Array()
  this._listeners['dragmove'] = new Array()
  this._listeners['dragend'] = new Array()
}

_ToolManDragGroup.prototype = {

  setHandle : function(handle) {
    var events = ToolMan.events()

    handle.toolManDragGroup = this
    events.register(handle, 'mousedown', this._dragInit)
    handle.onmousedown = function() { return false }

    if (this.element != handle)
      events.unregister(this.element, 'mousedown', this._dragInit)
  },

  register : function(type, func) {
    this._listeners[type].push(func)
  },

  addTransform : function(transformFunc) {
    this._transforms.push(transformFunc)
  },

  verticalOnly : function() {
    this.addTransform(this.factory.constraints().vertical())
  },

  horizontalOnly : function() {
    this.addTransform(this.factory.constraints().horizontal())
  },

  setThreshold : function(thresholdDistance) {
    this._thresholdDistance = thresholdDistance
  },

  transparentDrag : function(opacity) {
    var opacity = typeof(opacity) != "undefined" ? opacity : 0.75;
    var originalOpacity = ToolMan.css().readStyle(this.element, "opacity")

    this.register('dragstart', function(dragEvent) {
      var element = dragEvent.group.element
      element.style.opacity = opacity
      element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')'
    })
    this.register('dragend', function(dragEvent) {
      var element = dragEvent.group.element
      element.style.opacity = originalOpacity
      element.style.filter = 'alpha(opacity=100)'
    })
  },

  onTopWhileDragging : function(zIndex) {
    var zIndex = typeof(zIndex) != "undefined" ? zIndex : 100000;
    var originalZIndex = ToolMan.css().readStyle(this.element, "z-index")

    this.register('dragstart', function(dragEvent) {
      dragEvent.group.element.style.zIndex = zIndex
    })
    this.register('dragend', function(dragEvent) {
      dragEvent.group.element.style.zIndex = originalZIndex
    })
  },

  _dragInit : function(event) {
    event = ToolMan.events().fix(event)
    var group = document.toolManDragGroup = this.toolManDragGroup
    var dragEvent = group.factory._createEvent('draginit', event, group)

    group._isThresholdExceeded = false
    group._initialMouseOffset = dragEvent.mouseOffset
    group._grabOffset = dragEvent.mouseOffset.minus(dragEvent.topLeftOffset)
    ToolMan.events().register(document, 'mousemove', group._drag)
    document.onmousemove = function() { return false }
    ToolMan.events().register(document, 'mouseup', group._dragEnd)

    group._notifyListeners(dragEvent)
		
		fl_DraggingInProgress = true;
  },

  _drag : function(event) {
    event = ToolMan.events().fix(event)
    var coordinates = ToolMan.coordinates()
    var group = this.toolManDragGroup
    if (!group) return
    var dragEvent = group.factory._createEvent('dragmove', event, group)

    var newTopLeftOffset = dragEvent.mouseOffset.minus(group._grabOffset)

    if (!group._isThresholdExceeded) {
      var distance = 
          dragEvent.mouseOffset.distance(group._initialMouseOffset)
      if (distance < group._thresholdDistance) return
      group._isThresholdExceeded = true
      group._notifyListeners(
          group.factory._createEvent('dragstart', event, group))
    }

    for (i in group._transforms) {
      var transform = group._transforms[i]
      newTopLeftOffset = transform(newTopLeftOffset, dragEvent)
    }

    var dragDelta = newTopLeftOffset.minus(dragEvent.topLeftOffset)
    var newTopLeftPosition = dragEvent.topLeftPosition.plus(dragDelta)
    newTopLeftPosition.reposition(group.element)
    dragEvent.transformedMouseOffset = newTopLeftOffset.plus(group._grabOffset)

    group._notifyListeners(dragEvent)

    var errorDelta = newTopLeftOffset.minus(coordinates.topLeftOffset(group.element))
    if (errorDelta.x != 0 || errorDelta.y != 0) {
      coordinates.topLeftPosition(group.element).plus(errorDelta).reposition(group.element)
    }
  },

  _dragEnd : function(event) {
    event = ToolMan.events().fix(event)
    var group = this.toolManDragGroup
    var dragEvent = group.factory._createEvent('dragend', event, group)

    group._notifyListeners(dragEvent)

    this.toolManDragGroup = null
    ToolMan.events().unregister(document, 'mousemove', group._drag)
    document.onmousemove = null
    ToolMan.events().unregister(document, 'mouseup', group._dragEnd)

		// lets know that dragging process is over
		fl_DraggingInProgress = false;
		
		// try to save floating cart position
		dynamicContent = new sack();
		dynamicContent.requestFile = '/cart/floatingcartposition?left='+fl_LeftOffset+'&top='+fl_TopOffset;
		//dynamicContent.onCompletion = function(){ alert(dynamicContent.response) };
		dynamicContent.runAJAX();
		
	},

  _notifyListeners : function(dragEvent) {
    var listeners = this._listeners[dragEvent.type]
    for (i in listeners) {
      listeners[i](dragEvent)
    }
  }
}

function _ToolManDragEvent(type, event, group) {
  this.type = type
  this.group = group
  this.mousePosition = ToolMan.coordinates().mousePosition(event)
  this.mouseOffset = ToolMan.coordinates().mouseOffset(event)
  this.transformedMouseOffset = this.mouseOffset
  this.topLeftPosition = ToolMan.coordinates().topLeftPosition(group.element)
  this.topLeftOffset = ToolMan.coordinates().topLeftOffset(group.element)
}

_ToolManDragEvent.prototype = {
  toString : function() {
    return "mouse: " + this.mousePosition + this.mouseOffset + "    " +
        "xmouse: " + this.transformedMouseOffset + "    " +
        "left,top: " + this.topLeftPosition + this.topLeftOffset
  }
}

ToolMan._dragFactory._constraintFactory = {
  vertical : function() {
    return function(coordinate, dragEvent) {
      var x = dragEvent.topLeftOffset.x
      return coordinate.x != x
          ? coordinate.factory.create(x, coordinate.y) 
          : coordinate
    }
  },

  horizontal : function() {
    return function(coordinate, dragEvent) {
      var y = dragEvent.topLeftOffset.y
      return coordinate.y != y
          ? coordinate.factory.create(coordinate.x, y) 
          : coordinate
    }
  }
}


ToolMan._dragsortFactory = {
	makeSortable : function(item) {
		var group = ToolMan.drag().createSimpleGroup(item)

		group.register('dragstart', this._onDragStart)
		group.register('dragmove', this._onDragMove)
		group.register('dragend', this._onDragEnd)

		return group
	},

	makeListSortable : function(list) {
		var helpers = ToolMan.helpers()
		var coordinates = ToolMan.coordinates()
		var items = list.getElementsByTagName("li")

		helpers.map(items, function(item) {
			var dragGroup = dragsort.makeSortable(item)
			dragGroup.setThreshold(4)
			var min, max
			dragGroup.addTransform(function(coordinate, dragEvent) {
				return coordinate.constrainTo(min, max)
			})
			dragGroup.register('dragstart', function() {
				var items = list.getElementsByTagName("li")
				min = max = coordinates.topLeftOffset(items[0])
				for (var i = 1, n = items.length; i < n; i++) {
					var offset = coordinates.topLeftOffset(items[i])
					min = min.min(offset)
					max = max.max(offset)
				}
			})
		})
		for (var i = 1, n = arguments.length; i < n; i++)
			helpers.map(items, arguments[i])
	},

	_onDragStart : function(dragEvent) {
	},

	_onDragMove : function(dragEvent) {
		var helpers = ToolMan.helpers()
		var coordinates = ToolMan.coordinates()

		var item = dragEvent.group.element
		var xmouse = dragEvent.transformedMouseOffset
		var moveTo = null

		var previous = helpers.previousItem(item, item.nodeName)
		while (previous != null) {
			var bottomRight = coordinates.bottomRightOffset(previous)
			if (xmouse.y <= bottomRight.y && xmouse.x <= bottomRight.x) {
				moveTo = previous
			}
			previous = helpers.previousItem(previous, item.nodeName)
		}
		if (moveTo != null) {
			helpers.moveBefore(item, moveTo)
			return
		}

		var next = helpers.nextItem(item, item.nodeName)
		while (next != null) {
			var topLeft = coordinates.topLeftOffset(next)
			if (topLeft.y <= xmouse.y && topLeft.x <= xmouse.x) {
				moveTo = next
			}
			next = helpers.nextItem(next, item.nodeName)
		}
		if (moveTo != null) {
			helpers.moveBefore(item, helpers.nextItem(moveTo, item.nodeName))
			return
		}
	},

	_onDragEnd : function(dragEvent) {
		ToolMan.coordinates().create(0, 0).reposition(dragEvent.group.element)
	}
}

//
// FLOATING
//

var fl_oTop, fl_oLeft, fl_tTop, fl_tLeft, fl_tHeight, fl_tWidth, fl_tShow;
var fl_cHeight = 0;
var fl_cWidth = 0;
var fl_cart_closed = false;
var fl_LeftOffset = (!fl_LeftOffset) ? (3) : fl_LeftOffset;
var fl_TopOffset = (!fl_TopOffset) ? (3) : fl_TopOffset;
var fl_DraggingInProgress = false;

function fl_cartOpenClose()
{
	if( fl_cart_closed )
	{
		fl_cart_closed = false;
	}
	else
	{
		fl_cart_closed = true;
	}
}

function fl_getTop() 
{
	var _result = parseInt(document.getElementById('iMarketFloatingCart').style.top);
	return _result;
}
function fl_getLeft() 
{
	var _result = parseInt(document.getElementById('iMarketFloatingCart').style.left);
	return _result;
}

function fl_setTop(_value) 
{
	document.getElementById('iMarketFloatingCart').style.top = _value;
}
function fl_setLeft(_value) 
{
	document.getElementById('iMarketFloatingCart').style.left = _value;
}

function fl_floatRefresh() {
	if( fl_DraggingInProgress ) return;
	fl_getValues();
	fl_setTop(document.body.scrollTop + fl_TopOffset);
	fl_setLeft(document.body.scrollLeft + fl_LeftOffset);
}
function fl_getValues() 
{
	fl_cHeight = document.body.clientHeight;
	fl_cWidth = document.body.clientWidth;
	fl_tTop = document.getElementById('iMarketFloatingCart').style.top;
	fl_tLeft = document.getElementById('iMarketFloatingCart').style.left;
	fl_tHeight = document.getElementById('iMarketFloatingCart').offsetHeight;
	fl_tWidth = document.getElementById('iMarketFloatingCart').offsetWidth;
	fl_tbWidth = document.getElementById('iMarketFloatingCart').offsetWidth;
}

fl_getValues();
if( fl_cHeight && fl_cWidth ) 
{
	fl_setTop(document.body.scrollTop + fl_TopOffset);
	fl_setLeft(document.body.scrollLeft + fl_LeftOffset);
	setInterval("fl_floatRefresh()",5);
}

//
// CART
//

iMarketFloatingCart_maximize_img = new Image(13,13); iMarketFloatingCart_maximize_img.src = "/images/cart_maximize.gif";
iMarketFloatingCart_minimize_img = new Image(13,13); iMarketFloatingCart_minimize_img.src = "/images/cart_minimize.gif";
function iMarketFloatingCartMinimize()
{
	if( document.getElementById('iMarketFloatingCartBody').style.display == '' )
	{
		document.getElementById('iMarketFloatingCartBody').style.display = 'none';
		document.getElementById('iMarketFloatingCartMinimizeImg').src = iMarketFloatingCart_maximize_img.src;
	}
	else
	{
		document.getElementById('iMarketFloatingCartBody').style.display = '';
		document.getElementById('iMarketFloatingCartMinimizeImg').src = iMarketFloatingCart_minimize_img.src;
	}
}
var iMarketFloatingCartDrag = ToolMan.drag();
var iMarketFloatingCartHandle = document.getElementById("iMarketFloatingCart");
iMarketFloatingCartDrag.createSimpleGroup(iMarketFloatingCartHandle, document.getElementById("iMarketFloatingCartHandle"));
