//
//  Copyright (c) 1998-2000 Steven Champeon. All rights reserved.
// 
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as 
//  published by the Free Software Foundation; either version 2 of the
//  License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this program; if not, write to the Free Software
//  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//  The author may be contacted via email at <steve@dhtml-guis.com>;
//  other information may be found on the Web at http://dhtml-guis.com
//
//
//  Author: Steven Champeon <steve@dhtml-guis.com>
//  Maintainer: same
//  Release: 
//
//  $RCSfile: xplatform_wrapper.js,v $
//  $Revision: 1.11 $
//  $Date: 2000/10/08 17:41:40 $
//
//  Version History:
// 1.11 - 10/09/00 - bugfixes for abut() integer handling (Nathan Niesen)
// 1.10 - 08/13/00 - added array declaration for anchor_name
//  1.9 - 06/01/00 - anchor wrapper bugfix, again courtesy Jan.
//  1.8 - 04/28/00 - added anchor wrappers, courtesy of Jan Van Valen
//  1.7 - 04/28/00 - added offset* to get_top and get_left (Ralf Ziller)
//  1.6 - 12/06/99 - restored window width routines from 1.3.2
//  1.5 - 09/28/99 - made the GPL vs. LGPL disclaimer explicit
//  1.4 - 09/28/99 - updated disclaimer to use 'Lesser' GPL, a.k.a the
//                   GNU Library General Public License, to match the
//                   web site, which already said it was under the LGPL.
//
//  Purpose:
//   provide cross-browser wrapper objects.
//
//  Dependencies:
//   none.
//
//  Usage:
//   read the book.
// 
//  Credits:
//   Thanks to Simon E. S¿rensen, Ernie Jonker, Jan Van Valen, Ralf Ziller,
//   and everyone else who contributed bugfixes/extensions/testing etc.;
//   Also Shelley Powers, Danny Goodman, and Simon St. Laurent for the
//   inspiration and support.

var fully_loaded = false; // must set to true when fully loaded

var winHeight;
var winWidth;
var winRelHeight = 0;
var winRelWidth = 0;

var objects;

function debug(m) {
  if( navigator.javaEnabled() &&
      navigator.appName == "Netscape" ) {
    java.lang.System.out.println(m);
  }
}

function set_window_width() {
  if( window.innerWidth ) {
    winHeight = window.innerHeight;
    winWidth = window.innerWidth;
  } else {
    // should this be body.clientHeight? yes
    //winHeight = document.body.scrollHeight;
    winHeight = document.body.clientHeight;
    // should this be body.clientWidth? yes
    //winWidth = document.body.scrollWidth;
    winWidth = document.body.clientWidth;
  }
}

function set_relative_window_width() {
  if( document.body ) {
    winRelHeight = document.body.scrollTop;
    winRelWidth = document.body.scrollLeft;
  } else {
    winRelHeight = window.pageYOffset;
    winRelWidth = window.pageXOffset;
  }
}

// these need to be outside the function body because
// they are referenced by other functions later.
// forms
var form_name = new Array();
var form_count = 0;

// images
var image_name = new Array();
var image_count = 0;

// DIV objects and layers
var object_name = new Array();
// bugfix by Simon E. S¿rensen
var object_count = 0;

// anchor objects
// Jan Van Valen
var anchor_count = 0;
var anchor_name = new Array();
var anchor_number = new Array(); // bugfix 08/13/00

// create base objects
function create_base_objects() {
  if( document.all ) {
    objects = document.all.tags("DIV");
  } else {
    objects = document.layers;
  }

  for( i = 0; i < objects.length; i++ ) {
    current_name = objects[i].id;
    object_name[ current_name ] = new base_object( objects[i] );

    // IE doesn't index images per layer, but by the document,
    // so we need to check here and pass the whole collection
    // instead for IE.
    if( navigator.appName == "Netscape" ) {
      create_image_objects(objects[i].document);
      create_form_objects(objects[i].document);
      // Thanks to Jan Van Valen
			create_anchor_objects(objects[i].document);
			create_anchor_objects(document);
    }
  }
  if( navigator.appName != "Netscape" ) { // added 11/28/98
    create_image_objects(document);
    create_form_objects(document);
    // Thanks to Jan Van Valen
		create_anchor_objects(document);
  }
}

// create anchor objects - Jan Van Valen
function create_anchor_objects(d) {
	var k = d.anchors;
	if(navigator.appName == "Netscape") {
		var n = d.anchors.length;
	} else {
		var n = d.links.length; // so we get imagemaps as well as links (IE)
	}
	var l = d.links;
	anchor_count++;
	
	for( var x = 0; x < n; x++ ) {
		if(navigator.appName == "Netscape") {
			current_name = k[x].name; // use anchor name for Nav
		} else {
			current_name = l[x].name; // use link name for IE
		}
		// netscape doesn't return a link name but does return the anchor name
		// so use the anchors collection for the name: according to Danny 
		// Goodman's book both links and anchors are the same (see p 175).

		if( current_name == "" ) {
			current_name = "anchor" + anchor_count;
		}
		if( ! anchor_name[ current_name ] ) {
			anchor_name[ current_name ] = new anchor_object(l[x]);
			anchor_number[ anchor_count - 1 ] = current_name;
		}
	}
}

// href objects
function anchor_object(l) {
	l.get_href = get_anchor_href;
	l.set_href = set_anchor_href;
	return l;
}

// get the href property of the anchor
function get_anchor_href() {
    return this.href;
}

// set the href property of the anchor
function set_anchor_href(s) {
    this.href = s;
}

// create form objects
function create_form_objects(d) {
  var f = d.forms;
  var n = d.forms.length;

  for( var x = 0; x < n; x++ ) {
    current_name = f[x].name;
    if( current_name == "" ) {
      current_name = "form" + form_count;
      form_count++;
    }

    if( ! form_name[ current_name ] ) {
      form_name[ current_name ] = new form_object( f[x] );
    }
  }
}

// create image objects
function create_image_objects(d) {
  var i = d.images;
  var n = i.length;
  for( var x = 0; x < n; x++ ) {
    current_name = i[x].name;

    if( current_name == "" ) {
      current_name = "image" + image_count;
      image_count++;
    }
    
    if( ! image_name[ current_name ] ) {
      image_name[ current_name ] = new image_object( i[x] );
    }
  }
}

function base_object( object ) {
  if( object.style ) {
    this.isIE = object;
  } else {
    this.style = object;
  }
  
  object_count++;

  this.name = object.id;

  // handle visibility
  this.conceal = conceal;
  this.reveal = reveal;
  this.is_visible = is_visible;
  this.z_index = get_z_index;
  this.get_z_index = get_z_index;
  this.set_z_index = set_z_index;

  // handle positioning variables
  this.left = get_left;
  this.get_left = get_left;
  this.set_left = set_left;
  this.top = get_top;
  this.get_top = get_top;
  this.set_top = set_top;
  this.height = get_height;
  this.get_height = get_height;
  this.set_height = set_height;
  this.width = get_width;
  this.get_width = get_width;
  this.set_width = set_width;

  // handle clipping regions
  this.clipper = clipper;
  this.clipper_right = clipper_right;
  this.clipper_left = clipper_left;
  this.clipper_top = clipper_top;
  this.clipper_bottom = clipper_bottom;
  this.clipper_width = clipper_width;
  this.clipper_height = clipper_height;
  // alternate methods for single-param modification
  this.set_clipper_right = set_clipper_right;
  this.set_clipper_left = set_clipper_left;
  this.set_clipper_top = set_clipper_top;
  this.set_clipper_bottom = set_clipper_bottom;

  // handle absolute and relative positioning
  this.place = place;
  this.shove = shove;
  this.abut = abut;
  this.overlay = overlay;

  // handle color styling, background image
  this.bg_color = get_bg_color;
  this.set_bg_color = set_bg_color;
  this.color = get_color;
  this.set_color = set_color;
  this.bg_image = get_bg_image;
  this.set_bg_image = set_bg_image;

  // handle dynamic replacement of layer contents
  this.replace = replace;
  this.append = append;
  
  // handle events?
}

// form objects
function form_object( object ) {
  var f = object;
  f.get_action = get_form_action;
  f.set_action = set_form_action;
  f.get_enctype = get_form_enctype;
  f.set_enctype = set_form_enctype;
  f.get_method = get_form_method;
  f.set_method = set_form_method;
  f.get_target = get_form_target;
  f.set_target = set_form_target;
  return f;
}

// image objects
function image_object(i) {
  i.get_name = get_image_name;
  i.get_height = get_image_height;
  i.get_width = get_image_width;
  i.get_x = get_image_x;
  i.get_y = get_image_y;
  i.get_left = get_image_x; // added for abut() and overlay()
  i.get_top = get_image_y; // added for abut() and overlay()
  i.get_src = get_image_src;
  i.set_src = set_image_src;
  i.get_align = get_image_align;
  i.get_alt = get_image_alt;
  i.get_border = get_image_border;
  i.get_hspace = get_image_hspace;
  i.get_vspace = get_image_vspace;
  i.is_loaded = is_image_loaded;
  i.is_map = is_image_imap;
  i.use_map = use_image_map;

  return i;
}

// hide the object
function conceal() {
  if( this.isIE ) {
    this.isIE.style.visibility = "hidden";
  } else {
    this.style.visibility = "hidden";
  }
}

// show the object
function reveal() {
  if( this.isIE ) {
    this.isIE.style.visibility = "visible";
  } else {
    this.style.visibility = "visible";
  }
}

// is the object visible?
function is_visible() {
  if( this.isIE ) {
    //if( this.isIE.style.visibility != "hidden" ) {
    // bugfix suggested by Ernie Jonker
    if( this.isIE.style.visibility == "visible" ) {
      return true;
    }
  } else {
    if( this.style.visibility == "visible" ) {
      return true;
    } else if( this.style.visibility == "show" ) {
      return true;
    }
  }
  return false;
}

// return the object's left position
function get_left() {
  if( this.isIE ) {
    if( this.isIE.style.pixelLeft ) {
      var l = this.isIE.style.pixelLeft;
    } else if( this.isIE.style.clientLeft ) {
      var l = this.isIE.style.clientLeft;
    } else if( this.isIE.style.posLeft ) {
      var l = this.isIE.style.posLeft;
    } else if( this.isIE.style.offsetLeft ) {
    	// Thanks to Ralf Ziller
      var l = this.isIE.style.offsetLeft;
    } else {
      var l = 0;
    }
  } else {
    // remove clip stuff after checking rest of source
    if( this.style.clip.left ) {
      var l = this.style.clip.left;
    } else if( this.style.left ) {
      var l = this.style.left;
    } else {
      var l = 0;
    }
  }
  return l;
}

// set the object's left position
function set_left(l) {
  if( this.isIE ) {
    this.isIE.style.pixelLeft = l;
  } else {
    this.style.left = l;
  }
}

// return the object's top position
function get_top() {
  if( this.isIE ) {
    if( this.isIE.clientTop ) {
      var t = this.isIE.clientTop;
    } else if( this.isIE.style.pixelTop ) {
      var t = this.isIE.style.pixelTop;
    } else if( this.isIE.style.posTop ) {
      var t = this.isIE.style.posTop;
    } else if( this.isIE.style.offsetTop ) {
    	// Thanks to Ralf Ziller
      var t = this.isIE.style.offsetTop;
    } else {
      var t = 0;
    }
  } else {
    // todo: remove clip stuff after checking rest of source
    if( this.style.clip.top ) {
      var t = this.style.clip.top;
    } else if( this.style.top ) {
      var t = this.style.top;
    } else {
      var t = 0;
    }
  }
  return t;
}

// set the object's top position
function set_top(t) {
  if( this.isIE ) {
    this.isIE.style.pixelTop = t;
  } else {
    this.style.top = t;
  }
}

// return the object's height
function get_height() {
  if( this.isIE ) {
    if( this.isIE.clientHeight ) {
      var h = this.isIE.clientHeight;
    } else if( this.isIE.style.pixelHeight ) {
      var h = this.isIE.style.pixelHeight;
    } else if( this.isIE.style.posHeight ) {
      var h = this.isIE.style.posHeight;
    } else if( this.isIE.style.height ) {
      var h = this.isIE.style.height;
      h = parseInt(h.substr(0, h.length - 2));
    } else {
      h = 0;
    }
  } else {
    // todo: remove clip stuff after checking rest of source
    if( this.style.clip.height ) {
      var h = this.style.clip.height;
    } else if( this.style.height ) {
      var h = this.style.height;
    } else {
      var h = 0;
    }
  }
  return h;
}

// set the object's height
function set_height(h) {
  if( this.isIE ) {
    //this.isIE.style.height = h;
    this.isIE.style.pixelHeight = h;
  } else {
    this.style.height = h;
  }
}

// return the object's width
function get_width() {
  if( this.isIE ) {
    if( this.isIE.clientWidth ) {
      var w = this.isIE.clientWidth;
    } else if( this.isIE.style.pixelWidth ) {
      var w = this.isIE.style.pixelWidth;
    } else if( this.isIE.style.posWidth ) {
      var w = this.isIE.style.posWidth;
    } else if( this.isIE.style.width ) {
      var w = this.isIE.style.width;
      w = parseInt(w.substr(0, w.length -2));
    } else {
      var w = 0;
    }
  } else {
    // todo: remove clip stuff after checking rest of source
    if( this.style.clip.width ) {
      var w = this.style.clip.width;
    } else if( this.style.width ) {
      var w = this.style.width;
    } else {
      var w = 0;
    }
  }
  return w;
}

// set the object's width
function set_width(w) {
  if( this.isIE ) {
    this.isIE.style.pixelWidth = w;
  } else {
    this.style.width = w;
  }
}

// return the object's z-index
function get_z_index() {
  if( this.isIE ) {
    var z = this.isIE.style.zIndex;
    return z;
  } else {
    var z = this.style.zIndex;
    return z;
  }
}

// set the object's z-index
function set_z_index(z) {
  if( this.isIE ) {
    this.isIE.style.zIndex = z;
  } else {
    this.style.zIndex = z;
  }
}

// given the bounds of a rectangle, clip the object
function clipper(top, left, bottom, right) {
  if( this.isIE ) {
    var rect_str = "rect("+top+"px "+right+"px "+bottom+"px "+left+"px)";
//    var rect_str = "rect("+top+"px "+right+"px "+bottom+"px "+left+")";
    this.isIE.style.clip = rect_str;
  } else {
    this.style.clip.left = left;
    this.style.clip.right = right;
    this.style.clip.top = top;
    this.style.clip.bottom = bottom;
  }
}

// return right of clipping area
function clipper_right() {
  if( this.isIE ) {
    if( this.isIE.style.clip ) {
      var the_clip = this.isIE.style.clip;
      // the_clip shd look like rect(0px 0px 0px 0px) or auto
      if( the_clip == "auto" ) {
        return this.width();
      } else {
        var paren = the_clip.indexOf(')');
        if( paren != the_clip.length ) { // 
          // it probably looks like rect(0px 0px) 0px 0px
          // ugly bug on Macintosh platform. not to worry, clipping
          // regions don't work in IE on the Mac anyway.
          var coords = the_clip.substring(5);
          // coords shd look like 0px 0px) 0px 0px
        } else {
          var coords = the_clip.substring(5, (the_clip.length - 1 ));
          // coords shd look like 0px 0px 0px 0px
        }
        var rect = coords.split(" ");
        // this should give us:
        //  rect[0]: top in 'n' pixels
        //  rect[1]: right in 'n' pixels (may have trailing paren)
        //  rect[2]: bottom in 'n' pixels
        //  rect[3]: left in 'n' pixels
        var r = rect[1].split("p"); // 'n', 'x'
        if( r.length > 1 ) {
          return parseInt(r[0]);
        } else {
          return parseInt(r);
        }
      }
    } else {
      return 0;
    }
  } else {
    return this.style.clip.right;
  }
}

function set_clipper_right(r) {
  var t = this.clipper_top();
  var b = this.clipper_bottom();
  var l = this.clipper_left();
  this.clipper(t,l,b,r);
}

// return left of clipping area
function clipper_left() {
  if( this.isIE ) {
    if( this.isIE.style.clip ) {
      var the_clip = this.isIE.style.clip;
      if( the_clip == "auto" ) {
        return 0;
      } else {
        var paren = the_clip.indexOf(')');
        if( paren != the_clip.length ) {
          var coords = the_clip.substring(5);
        } else {
          var coords = the_clip.substring(5, (the_clip.length - 1 ));
        }
        var rect = coords.split(" ");
        // see notes at clipper_right
        var l = rect[3].split("p"); // 'n', 'x'
        if( l.length > 1 ) {
          return parseInt(l[0]);
        } else {
          return parseInt(l);
        }
      }
    } else {
      return 0;
    }
  } else {
    return this.style.clip.left;
  }
}

function set_clipper_left(l) {
  var t = this.clipper_top();
  var b = this.clipper_bottom();
  var r = this.clipper_right();
  this.clipper(t,l,b,r);
}

// return top of clipping area
function clipper_top() {
  if( this.isIE ) {
    if( this.isIE.style.clip ) {
      var the_clip = this.isIE.style.clip;
			if( the_clip == "auto" ) {
				return 0;
			} else {
				var paren = the_clip.indexOf(')');
				if( paren != the_clip.length ) {
					var coords = the_clip.substring(5);
				} else {
					var coords = the_clip.substring(5, (the_clip.length - 1 ));
				}
				var rect = coords.split(" ");
				// see notes at clipper_right
				var t = rect[0].split("p"); // 'n', 'x'
				if( t.length > 1 ) {
					return parseInt(t[0]);
				} else {
					return parseInt(t);
				}
			}
    } else {
      return 0;
    }  
  } else {
    return this.style.clip.top;
  }
}

function set_clipper_top(t) {
  var l = this.clipper_left();
  var b = this.clipper_bottom();
  var r = this.clipper_right();
  this.clipper(t,l,b,r);
}

// return bottom of clipping area
function clipper_bottom() {
  if( this.isIE ) {
    if( this.isIE.style.clip ) {
      var the_clip = this.isIE.style.clip;
      if( the_clip == "auto" ) {
        return this.height();
      } else {
        var paren = the_clip.indexOf(')');
        if( paren != the_clip.length ) {
					var coords = the_clip.substring(5);
        } else {
					var coords = the_clip.substring(5, (the_clip.length - 1 ));
				}
				var rect = coords.split(" ");
				// see notes at clipper_right
				var b = rect[2].split("p"); // 'n', 'x'
				if( b.length > 1 ) {
					return parseInt(b[0]);
				} else {
					return parseInt(b);
				}
			}
    } else {
      return this.height();
    }
  } else {
    return this.style.clip.bottom;
  }
}

function set_clipper_bottom(b) {
  var t = this.clipper_top();
  var l = this.clipper_left();
  var r = this.clipper_right();
  this.clipper(t,l,b,r);
}

// return width of clipping area
function clipper_width() {
  if( this.isIE ) {
    if( this.isIE.style.clip ) {
    	var bugfix = this.clipper_right() - this.clipper_left();
      return bugfix;
    } else {
      return this.width();
    }
  } else {
    return this.style.clip.right - this.style.clip.left;
  }
}

// return height of clipping area
function clipper_height() {
  if( this.isIE ) {
    if( this.isIE.style.clip ) {
      return this.clipper_bottom() - this.clipper_top();
    } else {
      return this.height();
    }
  } else {
    return this.style.clip.bottom - this.style.clip.top;
  }
}

// place object absolutely
function place( x, y ) {
  if( this.isIE ) {
    this.isIE.style.left = x;
    this.isIE.style.top = y;
  } else {
    this.style.moveTo( x, y );
  }
}

// move the object relative to current position
function shove( x, y ) {
  if( this.isIE ) {
    this.isIE.style.left = this.isIE.style.pixelLeft + x;
    this.isIE.style.top = this.isIE.style.pixelTop + y;
  } else {
    //this.style.moveBy( x, y );
    this.style.left += x;
    this.style.top += y;
  }
}

// handle placement relative to another object
function abut(o,compass,align,offset) {
  // get o's placement, dimensions
  var o_top = o.get_top();
  var o_left = o.get_left();
  var o_width = o.get_width();
  var o_height = o.get_height();
  // get our placement, dimensions
  var my_top = this.get_top();
  var my_left = this.get_left();
  var my_width = this.get_width();
  var my_height = this.get_height();
  var new_top = 0;
  var new_left = 0;

  // calculate offset
  if(offset == null) {
    offset = 0;
  }

  // based on compass, figure out where to put ourselves
  if( compass == "N" ) {
    new_top = (o_top - my_height) - offset;
    new_left = o_left;
    if( align == "RIGHT" ) {
      new_left += Math.abs(o_width - my_width);
    } else if( align == "CENTER" ) {
      new_left += parseInt( Math.abs((o_width - my_width)/2) );
    }
  } else if( compass == "E" ) {
    new_top = o_top;
    new_left = (o_left + o_width) + offset;
    if( align == "BOTTOM" ) {
      new_top += Math.abs(o_height - my_height);
    } else if( align == "CENTER" ) {
      new_top += parseInt( Math.abs((o_height - my_height)/2));
    }
  } else if( compass == "S" ) {
    new_top = (o_top + o_height) + offset;
    new_left = o_left;
    if( align == "RIGHT" ) {
      new_left += Math.abs(o_width - my_width);
    } else if( align == "CENTER" ) {
      new_left += parseInt( Math.abs((o_width - my_width)/2) );
    }
  } else if( compass == "W" ) {
    new_top = o_top;
    new_left = (o_left - my_width) - offset;
    if( align == "BOTTOM" ) {
      new_top += Math.abs(o_height - my_height);
    } else if( align == "CENTER" ) {
      new_top += parseInt( Math.abs((o_height - my_height)/2));
    }
  } else if( compass == "NE" ) {
    new_top = o_top - my_height - offset;
    new_left = o_left + o_width + offset;
  } else if( compass == "NW" ) {
    new_top = o_top - my_height - offset;
    new_left = o_left - my_width - offset;
  } else if( compass == "SE" ) {
    new_top = o_top + o_height + offset;
    new_left = o_left + o_width + offset;
  } else if( compass == "SW" ) {
    new_top = o_top + o_height + offset;
    new_left = o_left - my_width - offset;
  }

  this.place(new_left, new_top);
}

// given an object, overlay this object on top
function overlay(o, orientation, offset) {
  // get o's placement, dimensions
  var o_top = o.get_top();
  var o_left = o.get_left();
  var o_width = o.get_width();
  var o_height = o.get_height();
  if( o.get_z_index ) {
    var o_zindex = o.get_z_index();
  } else {
    var o_zindex = 0;
  }
  // get our placement, dimensions
  var my_top = this.get_top();
  var my_left = this.get_left();
  var my_width = this.get_width();
  var my_height = this.get_height();
  var new_top = 0;
  var new_left = 0;
  // calculate offset
  if(offset == null) {
    offset = 0;
  }

  // figure out orientation
  if( orientation == "NW" ) {
    new_top = o_top + offset;
    new_left = o_left + offset;
  } else if( orientation == "SW" ) {
    new_top = o_top  + o_height - my_height - offset;
    new_left = o_left + offset;
  } else if( orientation == "SE" ) {
    new_top = o_top + o_height - my_height - offset;
    new_left = o_left + o_width - my_width - offset;
  } else if( orientation == "NE" ) {
    new_top = o_top + offset;
    new_left = o_left + o_width - my_width - offset;
  } else if( orientation == "CENTER" ) {
    // if centering, ignore offset
    new_top = parseInt(o_top + (o_height/2) - (my_height/2));
    new_left = parseInt(o_left + (o_width/2) - (my_width/2));
  }
  this.place( new_left, new_top );
  this.set_z_index( o_zindex + 1);
}

// return the object's background color
function get_bg_color() {
  if( this.isIE ) {
    return this.isIE.style.backgroundColor;
  } else {
    return this.style.bgColor;
  }
}

// set the object's background color
function set_bg_color(c) {
  if( this.isIE ) {
    this.isIE.style.backgroundColor = c;
  } else {
    this.style.bgColor = c;
  }
}

// return the object's color
function get_color() {
  if( this.isIE ) {
    return this.isIE.style.color;
  } else {
    return this.style.fgColor;
  }
}

// set the object's color
function set_color(c) {
  if( this.isIE) {
    this.isIE.style.color = c;
  } else {
    this.style.fgColor = c;
  }
}

// return the object's background image
function get_bg_image() {
  if( this.isIE ) {
    return this.isIE.style.backgroundImage;
  } else {
    return this.style.background.src;
  }
}

// set the object's background image
function set_bg_image(i) {
  if( this.isIE ) {
	  //    this.isIE.style.backgroundImage = i;
	  // bugfix contributed by John Steedman
		this.isIE.style.backgroundImage = "URL("+i+")";
	} else {
    this.style.background.src = i;
  }
}


// set the action of a form
function set_form_action(a) {
  this.action = a;
}

// set the encoding type
function set_form_enctype(e) {
  this.encoding = e;
}

// set the method
function set_form_method(m) {
  this.method = m;
}

// set the target
function set_form_target(t) {
  this.target = t;
}

// get the action of a form
function get_form_action() {
  return this.action;
}

// get the encoding type
function get_form_enctype() {
  return this.encoding;
}

// get the method
function get_form_method() {
  return this.method;
}

// get the target
function get_form_target() {
  return this.target;
}

// get the name of the image
function get_image_name() {
  return this.name;
}

// get image height
function get_image_height() {
  return this.height;
}

// get image width
function get_image_width() {
  return this.width;
}

// get the image's URL of origin
function get_image_src() {
  return this.src;
}

// set the image's src
function set_image_src(s) {
  this.src = s;
}

// get the image's align setting (IE4 only)
function get_image_align() {
  if( this.align ) {
    return this.align;
  } else {
    return null;
  }
}

// get the image's alt text (IE4 only)
function get_image_alt() {
  if( this.alt ) {
    return this.alt;
  } else {
    return null;
  }
}

// get the image's border
function get_image_border() {
  return this.border;
}

// get the image's hspace
function get_image_hspace() {
  return this.hspace;
}

// get the image's vspace 
function get_image_vspace() {
  return this.vspace;
}

function get_image_z_index() {
  return 0;
}

// is the image loaded?
function is_image_loaded() {
  if( this.readyState ) {
    if( this.readyState == "complete" ) {
      return true;
    } else {
      return false;
    }
  } else {
    return this.complete;
  }
}

// is the image acting as a client-side imagemap?
function is_image_imap() {
  if( this.isMap != null ) {
    return this.isMap;
  } else {
    return false;
  }
}

// get the URL of the MAP element (IE4 only)
function use_image_map() {
  if( this.useMap ) {
    return this.useMap;
  } else {
    return false;
  }
}

// where is the image on the page?
function get_image_x() {
  // IE returns offsetLeft relative to current container
  // so we walk the hierarchy and sum them up
  // todo: need to do the same for Netscape if image is inside a layer
  if( this.offsetParent ) {
    var current = this;
    var the_x = 0;
    while( current.offsetParent != null ) {
      the_x += current.offsetLeft;
      current = current.offsetParent;
    }
    return the_x;
  } else if( this.x ) {
    return this.x;
  } else {
    return 0;
  }
}

function get_image_y() {
  // IE returns offsetTop relative to current container
  // so we walk the hierarchy and sum them up
  // todo: need to do the same for Netscape if image is inside a layer
  if( this.offsetParent ) {
    var current = this;
    var the_y = 0;
    while( current.offsetParent != null ) {
      the_y += current.offsetTop;
      current = current.offsetParent;
    }
    return the_y;
  } else if( this.y ) {
    return this.y;
  } else {
    return 0;
  }
}

// replace contents of layer dynamically
function replace(txt) {
  if( this.isIE ) {
    this.isIE.innerHTML = txt;
  } else {
    this.style.document.writeln(txt);
    this.style.document.close();
  }
}

// ??? not done
// append to contents of layer dynamically
function append(txt) {
  // bail if not fully loaded
  if( ! fully_loaded ) {
    return false;
  }

  if( this.isIE ) {
    this.isIE.insertAdjacentHTML("BeforeEnd", txt);

  } else {
    this.style.document.writeln( txt );
    this.style.document.close();
  }
  return true;
}

// track mouse movement
var mouse_x = 0;
var mouse_y = 0;
function track_mouse(e) {
  e = e || window.Event || window.event;
  mouse_x = e.pageX || e.clientX;
  mouse_y = e.pageY || e.clientY;
}

// handle events
function wrap_event(e) {
  if( window.event ) {
    // ----- INTERNET EXPLORER -----
    var return_event = new Object();
    e = window.event;

    // this is stupid. need to check for srcElement's parent
    // and see if it's a div. how to do this sanely?
    if( e.srcElement ) {
      var current = e.srcElement;
      while( current != null ) {
        if( object_name[current.id] ) {
          return_event.source = current.id;
          current = null;
        } else {
          current = current.offsetParent;
        }
      }
    }

    return_event.click_x     = e.clientX;
    return_event.click_y     = e.clientY;
    return_event.relative_x  = e.offsetX;
    return_event.relative_y  = e.offsetY;
    return_event.page_x      = e.clientX;
    return_event.page_y      = e.clientY;
    return_event.screen_x    = e.screenX;
    return_event.screen_y    = e.screenY;
    //return_event.button    = e.button;
  
    return_event.shift       = e.shiftKey; // == null) ? true : false;
    return_event.alt         = e.altKey; // == null) ? true : false;
    return_event.control     = e.ctrlKey; // == null) ? true : false;
    return_event.key         = e.keyCode; // == null) ? e.keyCode : false;
    
    return_event.cancel = false;

  } else {
    // ----- NETSCAPE -----
    var return_event = new Event();    
    return_event.click_x    = e.x;
    return_event.click_y    = e.y;
    return_event.relative_x = e.layerX;
    return_event.relative_y = e.layerY;
    return_event.screen_x   = e.screenX;
    return_event.screen_y   = e.screenY;
    return_event.page_x     = e.pageX;
    return_event.page_y     = e.pageY;

    if( e.target ) {
      return_event.source = e.target;
    } else {
      return_event.source = null;
    }

    return_event.shift   = (e.modifiers & Event.SHIFT_MASK) ? true : false;
    return_event.alt     = (e.modifiers & Event.ALT_MASK) ? true : false;
    return_event.control = (e.modifiers & Event.CONTROL_MASK) ? true : false;

    // problem here - Netscape uses which for both mouse and key events,
    // so we may get a key property if the mouse is clicked. No biggie,
    // but something to look out for if we're using modifiers and mouse
    // clicks at the same time.
    if( e.type.indexOf("key") >= 0 ) {
      return_event.key = e.which;
    } else {
      return_event.key = -1;
    }
  }

  return_event.type = e.type;
  return_event.already = true;

  return return_event;
}

// create a new layer - must be called prior to loading in IE,
// post-load in Netscape, because IE doesn't recognize new DIV
// objects added post-load, and because Netscape hangs when you
// try to create a new Layer before the document has fully loaded.
//
// question: does Netscape recognize new DIVs when printed to the
// browser, or what? why are we doing Layers instead of DIVs?
// Yes, it does - witness create_word_divs() in executive_poetry.js

function new_layer(name,styleinfo,contents,handlers,create) {
  if( document.all ) {
    var the_div = '<div id="' + name + '" ' + styleinfo +
      handlers + '>' + contents + '</div>';

    document.open("text/html");
    document.write( the_div );
    document.close();
    // need to grab a ref to the new object (?!?)
    var all_divs = document.all.tags("DIV");
    var new_layer = all_divs[all_divs.length - 1];
  } else {
    var new_layer = new Layer(1);
    new_layer.document.open("text/html");
    new_layer.document.write( contents );
    new_layer.document.close();
  }

  if( create ) {
    object_name[name] = new base_object( new_layer );
    object_name[name].conceal();
    return true;
  } else {
    return new_layer;
  }
}

// cross-browser screen properties
var xp_screen = new Object();

function get_screen_props() {
  // monitor bit & pixel depth
  if( screen.pixelDepth ) {
    xp_screen.color_depth = screen.colorDepth;
    xp_screen.depth = screen.pixelDepth;
  } else {
    xp_screen.color_depth = screen.colorDepth;
    xp_screen.depth = screen.bufferDepth; // eh, not really...
  }
  
  // available height and width (need to add workarounds for
  // Macintosh/IE, which calculates things incorrectly according to DHTML:TDR)
  if( screen.availHeight ) {
    xp_screen.aheight = screen.availHeight;
    xp_screen.awidth = screen.availWidth;
  }
  
  // height and width - same cross-browser
  if( screen.height ) {
    xp_screen.height = screen.height;
    xp_screen.width = screen.width;
  }
  return xp_screen;
}

// convenience functions
function get_selected_option(s) {
  if( s.options[s.selectedIndex].value != "" ) {
    return s.options[s.selectedIndex].value;
  } else if( s.options[s.selectedIndex].text != "" ) {
    return s.options[s.selectedIndex].text;
  } else {
    return "";
  }
}

// parseInt() doesn't grok floating point numbers less than 1.
// instead, we return the floor of the parsed float.
function get_integer(x) {
  var test = parseInt(x);
  if(isNaN(test)) {
    test = Math.floor(parseFloat(x));
  }
  return test;
}
