
//------------------
// Common functions
//------------------


//
// Preload
//  - forces loading of the given image URL.
//

function Preload( inImageSrc )
{
	var dummy = new Image();
	dummy.src = inImageSrc;
}


//
// DoNothing
//  - used for empty callbacks and methods.
//

function DoNothing()
{
	// do nothing
}


//
// WriteEmail
//  - writes out an email link. Simple obfuscation mechanism to slow scrapers.
//

function WriteEmail( inText, inUser, inBold, inBreak )
{
    document.write( '<img src="images/triangle.gif" width="11" height="12" border="0" align="texttop" alt="&gt;"> ' );
    document.write( '<a href="mailto:' + inUser + '@onegoodidea.com">' );
    if ( inBold )
        document.write( '<b>' );
    document.write( inText );
    if ( inBold )
        document.write( '</b>' );
    document.write( '</a>, ' + inUser + '@onegoodidea.com' );
    if ( inBreak )
        document.write( '<br>' );
}


//--------
// Mixins
//--------

// mixins are used to add an interface to another class of object. they basically
// add some more properties/methods to an object to add some behaviour to it.


//
// Broadcaster
//  - mixin for objects that can broadcast messages to Listeners.
//

function MixinBroadcaster( object )
{
	// public:
	
	object.BroadcastMessage = _BroadcastMessage;
	object.AddListener = _AddListener;

	// private:
	
	object._ListenerCount = 0;
	object._Listeners = new Array;
}

function _AddListener( inListener )
{
	// if we've been passed a defined object then add this object to the
	// array of listeners. this object had better have the Listener
	// interface mixed into it.
	
	if ( inListener )
		this._Listeners[this._ListenerCount++] = inListener;
}

function _BroadcastMessage( message, data )
{
	// iterate over the array of listeners, invoking the 'ListenToMessage'
	// method of each:

	for (i = 0; i < this._ListenerCount; i++)
		this._Listeners[i].ListenToMessage( this, message, data );
}


//
// Listener
//  - mixin for objects that can handle messages from Broadcasters.
//    the default 'ListenToMessage' method is empty, so you will want
//    to override this to add your own handler. this mixin is fairly
//    light - it's just there to ensure that a Listener object does
//    have the 'ListenToMessage' method. otherwise the broadcaster
//    will fail if it tries to deliver a message to the Listener.
//

function MixinListener( object )
{
	// public:
	
	object.ListenToMessage = DoNothing;
}


//-----------
// Constants
//-----------

//
// some standard messages for Broadcasters/Listeners:
//

msg_NoMessage = 0;
msg_Clicked = 1;
msg_MouseEntered = 2;
msg_MouseLeft = 3;



//---------
// Classes
//---------

//
// RolloverButton
//  - a class of image buttons that react to the mouse moving over them.
//    use as follows:
//
//      <img name="myImage" src="button.gif"
//         onMouseOver="mybutton.Enter();" onMouseOff="mybutton.Leave();">
//
//      <script>
//         mybutton = new RolloverButton( myImage, "button.gif", "highlighted.gif" );
//      </script>
//
//  - a rollover button has Broadcaster mixed into it and will broadcast the
//    messages 'msg_MouseEntered' and 'msg_MouseLeft' after updating the image.
//

function RolloverButton( inImage, inOffSrc, inOnSrc )
{
	// preload the two images:

	Preload( inOffSrc );
	Preload( inOnSrc );

	// mixin the broadcaster interface:

	MixinBroadcaster( this );

	// public methods:
	
	this.Enter = _RolloverButtonEnter;
	this.Leave = _RolloverButtonLeave;

	// private methods:
	
	this._Image = inImage;
	this._OffSrc = inOffSrc;
	this._OnSrc = inOnSrc;
}

function _RolloverButtonEnter()
{
	// update the image with the highlighted picture and broadcast
	// a 'msg_MouseEntered' message:
	
	this._Image.src = this._OnSrc;
	this.BroadcastMessage( msg_MouseEntered );
}

function _RolloverButtonLeave()
{
	// update the image with the standard picture and broadcast
	// a 'msg_MouseLeft' message:
	
	this._Image.src = this._OffSrc;
	this.BroadcastMessage( msg_MouseLeft );
}



//
// ButtonBanner
//  - a class for managing a banner that reacts to rollover buttons by displaying
//    a per-button image when a button is entered, and a default image when a
//    button is exited again. use as follows:
//
//      <img name="bannerImage" src="banner.gif">
//
//      <script>
//         mybanner = new ButtonBanner( bannerImage, "banner.gif" );
//         mybanner.AddButton( button1, "button1_banner.gif" );
//         mybanner.AddButton( button2, "button2_banner.gif" );
//      </script>
//

function ButtonBanner( inImage, inDefaultSrc )
{
	// preload the default picture:

	Preload( inDefaultSrc );

	// mixin the listener interface:

	MixinListener( this );

	// public methods:
	
	this.AddButton = _ButtonBannerAddButton;
	
	// override standard listener method with our own:
	
	this.ListenToMessage = _ButtonBannerListenToMessage;
	
	// private methods:
	
	this._Image = inImage;
	this._DefaultSrc = inDefaultSrc;
}


function _ButtonBannerAddButton( inButton, inSrc )
{
	// mixin the BannerImage interface to the given button and
	// add ourselves as a listener to that button:

	MixinBannerImage( inButton, inSrc );
	inButton.AddListener( this );
}

function _ButtonBannerListenToMessage( who, message )
{
	switch ( message )
	{
		// if the message corresponds to the mouse entering a button, then
		// update the banner image to the picture specified by that button.
		// we check that the button definitely has an associated picture first:
		
		case msg_MouseEntered:
			if ( who._BannerImageSrc )
				this._Image.src = who._BannerImageSrc
			break;
		
		// if the message corresponds to the mouse leaving a button, then
		// upate the banner image back to the default picture:
		
		case msg_MouseLeft:
			this._Image.src = this._DefaultSrc;
			break;
	}
}


//
// BannerImage
//  - a mixin for adding a banner picture to an object (specifically a
//    button that the ButtonBanner is listening to). provided here so that
//    you can mix this into specific classes. the 'AddButton' method of the
//    BannerButton class does this dynamically for a particular object.
//

function MixinBannerImage( object, inSrc )
{
	Preload( inSrc );
	object._BannerImageSrc = inSrc;
}


