function SelectSwitcher(srcId, dstId, addId, delId)
{
    this.options = {
        add_button : true,
        del_button : true,

        src_sort   : sort_text,
        dst_sort   : sort_text,

        add_precallback : null,
        del_precallback : null,

        add_postcallback : null,
        del_postcallback : null
    };

    this.src = document.getElementById(srcId);
    this.dst = document.getElementById(dstId);
    this.add = document.getElementById(addId);
    this.del = document.getElementById(delId);

    this.error = !this.src ||
                 !this.dst ||
                 (this.options.add_button && !this.add) ||
                 (this.options.del_button && !this.del);

    if (this.error)
        return;

    this.src.sw = this;
    this.dst.sw = this;

    this.src.doSwitch = SelectSwitcher_add;
    this.src.selectAll = SelectSwitcher_selectAll;
    this.dst.doSwitch = SelectSwitcher_del;
    this.dst.selectAll = SelectSwitcher_selectAll;

    // matt, 23/04/07 - changed to single-click, awaiting feedback
    // this.src.ondblclick...
    this.src.onchange = SelectSwitcher_add;
	if (!window.ie6) {
		this.src.onclick = SelectSwitcher_add;
	}
	if(window.ie6) {
		this.src.ondblclick = SelectSwitcher_add;	
	}
	
    this.dst.onchange = SelectSwitcher_del;

    
    if (this.options.add_button) {
        this.add.sw = this;
        this.add.onchange = SelectSwitcher_add;
    }
    
    if (this.options.del_button) {
        this.del.sw = this;
        this.del.onchange = SelectSwitcher_del;
    }

    if (this.options.src_sort)
        this.src.sort = SelectSwitcher_sort;
    if (this.options.dst_sort)
        this.dst.sort = SelectSwitcher_sort;

    this.addItem = function(key, val, selected)
    {
        if (this.error)
            return;

        if (selected) {
            this.dst[this.dst.length] = new Option(val, key);
        }
        else {
            this.src[this.src.length] = new Option(val, key);
        }
    }

    this.addItems = function(arr)
    {
        if (this.error)
            return;

        for (i = 0; i < arr.length; i++) {
            selected = arr[i].length > 2 && arr[i][2];
            this.addItem(arr[i][0], arr[i][1], selected);
        }
    }

    this.delItem = function(idx, selected)
    {
        if (this.error)
            return;

        if (selected)
            this.dst[idx] = null;
        else
            this.src[idx] = null;
    }

    this.swapallAdd = function()
    {
        if (this.error)
            return;

        for (i = this.src.options.length - 1; i >= 0; i--) {
            this.addItem(this.src[i].value, this.src[i].text, true);
            this.delItem(i, false);
        }
        this.dst.sort(this.options.dst_sort);
    }

    this.swapallDel = function()
    {
        if (this.error)
            return;

        for (i = this.dst.options.length - 1; i >= 0; i--) {
            this.addItem(this.dst[i].value, this.dst[i].text, false);
            this.delItem(i, true);
        }
        this.src.sort(this.options.src_sort);
    }

    this.normalizeWidths = function(minW)
    {
        if (this.error)
            return;

        w = Math.max(this.src.offsetWidth, this.dst.offsetWidth);
        w = Math.max(w, minW);

        this.src.style.width = w + 'px';
        this.dst.style.width = w + 'px';
    }

}

function SelectSwitcher_add(e)
{
    proceed = true;
    if (this.sw.options.add_precallback)
        proceed = this.sw.options.add_precallback(this.sw);

    if (!proceed)
        return false;

    var del = [];

	var n=this.sw.src.length;
	var k=n;
	do{
		var i=k-n;
		if (this.sw.src[i].selected) {
            this.sw.addItem(this.sw.src[i].value, this.sw.src[i].text, true);
            this.sw.src[i].selected = false;
            del[del.length] = i;
        }
	}
	while(--n);

    for (i = del.length - 1; i >= 0; i--)
        this.sw.delItem(del[i], false);

    if (this.sw.options.src_sort)
        this.sw.src.sort(this.sw.options.src_sort);
    if (this.sw.options.dst_sort)
        this.sw.dst.sort(this.sw.options.dst_sort);

    if (this.sw.options.add_postcallback)
        this.sw.options.add_postcallback(this.sw);

	return false;
}

function SelectSwitcher_del(e)
{
    proceed = true;
    if (this.sw.options.del_precallback)
        proceed = this.sw.options.del_precallback(this.sw);

    if (!proceed)
        return false;

    var del = [];

	var n=this.sw.dst.length;
	var k=n;
	do{
		var i=k-n;
		if (this.sw.dst[i].selected) {
            this.sw.addItem(this.sw.dst[i].value, this.sw.dst[i].text, false);
            this.sw.dst[i].selected = false;
            del[del.length] = i;
        }
	}
	while(--n);

    for (i = del.length - 1; i >= 0; i--)
        this.sw.delItem(del[i], true);

    if (this.sw.options.src_sort)
        this.sw.src.sort(this.sw.options.src_sort);
    if (this.sw.options.dst_sort)
        this.sw.dst.sort(this.sw.options.dst_sort);

    if (this.sw.options.del_postcallback)
        this.sw.options.del_postcallback(this.sw);
}

function sort_text(option1, option2)
{
    return option1.text.toLowerCase() < option2.text.toLowerCase() ? -1 :
           option1.text.toLowerCase() > option2.text.toLowerCase() ?  1 :
           0;
}

function SelectSwitcher_sort(callback)
{
    if (!callback)
        return;

    var options = new Array (this.options.length);
	
	//this looks strange, but is more efficient than the usual for loop
	var n=options.length;
	var k=n;
	if(n>0){
		do{
			var i=k-n;
			options[i] = new Option (this.options[i].text, this.options[i].value);
		}
		while(--n);
    
		options.sort(callback);
		this.options.length = 0;
		
		n=options.length;
		k=n;
		do{
			var i=k-n;
			this.options[i] = options[i];
		}
		while(--n);
	}
}

function SelectSwitcher_selectAll()
{
    for (i = 0; i < this.options.length; i++) {
        this.options[i].selected = true;
    }
}
