/*
 * Copyright 2006, John Drinkwater <john@nextraweb.com>
 * Distributed under the terms of the MIT License.
 * Please note, this script isn't as DOM friendly as I would like, 
 * but IE, as always, has problems with <select> and <option>s
 * Version 1h, from http://ezri.nextraweb.com/examples/js/haiku/rev1h/componentselect.js
 * Thanks to wkornew & tic
 */

// From Prototype
function $( ) {
    var elements = new Array( );
    for ( var i = 0; i < arguments.length; i++ ) {
        var element = arguments[ i ];
        if ( typeof element == 'string' )
            element = document.getElementById( element );
        if ( arguments.length == 1 )
            return element;
        elements.push( element );
    }
    return elements;
}

/*
	take the current selection, and make a haiku/component
 */
function updateSelection( set, level ) {
	
	var text, i, component = '';
	for ( i = 1; i <= level + 1 ; i++ ) { 
		if ( componentSelector[ set ][ i ] && componentSelector[ set ][ i ].selectedIndex != -1 ) {
			text = componentSelector[ set ][ i ].options[ componentSelector[ set ][ i ].selectedIndex ].text;
			if ( text != '' )
				component += text + '/';
		}
	}
	hiddenComponent[ set ].value = component.substring( 0, component.length - 1 );
}

/*
	The user has changed the selected component
 */
function selectComponent( e ) {

	// because browsers never make it easy (IE)..
	var caller, remover;
	if ( !e ) var e = window.event;
	if ( e.target ) caller = e.target; else if ( e.srcElement ) caller = e.srcElement;
	if ( caller.nodeType == 3 ) // defeat Safari bug
		caller = caller.parentNode;
	var level = caller.stage, set = caller.set, onlyLeafs = caller.allowleafs;

	// bomb out if this is a last choice
	if ( level >= maxBranches ) {
		updateSelection( set, level ); 
		return;
	}

	// remove any <select>s to the right of us
	for ( i = maxBranches; i > level; i-- ) {
		if ( null != ( remover = componentSelector[ set ][ i ] ) ) {
			remover.selectedIndex = -1;
			if ( remover.parentNode )
				 remover.parentNode.removeChild( remover );
		}
	}
	// check if the user back–pedalled to a non option ( we no longer have '' choices )
	var parentChoice = componentSelector[ set ][ level ].options[ componentSelector[ set ][ level ].selectedIndex ].text;
	if ( parentChoice == '' ) {
		updateSelection( set, level ); 
		return;
	}

	var choice, superChoice, shortLeaf = false, previous = 's33d', p = 0, recursive = false, currentSelector = componentSelector[ set ][ level + 1 ];
	// empty the choice
	currentSelector.options.length = 0;
	previous = currentSelector.options[ p++ ] = new Option( );
 
	// Populate the choice 
	for ( i = 0; i < componentList.length ; i++ ) {
		choice = componentList[ i ][ level ]; 
		superChoice = componentList[ i ][ level - 1 ]; 
		if ( superChoice == parentChoice ) {
			if ( previous != choice && choice != null ) {
			
				previous = choice;
				currentSelector.options[ p++ ] = new Option( choice, choice );
			}
			if ( componentList[ i ][ level + 1 ] != null ) 
				recursive = true;
			if ( choice == null )
				shortLeaf = true;
		}
	}
	currentSelector.selectedIndex = 0; // Konq. has fits without

	// shortLeaf is true when we have a stump with leafs further on
	if ( currentSelector.options.length > 0 ) {
		if ( !( shortLeaf || !onlyLeafs) || previous == currentSelector.options[ 0 ]  ) {
			currentSelector.options[ 0 ] = null;
		}
	}

	// avoid cases where there are no options, ie, we have selected a leaf
	if ( currentSelector.options.length < ( onlyLeafs ? 1 : 2 ) ) {
		updateSelection( set, level ); 
		return;
	}

	// We're done, add it back to the page
	var parent = caller.parentNode;
	var sibling = caller.nextSibling;
	if ( sibling != null )
		parent.insertBefore( currentSelector, sibling );
	else
		parent.appendChild( currentSelector );

	// does this branch continue?
	if ( recursive ) {
		var event = { target : currentSelector };
		selectComponent( event ); // My Konq was being funny with anon {}
	} else 
		updateSelection( set, level ); 
}



/*
	This function deletes the <select> box, replaces it with a hidden input box, 
	and as many <select>s as the first/selected component had parts: this new element has an 
	event that triggers on change, to add or remove <select> boxes
	original: the <select> field that is to be replaced
	set: support multiple component fields, can leave null for autoincrement
	onlyLeafs: add leafs that contain '', so users can pick super components
 */
function reduceComponents( original, set, onlyLeafs ) {
	return;	
	// check support, else block js method
	if ( !document.createElement || !original )
		return; 
	if ( set == null ) set = window.components++;
	if ( onlyLeafs == null ) onlyLeafs = true;

	var i, p, j, sibling = original, parent = original.parentNode;
	// we assume the options never change between reduceComponents calls
	if ( componentList.length == 0 ) {
		for ( i = 0; i < original.options.length; i++ ) {
			componentList[ i ] = original.options[ i ].text.split( '/' );
			maxBranches = ( maxBranches < componentList[ i ].length ? componentList[ i ].length : maxBranches );
		}
		componentList.sort(); // so Trac can be lazy
	}

	componentSelector[ set ] = new Array();

	// create some replacement dropdowns
	for ( i = 1; i <= maxBranches; i++ ) {
		componentSelector[ set ][ i ] = document.createElement( 'SELECT' );
		componentSelector[ set ][ i ].id = 'component-componentSelector-' + set + '-' + i;
		componentSelector[ set ][ i ].className = 'haikucomponent';
		componentSelector[ set ][ i ].stage = i;
		componentSelector[ set ][ i ].set = set;
		componentSelector[ set ][ i ].allowleafs = onlyLeafs;
		addEvent( componentSelector[ set ][ i ], 'change', selectComponent );
	}

	// Setup the field to submit
	var currentSelector = componentSelector[ set ][ 1 ];
			hiddenComponent[ set ] = document.createElement( 'INPUT' );
			hiddenComponent[ set ].id = original.id;
			hiddenComponent[ set ].name = original.name;
			hiddenComponent[ set ].type = 'hidden';	

	// Take currently selected option, or the first
	if ( original.selectedIndex == -1 ) original.selectedIndex = 0;
	hiddenComponent[ set ].value = original.options[ original.selectedIndex ].text;
	subItems		  = hiddenComponent[ set ].value.split( '/' );

	var previous = 's33d', shortLeaf = false;

	// Populate choice(s)	
	for ( i = 0; i < subItems.length + 1; i++ ) {

		p = 0;
		currentSelector = componentSelector[ set ][ i + 1 ];
		if ( !currentSelector )
			continue;
		previous = currentSelector.options[ p++ ] = new Option( );
	
		for( j = 0; j < componentList.length ; j++ ) {

			choice = componentList[ j ][ i ];
			if ( componentList[ j ][ i - 1 ] == subItems[ i - 1 ] ) {
				
				if ( previous != choice && choice != null && choice != '' ) {
					previous = choice;					
					currentSelector.options[ p++ ] = new Option( choice, choice );
					if ( choice == subItems[ i ] )
						currentSelector.selectedIndex = p - 1;
				}
				if ( choice == null )
					shortLeaf = true;
			}
		}
		
		// Special case(s) for supercomponents: we have children, but! we dont have a child ourselves
		if ( currentSelector.options.length > 0 ) {
			if ( !( subItems[ i ] == null || shortLeaf || !onlyLeafs ) || previous == currentSelector.options[ 0 ] ) {
				currentSelector.options[ 0 ] = null;
			}
		}

		if ( currentSelector.options.length < ( onlyLeafs ? 1 : 2 ) )
			continue;

		// insert into page
		if ( sibling != null )
			parent.insertBefore( currentSelector, sibling );
		else
			parent.appendChild( currentSelector );
	}
	parent.replaceChild( hiddenComponent[ set ], original );
}

window.componentList = new Array( );
window.components = 0;
window.componentSelector = new Array( );
window.hiddenComponent = new Array( );
window.maxBranches = 0;

// For the ticket page
function connect() { reduceComponents( $( 'component' ) ); }

addEvent( window, 'load', connect );

