// --file-- hcore.js
/*
 * Copyright (c) 2005, 2006 Justen Software LLC, also known as
 * justen.com and hiplatform.org. All rights reserved.
 * This material is made available under the terms of the HiPlatform V1
 * License. For more information, visit http://www.justen.com
 */

// temporary global functions to go into hcore.js
function debug( msg )
	{
	//alert( msg );
	}

var HCore_DYNAMIC = "dynamic";
var HCore_NATURAL = "natural";


/** Singleton with common methods */
var HCore = new HCore_();
function HCore_()
	{
	this.monthAbbreviations = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
	
	/* 
	 Argument is a string containing a date in the form yyyymmdd 
	 with optional trailing time value of hhmmxx or hhmmssxx, where 
	 xx is omitted or 'AM' or 'PM'. The return value is of the 
	 form 'dd-mmm-yyyy hh:mm:ss xx', for example '5-May-2004 08:30:21 AM'. 
	 The time portion is omitted if the time is missing from the input 
	 argument. Likewise, when a time is present, the seconds and the 
	 'AM' or 'PM' are included only when they are present in the input. 
	*/
	this.formatDate = function( v )
		{
		if ( v.length < 8 )
			return( v );
		var y = v.substring( 0, 4 );
		var m = v.substring( 4, 6 );
		var d = v.substring( 6, 8 );
		var date = (d*1) + '-' + this.monthAbbreviations[m-1] + '-' + y;
		if ( v.length == 8 )
			return( date );
		
		var h = v.substring( 8, 10 );
		var n = v.substring( 10, 12 );
		var time = (h*1) + ':' + n;
		if ( v.length == 12 )
			return( date + ' ' + time );
		var x = v.substring( 12, 14 );
		if ( x == 'AM' || x == 'PM' )	 
			return( date + ' ' + time + ' ' + x );
		time = time + ':' + x;
		if ( v.length == 12 )
			return( date + ' ' + time );
		return( date + ' ' + time + ' ' + v.substring( 14, v.length ) );
		}
		
	this.serialNumber = 0;
	this.getNextSerialNumber = function()
		{
		this.serialNumber++;
		return( this.serialNumber );
		}

	this.write = function( data )
		{
		//alert( data );
		document.write( data );
		}

	this.isRightClick = function( mouseEvent )
		{
		var e = mouseEvent || window.event;
		var rightclick;
		if (e.which) rightclick = (e.which == 3);
		else if (e.button) rightclick = (e.button == 2);
		return rightclick;
		}
		
	this.getMousePosition = function( mouseEvent ) 
		{
		var e = mouseEvent || window.event;
		var xpos = 0;
		var ypos = 0;
		
		if ( e.pageX || e.pageY )
			{
			xpos = e.pageX;
			ypos = e.pageY;
			}
		else
			{	
			// hack around IE issue 
			if ( document.body != null )
				{ 
				xpos = e.clientX + 
					document.body.scrollLeft + 
					document.documentElement.scrollLeft;
				ypos = e.clientY + 
					document.body.scrollTop + 
					document.documentElement.scrollTop;
				}
			}
			
		var pos = {x:xpos,y:ypos};	
		return( pos );
		}

	/* returns o.x and o.y */
	this.getElementPosition = function( elmt )
		{
		var left = 0;
		var top  = 0;

		while ( elmt.offsetParent )
			{
			left += elmt.offsetLeft;
			top  += elmt.offsetTop;
			elmt = elmt.offsetParent;
			}

		left += elmt.offsetLeft;
		top  += elmt.offsetTop;
		
		return {x:left, y:top};
		}

	this.getMouseOffset = function( fromElmt, mouseEvent )
		{
		var e = mouseEvent || window.event;

		var docPos = this.getElementPosition( fromElmt );
		var mousePos = this.getMousePosition( e );
		
		return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
		}
		
	this.mouseInside = function( fromElmt, mouseEvent )
		{
		var o = this.getMouseOffset( fromElmt, mouseEvent );
		if ( o.x >= 0 && o.x < fromElmt.clientWidth &&
			o.y >= 0 && o.y < fromElmt.clientHeight )
			return( true );
		return( false );		
		}
		
	/** drag and drop support */	

	this.mouseMove = function( event )
		{
		// attached to the document object, so 'this' == document
		
		event = event || window.event;
		var mousePos = HCore.getMousePosition( event );

 		var o = HCore.dragObject;
		if ( o != null )
			{
			var l = o.H_dragLimits;
			var insideLimits = true;
			if ( l != null )
				{
				if ( o.H_inXDirection &&
					( mousePos.x < l.left || mousePos.x > l.right ) )
					insideLimits = false;
				if ( o.H_inYDirection &&
					( mousePos.y < l.top || mousePos.y > l.bottom )	)
					insideLimits = false;
				}
			
			if ( insideLimits )
				{
				document.body.style.cursor = o.H_cursor;
				if ( o.H_dragging != undefined )
					o.H_dragging( event );
				}
			else
				document.body.style.cursor = 'default';

			return false;
			}
		}
		
	this.mouseUp = function( mouseEvent )
		{
		// attached to the document object, so 'this' == document
		
		var e = mouseEvent || window.event;
		var o = HCore.dragObject;
		if ( o == null )
			return;
		if ( o.H_dropped != undefined )
			// if a callback has been defined
			o.H_dropped( e );
		document.body.style.cursor = 'default';			
		HCore.dragObject = null;
		}
		
	document.onmousemove = this.mouseMove;
	document.onmouseup = this.mouseUp;
	this.dragObject = null;

	this.attachDragHandler = function( 
		elmt, inXDirection, inYDirection, limits )
		{
		elmt.H_inXDirection = inXDirection;
		elmt.H_inYDirection = inYDirection;
		elmt.H_dragLimits = limits;
		
		if ( inXDirection && inYDirection )
			elmt.H_cursor = 'move';
		else
			{
			if ( inXDirection )
				elmt.H_cursor = 'e-resize';
			if ( inYDirection )
				elmt.H_cursor = 'n_resize';
			}
		elmt.onmouseover = function( event )
			{
			this.style.cursor = this.H_cursor;
			}
		elmt.onmouseout = function( event )
			{
			this.style.cursor = 'default';
			if ( this.H_onmouseout != undefined )
				// if a callback has been defined
				this.H_onmouseout( event );
			}
		elmt.onmousedown = function( event )
			{
			event = event || window.event;
			HCore.dragObject = this;
			document.body.style.cursor = this.H_cursor;
			if ( this.H_dragStarted != undefined )
				// if a callback has been defined
				this.H_dragStarted( event );
			return false;
			}
		}				   

	this.formatNumber = function(num,dec,thou,pnt,curr1,curr2,n1,n2) 
		{
		// number formatting function
		// copyright Stephen Chapman 24th March 2006
		// permission to use this function is granted provided
		// that this copyright notice is retained intact
		var x = Math.round(num * Math.pow(10,dec));
		if (x >= 0) n1=n2='';
		var y = (''+Math.abs(x)).split('');
		var z = y.length - dec;
		y.splice(z, 0, pnt);
		while (z > 3) 
			{z-=3;
			y.splice(z,0,thou);
			}
		var r = curr1+n1+y.join('')+n2+curr2;
		return r;
		}
		
	this.formatUsDollars = function( value, decimals )
		{
		var decimalPt = '.';
		if ( decimals == 0 )
			decimalPt = '';
		return this.formatNumber( value, decimals, ',', decimalPt, '$', '','-','');
		} 

	this.controls = [];
	this.shuntResizing = false;
	/* 
	Lets controls implement methods that get called when 
	window has finished loading or has been resized.
	*/
	this.addWindowListener = function( control )
		{
		this.controls.push( control );
		if ( window.onload == undefined )
			{
			window.onload = function()
				{
				for ( var n = 0; n < HCore.controls.length; n++ )
					{
					var ctl = HCore.controls[n];
					if ( ctl.onload != undefined )
						ctl.onload();
					}
				}
			}
		if ( window.onresize == undefined )
			{
			window.onresize = function()
				{
				HCore.initiateResize();
				}
			}
		}

	this.initiateResize = function()
		{
		// IE 6 floods this with a huge number of messages
		// when page is made smaller, so we use the artifice
		// of a delayed job to filter out most of them. This is
		// less accurate and makes the Firefox version less
		// responsive but it avoids CPU meltdown in IE 6. It also
		// avoids a situation wherein IE 6 will issue another
		// resize message when the controls are resized inside
		// this logic (producing an infinite loop).
		if ( HCore.shuntResizing )
			return;
		HCore.shuntResizing = true;	
		
/*
var wsize = HCore.getWindowSize();			
alert( " window height " + wsize.height +  
	" window width " + wsize.width +  
	" body height " + document.body.clientHeight );
*/		
		HCore.makeControlsVisible( false );
		
		setTimeout( "HCore_doResizing()", 1000 );
			// wait a second and then do the actual resize
		}

	this.makeControlsVisible = function( on )
		{
		for ( var n = 0; n < this.controls.length; n++ )
			{
			var ctl = this.controls[n];
			if ( ctl.setVisible != undefined )
				ctl.setVisible( on );
			}
		}

	this.keyControls = [];
	/* 
	Lets controls implement methods that get called when 
	a key is pressed.
	*/
	this.addKeyListener = function( control )
		{
		this.keyControls.push( control );
		
		if ( document.onkeyup == undefined )
			{
			document.onkeyup = function( event )
				{
				if ( !event ) var event = window.event;
					// standard cross browser event logic
				for ( var n = 0; n < HCore.keyControls.length; n++ )
					{
					var ctl = HCore.keyControls[n];
					if ( ctl.onkeyup != undefined )
						{
						var keyConsumed = ctl.onkeyup( event );
						if ( keyConsumed )
							break; 
						}
					}
				}
			}
		}		
		
	this.getWindowSize = function()
		{
		var w = 0;
		var h = 0;
		if( typeof( window.innerWidth ) == 'number' )
			{
			w = window.innerWidth;
			h = window.innerHeight;
			}
		else 
			{
		  	w = document.documentElement.clientWidth;
		  	h = document.documentElement.clientHeight;
			}

		return { width:w, height:h }
		}
	}

/** standalone method to make setTimeout work */
function HCore_doResizing()
	{
	for ( var n = 0; n < HCore.controls.length; n++ )
		{
		var ctl = HCore.controls[n];
		if ( ctl.onresize != undefined )
			ctl.onresize();
		}
		
	HCore.makeControlsVisible( true );
	
	for ( var n = 0; n < HCore.controls.length; n++ )
		{
		var ctl = HCore.controls[n];
		if ( ctl.onresizeCompleted != undefined )
			ctl.onresizeCompleted();
		}
		
	setTimeout( "HCore_resumeProcessingResizeMessages()", 500 );
	}
	

function HCore_resumeProcessingResizeMessages()
	{		
	HCore.shuntResizing = false;
	}
