function api_obj(id) {
	this.doc = document;
	this.cont = this.doc
	this.obj = document.getElementById(id)
	if (this.obj != null) {
		this.css = document.getElementById(id).style
		this.obj_v = this.css.visibility
		if (this.obj_v == "") this.obj_v = "inherit"
		this.obj_d = this.css.display
		if (this.obj_d == "") this.obj_d = "block"
		this.obj_z = this.css.zIndex
		if (this.obj_z == "") this.obj_z = 0
		this.obj_x = parseInt(this.obj.offsetLeft)
		this.obj_y = parseInt(this.obj.offsetTop)		
		this.obj_w = parseInt(this.obj.offsetWidth)
		this.obj_h = parseInt(this.obj.offsetHeight)
		this.obj_c = 0
		if (this.css.clip) {
			this.obj_c = this.css.clip
			this.obj_c = this.obj_c.slice(5,this.obj_c.length-1)
			this.obj_c = this.obj_c.split(' ')
			for (var i = 0; i < 4; i++) {
				this.obj_c[i] = parseInt(this.obj_c[i])
			}
			this.obj_ct = parseFloat(this.obj_c[0])
			this.obj_cr = parseFloat(this.obj_c[1])
			this.obj_cb = parseFloat(this.obj_c[2])
			this.obj_cl = parseFloat(this.obj_c[3])
			this.obj_cw = this.obj_cr - this.obj_cl
			this.obj_ch = this.obj_cb - this.obj_ct
		}
		if (bw.ns) {
			this.colVal = this.css.backgroundColor.slice(4,-1).split(',')
			if (this.colVal.length == 0) this.obj_rr = this.obj_gg = this.obj_bb = "ff"
			else this.obj_rr = setColTriplet2Hex(this.colVal[0]).hex; this.obj_gg = setColTriplet2Hex(this.colVal[1]).hex; this.obj_bb = setColTriplet2Hex(this.colVal[2]).hex
		} else if (bw.ie) {
			this.colVal = this.css.backgroundColor.slice(1,7)
			if (this.colVal == "") this.obj_rr = this.obj_gg = this.obj_bb = "ff"
			else this.obj_rr = this.colVal.substr(0,2); this.obj_gg = this.colVal.substr(2,2); this.obj_bb = this.colVal.substr(4,2)    
		}
		this.obj_noDragDrop()
		this.ref = "ref"+ id + "Object"; eval(this.ref + "=this")
		this.css.cursor = "auto"
		return this
	}
}

// make a new absolute positioned item and return api_obj
var lyrID = new Array()
function api_obj_new(id,bgc,bgi,w,h,v,x,y,z,str,p) {
	if (!lyrID[id]) {
		var div = document.createElement("div")
			div.id = id
			div.style.position = 'absolute'
			div.style.overflow = 'hidden'
			if (bgc) div.style.backgroundColor = "#" + bgc
			if (bgi) div.style.backgroundImage = bgi
			div.style.top = y + 'px'
			div.style.left = x + 'px'
			div.style.width = w + 'px'
			div.style.height = h + 'px'
			if (v) div.style.visibility = v
			div.style.clip = "rect(0px," + w + "px," + h + "px,0px)"
			div.style.zIndex = z
			if (str) div.innerHTML = str  
			if (!p) document.body.appendChild(div)
			else p.obj.appendChild(div)
    }
	lyrID[id] = new api_obj(id)
	return lyrID[id]
}

// replace layer content
api_obj.prototype.obj_aniWrite = function(HTMLstr,time,chk) {
    if (!chk) {
		this.chrCnt = -1
		this.toWrite = ""
		this.finish = false
    }
    if (this.chrCnt++ <= HTMLstr.length) {
  	  // write html without pausing
		if (HTMLstr.charAt(this.chrCnt) == "<") {
    		while (HTMLstr.charAt(this.chrCnt) != ">") {
				this.toWrite += HTMLstr.charAt(this.chrCnt)
				this.chrCnt++
            }
    	}
		this.toWrite += HTMLstr.charAt(this.chrCnt)
		this.obj_write(this.toWrite)
		setTimeout(this.ref+".obj_aniWrite('" + HTMLstr + "'," + time + ",1)",time)
    } else {
		this.chrCnt = -1
		this.toWrite = ""
		this.finish = true
    }
	return this
}

// write text to a layer
api_obj.prototype.obj_write = function(str) {
	this.obj.innerHTML = str
}

// move object to
api_obj.prototype.obj_moveTo = function(x,y) {
	this.obj_x = parseInt(this.css.left = x + px); this.obj_y = parseInt(this.css.top = y + px)
}

// move object by
api_obj.prototype.obj_moveBy = function(x,y) {
	this.obj_x = this.css.left = parseInt(this.obj_x) + x + px; this.obj_y = this.css.top = parseInt(this.obj_y) + y + px
}

// move object by animation
api_obj.prototype.obj_aniMove = function(x,y,steps,time,chk) {
    if (!chk) {
		this.mvCnt = 1
		this.stpx = Math.round(x / steps); this.stpy = Math.round(y / steps)
    }
    if (this.mvCnt++ <= steps) {
		if (this.stpx > x) this.stpx = x
		if (this.stpy > y) this.stpy = y 
		this.obj_moveBy(this.stpx,this.stpy)
		setTimeout(this.ref+".obj_aniMove(" + x + "," + y + "," + steps + "," + time + ",1)",time)
    }
}

// set object visibility
api_obj.prototype.obj_visibility = function(v) {
	this.css.visibility = v; this.obj_v = v
}

// set object display
api_obj.prototype.obj_display = function(d) {
	this.css.display = d; this.obj_d = d
}

// set object z-index
api_obj.prototype.obj_zIndex = function(z) {
	this.css.zIndex = z; this.obj_z = z
}

// clip object to
api_obj.prototype.obj_clipTo = function(t,r,b,l) { 
	this.obj_ct = t; this.obj_cr = r; this.obj_cb = b; this.obj_cl = l
	if (t < 0) t = 0; if (r < 0) r = 0; if (b < 0) b = 0; if (l < 0) l = 0
	this.css.clip = "rect(" + t + "," + r + "," + b + "," + l + ")"
	this.css.pixelWidth = this.css.width = r; this.css.pixelHeight = this.css.height = b
}

// clipping object by 
api_obj.prototype.obj_clipBy = function(t,r,b,l) { 
	this.obj_clipTo(this.obj_ct + t,this.obj_cr + r,this.obj_cb + b,this.obj_cl + l)
}

// clipping object by animation
api_obj.prototype.obj_aniClip = function(t,r,b,l,steps,time,chk) {
    if (!chk) {
		this.clpCnt = 1
		this.stpt = Math.round(t / steps); this.stpr = Math.round(r / steps); this.stpb = Math.round(b / steps); this.stpl = Math.round(l / steps)
    }
    if (this.clpCnt++ <= steps) {
		if (this.stpt > t) this.stpt = t; if (this.stpr > r) this.stpr = r; if (this.stpb > b) this.stpb = b; if (this.stpl > l) this.stpl = l
		this.obj_clipBy(this.stpt,this.stpr,this.stpb,this.stpl)
		setTimeout(this.ref+".obj_aniClip(" + t + "," + r + "," + b + "," + l + "," + steps + "," + time + ",1)",time)
    }
}

// Function to make object move in a circle or ellipse. Make into full curve function
// angX - the angle of the X axis - to be implemented
// angY - the angle of the Y axis - to be implemented
// radX - The radius of the circle x
// radY - The radius of the circle y - make the same as radX to make circle
// a - The angle on a circle to start the animation at. Full circle is 360 degrees, start from anywhere on circle. 
// enda - The angle on a circle to end the circle animation at. Full circle is 360 degrees, add more than 360 for extra revolutions, less than to not complete circle. Use minus numbers here and with 'ainc' to change direction to clockwise
// xc - The center of the circle position on an x axis. Can use position by/to function as argument to set this value.
// yc - The center of the circle position on a y axis. Can use position by/to function as argument to set this value.
// ainc - The number of degrees on the circle to move with each timeout. Use smaller amounts for smoother but slower animation. Use minus numbers here and with 'ainc' to change direction to clockwise
// time - The setTimeout time
// NB: If you use minus numbers on either 'a' or 'ainc' and a positive integer on the other the object will travel infinitely.
api_obj.prototype.obj_circle = function(angX,angY,radX,radY,a,enda,xc,yc,ainc,time) {
    if ((Math.abs(ainc) < Math.abs(enda-a))) {
      a += ainc
      var x = xc + radX * Math.cos(a * Math.PI/180)
      var y = yc - radY * Math.sin(a * Math.PI/180)
      this.obj_moveTo(x,y)
      setTimeout(this.ref+".obj_circle(" + angX + "," + angY + "," + radX + "," + radY + "," + a + "," + enda + "," + xc + "," + yc + "," + ainc + "," + time + ")",time)
    }
}

// change object background colour
api_obj.prototype.obj_bgcolor = function(rr,gg,bb) {
	this.css.backgroundColor = rr + gg + bb
	this.obj_rr = rr; this.obj_gg = gg; this.obj_bb = bb
}

// convert 16 bit colour value to hexadecimal
var hexChars = "0123456789ABCDEF"
function setColTriplet2Hex(trplt) {
	this.a = trplt % 16
	this.b = (trplt - this.a) / 16
	this.hex = "" + hexChars.charAt(this.b) + hexChars.charAt(this.a)
	return this
}

// convert denary to binary
function setColDec2Bin(dec,chk) {
    if (!chk) this.rvbin = "", this.bin = "";
    if ((dec / 2) > 0) {
		this.decRm = (dec / 2) + ""
			if (this.decRm.indexOf('.') != -1) this.rvbin += "1"
			else this.rvbin += "0"
  		setColDec2Bin(Math.floor(this.decRm),1)
    } else {
        for (var i = this.rvbin.length - 1; i >= 0; i--) {
			this.bin += this.rvbin[i]
        }
    }
	return this
}

// animated object background colour change
api_obj.prototype.obj_aniBgcolor = function(rr,gg,bb,steps,time,chk) {
    if (!chk) {
		this.colCnt = 1
		this.rr_end = rr; this.gg_end = gg; this.bb_end = bb
		this.rr_end_dec = parseInt(rr,'16'); this.gg_end_dec = parseInt(gg,'16'); this.bb_end_dec = parseInt(bb,'16')
	}
	if (this.colCnt++ < steps) {
		this.rr_dec = parseInt(this.obj_rr,'16')	  
		this.rr_inc = ((this.rr_end_dec - this.rr_dec) / (steps - 4)) * -1
		this.rr_dec -= this.rr_inc
		this.rr_hex = setColTriplet2Hex(this.rr_dec).hex
		this.gg_dec = parseInt(this.obj_gg,'16')
		this.gg_inc = ((this.gg_end_dec - this.gg_dec) / (steps - 4)) * -1
		this.gg_dec -= this.gg_inc
		this.gg_hex = setColTriplet2Hex(this.gg_dec).hex
		this.bb_dec = parseInt(this.obj_bb,'16')
		this.bb_inc = ((this.bb_end_dec - this.bb_dec) / (steps - 4)) * -1
		this.bb_dec -= this.bb_inc
		this.bb_hex = setColTriplet2Hex(this.bb_dec).hex
		this.obj_bgcolor(this.rr_hex,this.gg_hex,this.bb_hex)
		setTimeout(this.ref+".obj_aniBgcolor('" + this.rr_hex + "','" + this.gg_hex + "','" + this.bb_hex + "'," + steps + "," + time + ",1)",time)
    } else this.obj_bgcolor(this.rr_end,this.gg_end,this.bb_end)
}

// drag drop functions - not finished for nested drag and drops
var dd_obj = 0, dd_msObj = 0, dd_z = 100;
api_obj.prototype.obj_ddActivate = function() {
	this.dd = 1
	obj_addEvent(this.cont, 'mousemove', obj_ddMove, true)
	obj_addEvent(this.cont, 'mousedown', obj_ddDown, true)
	obj_addEvent(this.cont, 'mouseup', obj_ddUp, true)
}

api_obj.prototype.obj_dragDrop = function() {
	if (!this.dd) this.obj_ddActivate()
	obj_addEvent(this.obj, 'mouseover', this.obj_ddOverEvt, true)
	this.obj.onmouseover = new Function("obj_ddOverObj(" + this.ref + ")")
	this.obj.onmouseout = new Function("dd_msObj = 0")
}

api_obj.prototype.obj_ddOverEvt = function(e) {
    if (bw.ie) e.cancelBubble = true
	// else e.stopPropagation()
}

api_obj.prototype.obj_noDragDrop = function() {
	obj_removeEvent(this.obj,'mouseout')
	obj_removeEvent(this.obj,'mouseover')
	this.css.cursor = "auto"
	dd_obj = 0
	dd_msObj = 0
	this.dd = 0
}

// functions to make an object move along a bezier curve
coord = function(x,y) { 
	if(!x) var x = 0
	if(!y) var y = 0
	return {x : x, y : y}
}
	
B1 = function(t) { return (t*t*t) }
B2 = function(t) { return (3*t*t*(1-t)) } 
B3 = function(t) { return (3*t*(1-t)*(1-t)) }
B4 = function(t) { return ((1-t)*(1-t)*(1-t)) }

function getBezier(percent,C1,C2,C3,C4) {
	var pos = new coord()
		pos.x = C1.x * B1(percent) + C2.x * B2(percent) + C3.x * B3(percent) + C4.x * B4(percent)
		pos.y = C1.y * B1(percent) + C2.y * B2(percent) + C3.y * B3(percent) + C4.y * B4(percent)
	return pos
}

api_obj.prototype.obj_curve = function(splinex1,spliney1,splinex2,spliney2,splinex3,spliney3,splinex4,spliney4,time,chk) {
	if (!chk) {
		// change direction of motion at each end of the curve
		this.stage = 0
		this.dir = 0
		// Control Points
		this.P1 = coord(splinex1,spliney1)
		this.P2 = coord(splinex2,spliney2)
		this.P3 = coord(splinex3,spliney3)
		this.P4 = coord(splinex4,spliney4)
	}
	if (this.stage >= 1) this.dir = 1
	//if (this.stage < 0) this.dir = 0
		
	// increment to next step
	if (this.dir == 0) {
		this.stage += 0.01
		//turn round and go back
		//else this.stage -= 0.01	
		// find position on bezier curve
		this.curpos = getBezier(this.stage,this.P1,this.P2,this.P3,this.P4)
		this.obj_moveTo(this.curpos.x,this.curpos.y)
			setTimeout(this.ref+".obj_curve('','','','','','','',''," + time + ",1)",time)
    }
}

function obj_ddOverObj(obj) {
	dd_msObj = obj
	dd_msObj.css.cursor = "move"
}

function obj_ddUp(e) {
	dd_obj = 0
}

function obj_ddDown(e) {
	if (dd_msObj) {
		x = getMouseEvtX(e)
		y = getMouseEvtY(e)
		dd_obj = dd_msObj
		dd_z++
		dd_obj.obj_zIndex(dd_z)
		dd_obj.ox = x - dd_obj.obj_x
		dd_obj.oy = y - dd_obj.obj_y
    }
}

function obj_ddMove(e) {
	x = getMouseEvtX(e)
	y = getMouseEvtY(e)
    if (dd_obj) {
		nx = Math.max(x - dd_obj.ox,0)
		ny = Math.max(y - dd_obj.oy,0)
		dd_obj.obj_moveTo(nx,ny)
    }
    return false
}

//get co-ordinates of mouse
function getMouseEvtY(e) {
    return (bw.ns || bw.ff) ? e.pageY : event.y || event.clientY
}

function getMouseEvtX(e) {
    return (bw.ns || bw.ff) ? e.pageX : event.x || event.clientX
}

//attach an event and perform a function
function obj_addEvent(obj,e,fn,useCapture) {
	if (obj.addEventListener) {
		obj.addEventListener(e,fn,useCapture)
		return true
    } else if (obj.attachEvent) {
		var r = obj.attachEvent("on" + e,fn)
		return r
    } else {
//	    if (bw.ns4) obj.captureEvents(eval("Event." + e.toUpperCase()))
		var r = "obj.on" + e + " = fn"
		eval(r)
		return true
	}
}

//remove an event capture
function obj_removeEvent(obj,e,fn,useCapture) {
	var r = "obj.on" + e + " = ''"
	eval(r)
	return true
/*	if (obj.removeEventListener) {
		obj.removeEventListener(e, fn, useCapture)
		return true
    } else if (obj.detachEvent) {
		var r = obj.detachEvent("on" + e, fn)
		return r
    } else {
		eval("obj.on" + e + " = ''")
	}	*/
}