/*
 * layer implementation
 * ====================
 * Author: Barak Ulmann
 * based on the DynLayer technology. learn more about the DynDuo and cross-browser dhtml in:
 * http://www.dansteinman.com/dynduo/
 * Last Updated: October 5th 2003
 * compatibility: IE5 and above, NS4 and above
 * description: create a layer object.
 * object supports the following methods:
 * 1. moveTo, moveBy - set layer's x,y position
 * 2. slideTo, slideBy - animated sliding along a straight line
 * 3. clipTo, clipBy - set layer's clip values
 * 4. wipeTo, wipeBy - animated clipping
 * 5. setOpacity - set layers' opacity in percentage (not NS4 compatible) - NEW feature
 * 6. fadeTo, fadeBy - animated fading - NEW feature
 * 7. slideToView - 'sticky' y-position causes layer scroll with page - NEW feature
 *
 * comments:
 * the Layer object leaves some of the DynLayer's methods untouched or only slightly changed.
 * the Layer object solves the layer onclick NS4 incompatibility.
 * the Layer object solves the NS6 nested layers wiping incompatibility (the inner
 * layer was not wipped when the outer layer is).
 *
 * -- not final --
 * needed to be tested with ns6.2
 */
 
// create a simple layer object
function Layer(
	id // layer's id as declared in the div tag
	,nestref //  parent layer reference - for ns4
	)
{
	this.id = id
	this.obj = id + 'Object'
	eval(this.obj + '=this')
	if (document.layers) {
		this.elm = nestref? eval('document.' + nestref + '.document.' + id): document.layers[id]
		this.css = this.elm
		this.doc = this.elm.document
		this.x = this.css.left
		this.y = this.css.top
		this.w = this.css.clip.width
		this.h = this.css.clip.height
	}
	else if (document.all || document.getElementById) {
		this.elm = document.all? document.all[id]: document.getElementById(id)
		this.css = this.elm.style
		this.doc = document
		this.x = this.elm.offsetLeft
		this.y = this.elm.offsetTop
		this.w = (browser.ie4)? this.css.pixelWidth: this.elm.offsetWidth
		this.h = (browser.ie4)? this.css.pixelHeight: this.elm.offsetHeight
	}
	if (browser.ns61 || browser.ns62) { // get nested divs - needed for clipping with NS6.1 and NS6.2
		this.layers = new Array()
		var nestedDivs = this.elm.getElementsByTagName('DIV') // get all nested Divs (recursively)
		for (var i = 0; i < nestedDivs.length; i++) {
			if (nestedDivs.item(i).parentNode.id == this.id) // get only child Divs
				this.layers[i] = new Layer(nestedDivs.item(i).id)
		}
	}
	this.event = this.elm
	if (browser.ns4) {
		this.event.captureEvents(Event.MOUSEDOWN)
		this.event.captureEvents(Event.MOUSEUP)
		this.event.captureEvents(Event.MOUSEMOVE)
		// the onclick is a property of the layers' document
		this.event.onclick = new Function('')
		this.event.onmousedown = function(e) {
				m = new Mouse(e)
				this.mouseX = m.x
				this.mouseY = m.y
			}
		this.event.onmouseup = function(e) {
				m = new Mouse(e)
				if (m.x == this.mouseX && m.y == this.mouseY)
					if (this.onclick) this.onclick(e)
			}
		this.event.watch('onclick',
			function(property,oldval,newval)
			{
				this.document.onclick = newval // works partially - works good only if layer contains no html
				return newval
			}
		)
	}
	this.opacity = 100
}

// set layer's visibility
function LayerShow()
{
	this.css.visibility = browser.ns4? 'show': 'visible'
}
function LayerHide()
{
	this.css.visibility = browser.ns4? 'hide': 'hidden'
}
Layer.prototype.hide = LayerHide
Layer.prototype.show = LayerShow

// check layer visibility
function LayerIsVisible()
{
	return this.css.visibility == (browser.ns4? 'show': 'visible')
}
Layer.prototype.isVisible = LayerIsVisible

// write into layer
function LayerWrite(html)
{
	if (browser.ns4) {
		this.doc.open()
		this.doc.write(html)
		this.doc.close()
	}
	else
		this.elm.innerHTML = html
}
Layer.prototype.write = LayerWrite

// set layer's event handler
function LayerSetEventHandler(eventName,handler)
{
	// check if handler is a string to be evaluated or a function object
	var func = typeof(handler) == 'function'? handler: new Function(handler)
	switch(eventName) {
	case 'onclick':
		browser.ns4? this.doc.onclick = func: this.event.onclick = func
		break
	case 'onmouseout':
		this.event.onmouseout = func
		break
	case 'onmouseover':
		this.event.onmouseover =  func
		break
	case 'onmousedown':
		if (browser.ns4) this.elm.captureEvents(Event.MOUSEDOWN)
		this.event.onmousedown = func
		break
	case 'onmouseup':
		if (browser.ns4) this.elm.captureEvents(Event.MOUSEUP)
		this.event.onmouseup = func
		break
	case 'onmousemove':
		if (browser.ns4) this.elm.captureEvents(Event.MOUSEMOVE)
		this.event.onmousemove = func
		break
	default: break
	}
	return this
}
Layer.prototype.setEventHandler = LayerSetEventHandler

// set layer's bg
function LayerSetBg(color)
{
	if (browser.ns4)
		this.css.bgColor = color
	else
		this.css.backgroundColor = color
}
Layer.prototype.setbg = LayerSetBg

// change layer's image's source
function LayerChangeImage(imgName,imgObj)
{
	this.doc.images[imgName].src = imgObj.src
}
Layer.prototype.changeImage = LayerChangeImage

// set layer's opacity in percentage not ns4 compatible
function LayerSetOpacity(prcnt)
{
	if (browser.ie && browser.version >= 5) {
		if (this.css.filter)
			this.css.filter = this.css.filter.replace('alpha(opacity=' + this.opacity + ')','alpha(opacity=' + prcnt + ')')
		else
			this.css.filter = 'alpha(opacity=' + prcnt + ')'
	}
	else if (browser.ns && browser.version >= 5)
		this.css.MozOpacity = prcnt/100
	else if (prcnt < 50)
		this.hide()
	else
		this.show()
	this.opacity = prcnt
}
Layer.prototype.setOpacity = LayerSetOpacity

// move methods:
// =============

// move layer to absolute position
function LayerMoveTo(x,y)
{
	if (x != null) {
		this.x = x
		if (browser.ns4) this.css.left = this.x
		else if (browser.ie) this.css.pixelLeft = this.x
		else if (browser.ns && browser.version >= 5) this.css.left = Math.floor(this.x) + 'px'
	}
	if (y != null) {
		this.y = y
		if (browser.ns4) this.css.top = this.y
		else if (browser.ie) this.css.pixelTop = this.y
		else if (browser.ns && browser.version >= 5) this.css.top = Math.floor(this.y) + 'px'
	}
}
// move layer to relative position
function LayerMoveBy(x,y)
{
	this.moveTo(this.x + x,this.y + y)
}
Layer.prototype.moveTo = LayerMoveTo
Layer.prototype.moveBy = LayerMoveBy

// clip method:
// ============

// init for ie and ns5
function DynLayerClipInit(clipTop,clipRight,clipBottom,clipLeft)
{
	if (browser.ie || browser.ns5) {
		if (arguments.length == 4) this.clipTo(clipTop,clipRight,clipBottom,clipLeft)
		else this.clipTo(0,this.w,this.h,0)
	}
}
// clip layer in absolute values
function DynLayerClipTo(t,r,b,l)
{
	if (t == null) t = this.clipValues('t')
	if (r == null) r = this.clipValues('r')
	if (b == null) b = this.clipValues('b')
	if (l == null) l = this.clipValues('l')
	if (browser.ns4) {
		this.css.clip.top = t
		this.css.clip.right = r
		this.css.clip.bottom = b
		this.css.clip.left = l
	}
	else if (browser.ie || browser.ns5) this.css.clip = "rect("+t+"px "+r+"px "+b+"px "+l+"px)"
}
// clip layer in relative values
function DynLayerClipBy(t,r,b,l)
{
	this.clipTo(this.clipValues('t')+t,this.clipValues('r')+r,this.clipValues('b')+b,this.clipValues('l')+l)
}
// get clip values
function DynLayerClipValues(which)
{
	if (browser.ie || browser.ns5)
		var clipv = this.css.clip.split("rect(")[1].split(")")[0].split("px")
	if (which == "t") return (browser.ns4)? this.css.clip.top : Number(clipv[0])
	if (which == "r") return (browser.ns4)? this.css.clip.right : Number(clipv[1])
	if (which == "b") return (browser.ns4)? this.css.clip.bottom : Number(clipv[2])
	if (which == "l") return (browser.ns4)? this.css.clip.left : Number(clipv[3])
}
Layer.prototype.clipInit = DynLayerClipInit
Layer.prototype.clipTo = DynLayerClipTo
Layer.prototype.clipBy = DynLayerClipBy
Layer.prototype.clipValues = DynLayerClipValues

// slide effect method:
// ====================

// slide to absolute position
function DynLayerSlideTo(endx,endy,inc,speed,fn) {
	if (endx==null) endx = this.x
	if (endy==null) endy = this.y
	var distx = endx-this.x
	var disty = endy-this.y
	this.slideStart(endx,endy,distx,disty,inc,speed,fn)
}
// slide to relative position
function DynLayerSlideBy(distx,disty,inc,speed,fn) {
	var endx = this.x + distx
	var endy = this.y + disty
	this.slideStart(endx,endy,distx,disty,inc,speed,fn)
}
function DynLayerSlideStart(endx,endy,distx,disty,inc,speed,fn) {
	if (this.slideActive) return
	if (!inc) inc = 10
	if (!speed) speed = 20
	var num = Math.sqrt(Math.pow(distx,2) + Math.pow(disty,2))/inc
	if (num==0) return
	var dx = distx/num
	var dy = disty/num
	if (!fn) fn = null
	this.slideActive = true
	this.slide(dx,dy,endx,endy,num,1,speed,fn)
}
function DynLayerSlide(dx,dy,endx,endy,num,i,speed,fn) {
	if (i++ < num) {
		this.moveBy(dx,dy)
		this.onSlide()
		if (this.slideActive)
			this.timeoutId = setTimeout(this.obj+".slide("+dx+","+dy+","+endx+","+endy+","+num+","+i+","+speed+",\""+fn+"\")",speed)
		else this.onSlideEnd()
	}
	else {
		this.slideActive = false
		this.moveTo(endx,endy)
		this.onSlide()
		this.onSlideEnd()
		eval(fn)
	}
}
function LayerSlideStop()
{
	if (!this.slideActive) return
	clearTimeout(this.timeoutId)
	this.slideActive = false
}
Layer.prototype.slideInit = new Function("")
Layer.prototype.slideTo = DynLayerSlideTo
Layer.prototype.slideBy = DynLayerSlideBy
Layer.prototype.slideStart = DynLayerSlideStart
Layer.prototype.slideStop = LayerSlideStop
Layer.prototype.slide = DynLayerSlide
Layer.prototype.onSlide = new Function("")
Layer.prototype.onSlideEnd = new Function("")

// wipe effect method:
// ===================

// wipe init
function DynLayerWipeInit(clipTop,clipRight,clipBottom,clipLeft)
{
	if (arguments.length==4) this.clipInit(clipTop,clipRight,clipBottom,clipLeft)
	else this.clipInit()
}
// wipe to absolute clip values
function DynLayerWipeTo(
	endt,endr,endb,endl // top, right, bottom, left final values
	,num		// number of iterations
	,timeval	// time interval for timeout - 30 by default
	,fn			// function string to be evaluated at wipe end
	)
{
	var distt = (endt != null)? endt - this.clipValues('t'): 0
	var distr = (endr != null)? endr - this.clipValues('r'): 0
	var distb = (endb != null)? endb - this.clipValues('b'): 0
	var distl = (endl != null)? endl - this.clipValues('l'): 0
	if (timeval == null) timeval = 30
	this.wipeStart(distt,distr,distb,distl,endt,endr,endb,endl,num,timeval,fn)
}
// wipe to relative clip values
function DynLayerWipeBy(distt,distr,distb,distl,num,speed,fn)
{
	this.wipeStart(distt,distr,distb,distl,distt+this.clipValues('t'),distr+this.clipValues('r'),distb+this.clipValues('b'),distl+this.clipValues('l'),num,speed,fn)
}
function DynLayerWipeStart(
	distt,distr,distb,distl // top, right, bottom, left distances
	,endt,endr,endb,endl	// -- " -- final values
	,num		// number of iterations
	,timeval	// time interval for timeout
	,fn			// function string to be evaluated at wipe end
	)
{
	if (this.wipeActive) return
	this.wipeActive = true
	this.timeoutId = 0
	this.iter = 0
	if (!fn) fn = null
	this.wipe(distt/num,distr/num,distb/num,distl/num,endt,endr,endb,endl,this.clipValues('t'),this.clipValues('r'),this.clipValues('b'),this.clipValues('l'),num,timeval,fn)
}
function DynLayerWipe(dt,dr,db,dl,endt,endr,endb,endl,st,sr,sb,sl,num,timeval,fn)
{
	if (!this.wipeActive) return
	var i
	if (this.iter++ < num) {
		i = this.iter
		if (browser.ns61 || browser.ns62) { // hide and show nested divs in each iteration for NS6.1 and NS6.2
			for(var j in this.layers) {
				this.layers[j].hide()
				this.layers[j].show()
			}
		}
		this.clipTo(st + i*dt, sr + i*dr, sb + i*db,sl + i*dl)
		this.timeoutId = setTimeout(this.obj+".wipe("+dt+","+dr+","+db+","+dl+","+endt+","+endr+","+endb+","+endl+","+st+","+sr+","+sb+","+sl+","+num+","+timeval+",\""+fn+"\")",timeval)
	}
	else {
		this.wipeActive = false
		this.iter = 0
		this.clipTo(endt,endr,endb,endl)
		eval(fn)
	}
}
function LayerWipeStop()
{
	if (!this.wipeActive) return
	clearTimeout(this.timeoutId)
	this.wipeActive = false
}
function LayerWipeContinue(
	endt,endr,endb,endl	// -- " -- final values
	,num		// number of iterations
	,timeval	// time interval for timeout
	,fn			// function string to be evaluated at wipe end
	)
{
	var distt = (endt != null)? endt - this.clipValues('t'): 0
	var distr = (endr != null)? endr - this.clipValues('r'): 0
	var distb = (endb != null)? endb - this.clipValues('b'): 0
	var distl = (endl != null)? endl - this.clipValues('l'): 0
	if (timeval == null) timeval = 30
	if (this.wipeActive) return
	this.wipeActive = true
	this.timeoutId = 0
	if (!fn) fn = null
	this.wipe(distt/num,distr/num,distb/num,distl/num,endt,endr,endb,endl,this.clipValues('t'),this.clipValues('r'),this.clipValues('b'),this.clipValues('l'),num,timeval,fn)
}
Layer.prototype.wipeInit = DynLayerWipeInit
Layer.prototype.wipeTo = DynLayerWipeTo
Layer.prototype.wipeBy = DynLayerWipeBy
Layer.prototype.wipeStart = DynLayerWipeStart
Layer.prototype.wipe = DynLayerWipe
Layer.prototype.wipeStop = LayerWipeStop
Layer.prototype.wipeContinue = LayerWipeContinue

// clipped slide effect method: (a combination of slide and wipe)
// ============================

// clipped slide to absolute position
function LayerClippedSlideTo(endx,endy,endt,endr,endb,endl,inc,speed,fn)
{
	if (endx == null) endx = this.x
	if (endy == null) endy = this.y
	var distx = endx - this.x
	var disty = endy - this.y
	var distt = (endt != null)? endt - this.clipValues('t'): 0
	var distr = (endr != null)? endr - this.clipValues('r'): 0
	var distb = (endb != null)? endb - this.clipValues('b'): 0
	var distl = (endl != null)? endl - this.clipValues('l'): 0
	this.clippedSlideStart(endx,endy,distx,disty,endt,endr,endb,endl,distt,distr,distb,distl,inc,speed,fn)
}

// clipped slide to relative position
function LayerClippedSlideBy(distx,disty,distt,distr,distb,distl,inc,speed,fn)
{
	var endx = this.x + distx
	var endy = this.y + disty
	var endt = distt + this.clipValues('t')
	var endr = distr + this.clipValues('r')
	var endb = distb + this.clipValues('b')
	var endl = distl + this.clipValues('l')
	this.clippedSlideStart(endx,endy,distx,disty,endt,endr,endb,endl,distt,distr,distb,distl,inc,speed,fn)
}

function LayerClippedSlideStart(endx,endy,distx,disty,endt,endr,endb,endl,distt,distr,distb,distl,inc,speed,fn)
{
	if (this.slideActive) return
	if (!inc) inc = 10
	if (!speed) speed = 20
	var num = Math.sqrt(Math.pow(distx,2) + Math.pow(disty,2))/inc
	if (num==0) return
	var dx = distx/num
	var dy = disty/num
	var dt = distt/num
	var dr = distr/num
	var db = distb/num
	var dl = distl/num
	if (!fn) fn = null
	this.slideActive = true
	this.clippedSlide(dx,dy,endx,endy,dt,dr,db,dl,endt,endr,endb,endl,num,1,speed,fn)
}
function LayerClippedSlide(dx,dy,endx,endy,dt,dr,db,dl,endt,endr,endb,endl,num,i,speed,fn)
{
	if (!this.slideActive) return
	if (i++ < num) {
		this.moveBy(dx,dy)
		if (browser.ns61 || browser.ns62) { // hide and show nested divs in each iteration for NS6.1 and NS6.2
			for(var j in this.layers) {
				this.layers[j].hide()
				this.layers[j].show()
			}
		}
		this.clipBy(dt,dr,db,dl)
		this.onSlide()
		if (this.slideActive)
			this.timeoutId = setTimeout(this.obj + '.clippedSlide('+dx+','+dy+','+endx+','+endy+','+dt+','+dr+','+db+','+dl+','+endt+','+endr+','+endb+','+endl+','+num+','+i+','+speed+',\''+fn+'\')',speed)
		else this.onSlideEnd()
	}
	else {
		this.slideActive = false
		this.moveTo(endx,endy)
		this.clipTo(endt,endr,endb,endl)
		this.onSlide()
		this.onSlideEnd()
		eval(fn)
	}
}
Layer.prototype.clippedSlideTo = LayerClippedSlideTo
Layer.prototype.clippedSlideBy = LayerClippedSlideBy
Layer.prototype.clippedSlideStart = LayerClippedSlideStart
Layer.prototype.clippedSlide = LayerClippedSlide

// fade effect method: (not ns4 compatible)
// ===================

// fade to absolute opacity percentage
function LayerFadeTo(
	prcnt		// opacity percentage - integer 0-100
	,num		// number of iterations
	,timeval	// time interval for timeout
	,fn			// function string to be evaluated at wipe end
	)
{
	if (LayerFadeTo.arguments.length < 2 || isNaN(prcnt) || isNaN(num) || prcnt < 0 || prcnt > 100)
		return
	var diff = prcnt - this.opacity
	if (timeval == null) timeval = 30
	this.fadeStart(diff,num,timeval,fn)
}
// fade to relative opacity percentage
function LayerFadeBy(diff,speed,timeval,fn)
{
	this.fadeStart(diff,num,timeval,fn)
}

function LayerFadeStart(
	diff 		// opacity difference
	,num		// number of iterations
	,timeval	// time interval for timeout
	,fn			// function string to be evaluated at wipe end
	)
{
	if (this.fadeActive) return
	this.fadeActive = true
	this.timeoutId = 0
	this.iter = 0
	if (!fn) fn = null
	this.fade(diff/num,this.opacity+diff,this.opacity,num,timeval,fn)
}
function LayerFade(dopac,endopac,stopac,num,timeval,fn)
{
	if (!this.fadeActive) return
	if (this.iter++ < num) {
		this.setOpacity(stopac + this.iter*dopac)
		this.timeoutId = setTimeout(this.obj + '.fade(' + dopac + ',' + endopac + ',' + stopac + ',' + num + ',' + timeval + ',"' + fn + '")',timeval)
	}
	else {
		this.fadeActive = false
		this.iter = 0
		this.setOpacity(endopac)
		eval(fn)
	}
}
function LayerFadeStop()
{
	if (!this.fadeActive) return
	clearTimeout(this.timeoutId)
	this.fadeActive = false
}
function LayerFadeContinue(
	endt,endr,endb,endl	// -- " -- final values
	,num		// number of iterations
	,timeval	// time interval for timeout
	,fn			// function string to be evaluated at wipe end
	)
{
	if (LayerFadeTo.arguments.length < 2 || isNaN(prcnt) || isNaN(num) || prcnt < 0 || prcnt > 100)
		return
	var diff = prcnt - this.opacity
	if (timeval == null) timeval = 30
	if (this.fadeActive) return
	this.fadeActive = true
	this.timeoutId = 0
	if (!fn) fn = null
	this.fade(diff/num,this.opacity+diff,this.opacity,num,timeval,fn)
}
Layer.prototype.fadeTo = LayerFadeTo
Layer.prototype.fadeBy = LayerFadeBy
Layer.prototype.fadeStart = LayerFadeStart
Layer.prototype.fade = LayerFade
Layer.prototype.fadeStop = LayerFadeStop
Layer.prototype.fadeContinue = LayerFadeContinue

// scroll to view method - layer's y position is 'sticky'
function LayerScrollToView(inc,speed,fn)
{
	if (!this.scrollActive)
		return
	var pageYOffset = browser.ie? document.body.scrollTop: window.pageYOffset
	var str = this.obj + '.scrollToView(' + 
		(inc? inc: 'null') + ',' + 
		(speed? speed: 'null') + ',' + 
		(fn? '"' + fn + '"': 'null') + ')'
	this.slideTo(null,pageYOffset + this.Yoffset,inc,speed,fn)
	this.onSlideEnd = new Function(str)
	if (browser.ns4 || browser.ns61 || browser.ns62)
		setTimeout(str,1000)
}
function LayerScrollToViewInit(inc,speed,fn)
{
	this.Yoffset = this.y
	this.scrollActive = true
	if (browser.ns4 || browser.ns61 || browser.ns62)
		this.scrollToView(inc,speed,fn)
	else {
		var str = this.obj + '.scrollToView(' + 
			(inc? inc: 'null') + ',' + 
			(speed? speed: 'null') + ',' + 
			(fn? '"' + fn + '"': 'null') + ')'
		window.onscroll = eventAppend(window.onscroll,str)
	}
}
function LayerScrollToViewStop()
{
	this.scrollActive = false
}
function LayerScrollToViewCont()
{
	this.Yoffset = this.y
	this.scrollActive = true
}
Layer.prototype.scrollToViewInit = LayerScrollToViewInit
Layer.prototype.scrollToView = LayerScrollToView
Layer.prototype.scrollToViewStop = LayerScrollToViewStop
Layer.prototype.scrollToViewCont = LayerScrollToViewCont

//======================================================================================
// should be in a separate file/object - event???
function eventAppend(eventHandler,handler,param)
{
	if (!eventHandler)
		return new Function(param,handler)
	var funcStr = eventHandler.toString()
	var p = funcStr.indexOf('{')+1
	var q = funcStr.lastIndexOf('}')-1
	funcStr = funcStr.substring(p,q) + ';' + handler
	return new Function(param,funcStr)
}