// determine browser
var IE = (navigator.appName == "Microsoft Internet Explorer");

var costModelClipboard;

var submitListeners = new Array();
var submitListenerCount = 0;

// for cost model configuration screen. clipboard may look like this:
// cmclip:repetition=0.30:5=0.80:4=0.70:3=0.60:2=0.50:1=0.40:perfect=0.10:ice=0.05
function copyCostModelRow(name)
{
    var formElements = document.forms[0].elements;
    var re = new RegExp(name + "$"); // ends with
    var clipboardValue = "cmclip";

    for (var i = 0; i < formElements.length; i++ )
    {
        // a cost model line item id and range id may clash, in that case we want to
        // make sure that we pick the right input fields. (CQ #9748)
        if (formElements[i].name.match(re))
        {
            var value = formElements[i].value;
            var tags = formElements[i].name.split("_");
            clipboardValue = clipboardValue + ":" + tags[1] + "=" + value;
        }
    }
    costModelClipboard = clipboardValue;
}


// for cost model configuration screen. clipboard looks like this:
// cmclip:repetition=0.30:5=0.80:4=0.70:3=0.60:2=0.50:1=0.40:perfect=0.10:ice=0.05
function pasteCostModelRow(name)
{
    if (costModelClipboard != null)
    {
        clipboardValue = costModelClipboard;
        values = clipboardValue.split(":");
        if (values[0] == "cmclip")
        {
            for (var i = 1; i < values.length; i++ )
            {
                var pair = values[i].split("=");
                var inputIdentifier = "match_" + pair[0] + "_" + name.toString();
                document.forms[0].elements[inputIdentifier].value = pair[1];
            }
        }
    }
}

// check or uncheck all checkboxes in a form. Assumes that checkboxes are
// named "checkbox".
// params:
//      identifier:     id for check all box and associated checkboxes
function checkAll(identifier)
{
    checkAllByName(identifier, "checkbox");
}

// check or uncheck all checkboxes in a form with a given identifier and name.
// params:
//      identifier:     id for check all box and associated checkboxes
//      name:           name of associated checkboxes (assumes that only
//                      checkboxes have this name)
function checkAllByName(identifier, name)
{
    var form = document.forms[identifier];
    if(typeof(document.forms[0].methodUsed) != "undefined") {
        form = document.forms[0];
    }

    // find our checkAll box
    var checkAll = form.checkAllBox;
    if(checkAll.length) {
       for (i = 0; i < checkAll.length; i++) {
         if(checkAll[i].id == identifier) {
            checkAll = checkAll[i];
            break;
         }
       }
    }

    checkAllByNameFromForm(identifier, name, checkAll.checked, form);
}

// check or uncheck all checkboxes in a form
// params:
//      identifier:     checkboxes id value
//      name:           checkboxes name value (assumes that only checkboxes
//                      have this name)
//      markAsChecked:  true marks boxes as checked; false marks boxes as not
//                      checked
//      form:           the form containing the checkboxes
function checkAllByNameFromForm(identifier, name, markAsChecked, form) {
    var cbox = eval("form." + name);
    if (cbox != null)
    {
        for (i = 0; cbox[i] != null; i++)
        {
            //  XXX: ugly solution
            if((cbox[i].id == identifier) &&
               (cbox[i].parentNode.parentNode.style.display != "none")) {
                cbox[i].checked = markAsChecked;
            }
        }
        if (i == 0)
        {
            if(cbox.id == identifier) {
                cbox.checked = markAsChecked;
            }
        }
    }
}

function isInputEnterKeyPressed(theEvent) {
    var code = 0;

    if (theEvent.keyCode) {
        code = theEvent.keyCode;
    } else if (theEvent.which) {
        code = theEvent.which;
    }

    return (code == 13);
}

// variables and functions for range selection of checkboxes in table

var isAltDown = false;
var prevClicked = new Array();

function handleProjectGroupTreeCheckboxClick(i, identifier,nodeToken,obj) // i is the ith checkbox
{
    var form = document.forms[identifier];
    if(typeof(document.forms[0].methodUsed) != "undefined") {
        form = document.forms[0];
    }

    var posCur = nodeToken.lastIndexOf(".");
    var nodeTypeCur = nodeToken.substring(posCur+1,nodeToken.length);

    if(form.nodeType.value != nodeTypeCur) {
        for(j=0 ; j < form.checkbox.length ; j++){
            if(form.checkbox[j].checked){
                form.checkbox[j].checked = false;
            }
        }
        obj.checked = true;
        form.nodeType.value = nodeTypeCur;
    }
}

function getTargetElement(theEvent)
{
    var result = null;

    if (!theEvent) {
        theEvent = window.event;
    }

    if (theEvent.target) {
        result = theEvent.target;
    } else if (theEvent.srcElement) {
        result = theEvent.srcElement;
    }

    if (result.nodeType == 3) {
        result = result.parentNode;
    }

    return result;
}

function findParentTableBody(theElement)
{
    if (theElement == null) {
        return null;
    }

    var parent = theElement.parentNode;

    while (parent) {
        if (parent.tagName.toLowerCase() == "tbody") {
            return parent;
        }

        parent = parent.parentNode;
    }

    return null;
}

function findCheckbox(theRow) {
    var result = null;

    var cell = theRow.cells[0];
    if (cell.firstChild != null) {
        var firstChildNode = cell.firstChild;
        if ((firstChildNode.nodeName.toLowerCase() == "input") &&
            (firstChildNode.getAttribute("type").toLowerCase() == "checkbox")) {
            result = firstChildNode;
        }
    }

    return result;
}

function handleCheckboxClick(event, identifier)
{
    var form = document.forms[identifier];
    if(typeof(document.forms[0].methodUsed) != "undefined") {
        form = document.forms[0];
    }
    var cbox = eval("form.checkbox");

    if (cbox != null)
    {
        var isAltDown = event.altKey;
        var targetElement = getTargetElement(event);

        if (prevClicked[identifier] == null  || !isAltDown)
        {
            prevClicked[identifier] = targetElement;
            return;
        }

        //  Need to check/uncheck group of checkboxes
        //  between previously clicked and this one
        var checked = prevClicked[identifier].checked;
        var start = prevClicked[identifier];
        var end = targetElement;

        if (start == end) {
            //  Empty interval
            return;
        }

        var tableBody = findParentTableBody(targetElement);
        if (tableBody == null) {
            //  Strange, but we are out of a table
            return;
        }

        var rows = tableBody.rows;
        var intervalEnd = null;

        for (var i = 0; i < rows.length; i++) {
            var checkbox = findCheckbox(rows[i]);

            if (checkbox) {
                if (intervalEnd == null) {
                    //  We are not in the interval
                    if (checkbox == start) {
                        intervalEnd = end;
                    } else if (checkbox == end) {
                        intervalEnd = start;
                    }
                } else {
                    if (rows[i].style.display.toLowerCase() != "none") {
                        checkbox.checked = checked;
                    }

                    if (checkbox == intervalEnd) {
                        break;
                    }
                }
            }
        }
        prevClicked[identifier] = targetElement;
        return;
    }
}

function handleButton(submit, popup, url, name, style)
{
    hideAllPopups();

    if (submit)
    {
        var form = document.forms[0];
        form.action = url;
        if (popup)
        {
            name = 'popup_' + name;
            openStandardWindow('', name, style);
            form.target = name;
        }
        else
        {
            form.target = "_self";
        }

        for (slInd=0; slInd < submitListenerCount; slInd++) {
          submitListeners[slInd]();
        }

        form.submit();
    }
    else
    {
        if (popup)
        {
            name = 'popup_' + name;
            openStandardWindow(url, name, style);
        }
        else
        {
            location.href = url;
        }
    }
}

// simple wrapper for window.open that adds randomness
function openWindow(url, name, properties)
{
    if(url != '') {
        // add some randomness
        url += '&random=' + escape(Math.random()); // TODO
    }
    // debug - to be able to see JavaScript errors in popup status bar
    //properties = 'width=800,height=600,status=1,toolbar=1,location=0,menubar=1,resizable,scrollbars=yes';

    return window.open(url, name, properties);
}

function openStandardWindow(url, name, style)
{
    if(!name.match('popup_')) {
        name = 'popup_' + name
    }

    properties = 'width=500,height=500,toolbar=0,location=0,menubar=0,resizable,scrollbars=yes';
    if (style == 'normal_wide')
    {
        properties = 'width=650,height=500,toolbar=0,location=0,menubar=0,resizable,scrollbars=yes';
    }
    if (style == 'normal_extra_wide')
    {
        properties = 'width=800,height=500,toolbar=0,location=0,menubar=0,resizable,scrollbars=yes';
    }
    if (style == 'normal_long')
    {
        properties = 'width=600,height=640,toolbar=0,location=0,menubar=0,resizable,scrollbars=yes';
    }
    if (style == 'normal')
    {
        properties = 'width=600,height=500,toolbar=0,location=0,menubar=0,resizable,scrollbars=yes';
    }
    if (style == 'extra_wide')
    {
        properties = 'width=900,height=500,toolbar=0,location=0,menubar=0,resizable,scrollbars=yes';
    }
    if (style == 'extra_wide_more')
    {
        properties = 'width=950,height=500,toolbar=0,location=0,menubar=0,resizable,scrollbars=yes';
    }
    if (style == 'smallfixed')
    {
        properties = 'width=500,height=250,toolbar=0,location=0,menubar=0,scrollbars=yes';
    }
    if (style == 'small')
    {
        properties = 'width=500,height=250,toolbar=0,location=0,menubar=0,resizable,scrollbars=yes';
    }
    if (style == 'editorsize')
    {
        properties = 'width=900,height=600,toolbar=0,location=0,menubar=0,resizable,scrollbars=yes';
    }
    if (style == 'report')
    {
        properties = 'width=1015,height=710,toolbar=0,location=0,menubar=0,resizable,scrollbars=yes';
    }
    if (style == 'large')
    {
        properties = 'width=800,height=600,toolbar=0,location=0,menubar=0,resizable,scrollbars=yes';
        // Viewer window needs status bar. This is fragile. Refactor is so
        // this can be controlled from Java
        if (name == 'popup_viewer') {
            properties += ',status=yes';
        }
    }
    if (style == 'long')
    {
        properties = 'width=650,height=640,toolbar=0,location=0,menubar=0,resizable,scrollbars=yes';
    }
    if (style == 'applet')
    {
        properties = 'width=800,height=600,toolbar=0,location=0,menubar=0,resizable,scrollbars=no';
    }
    openWindow(url, name, properties);
}

// called by a popup window to refresh/reload the page that opened it
// Pages based on a new component architecture will have "methodUsed" object
// set to whatever method was used to request the page (POST or GET)
// If the page was a result of submit we call submit() to reload the page,
// otherwise we do plain reload()
var pagetoken;
var pagelocation;
function refreshPage(openertoken)
{
    if (document.explorerApplet) {
        // doesn't make sense to refresh the whole explorer page,
        // so we use this to instead refresh the state of the applet.
        document.explorerApplet.refreshCurrentNode();
    }
    else if (pagetoken == openertoken || openertoken == "force_refresh")
    {
         if (typeof(doRefresh) == 'function') {
            // Page wants to handle its own refresh
            doRefresh();
         }
         else if (typeof(document.forms[0].methodUsed) != "undefined" &&
             document.forms[0].methodUsed.value == 'POST')
         {
             // POST case. Need to resubmit
             doSubmit("page_refresh");
         }
         else if (pagelocation)
         {
             // GET case. Need to reload. Do not use reload() method
             // because it is restricted in IE6
             location = pagelocation;
         }
         else
         {
             // Just reload our own page
             location = location;
         }
    }
}

function listBoxMove(from, to)
{
    options = new Array();
    var j = 0;
    for (var i = 0; i < from.options.length; i++)
    {
        if ((from.options[i].selected) && (isItem(from.options[i].value)))
        {
            var option = new Option();
            option.value = from.options[i].value;
            option.text = from.options[i].text;
            to.options[to.options.length] = option;
            from.options[i].value = "";
            from.options[i].text = "";
        }
        else
        {
            options[j] = from.options[i];
            j++;
        }
    }
    for (var i = 0; i < j; i++)
    {
        from.options[i].value = options[i].value;
        from.options[i].text = options[i].text;
    }
    from.options.length = j;
    listBoxSort(to, false);
}

function isItem(string)
{
    if (string.indexOf("-") == -1)
    {
        return false;
    }
    return true;
}

function getSortNumber(string)
{
    var pos;
    pos = string.indexOf("-");
    if (pos == -1)
    {
        pos = string.indexOf("*");
    }

    return parseInt(string.substring(0, pos));
}

function listBoxSort(box, useName)
{
    for (var i = 0; i < box.options.length; i++)
    {
        var swapped = 0;
        for (var j = 0; j < box.options.length - 1 - i; j++)
        {
            var needSwap;
            if(useName)
            {
               if(box.options[j].value > box.options[j+1].value)
                {
                        needSwap = true;
                }
                else
                {
                        needSwap = false;
                }
            }
            else
            {
                if(getSortNumber(box.options[j].value) >
                        getSortNumber(box.options[j+1].value))
                {
                        needSwap = true;
                }
                else
                {
                        needSwap = false;
                }
            }
            if (needSwap)
            {
                var tempValue = box.options[j].value;
                var tempText = box.options[j].text;
                box.options[j].value = box.options[j+1].value;
                box.options[j].text = box.options[j+1].text;
                box.options[j+1].value = tempValue;
                box.options[j+1].text = tempText;
                swapped = 1;
            }
        }
        if (! swapped)
        {
            break;
        }
    }
}

function listBoxSelectAll(box)
{
    for (var i = 0; i < box.options.length; i++)
    {
        box.options[i].selected = true;
    }
}

// PagedTable stuff
function handleTablePageing(identifier, page)
{
    var pageObj = eval("document.forms[0]." + identifier + "page");
    pageObj.value = page;
    doSubmit("paging_" + identifier);
}
function handleTableSorting(identifier, sortcolumn)
{
    var sortObj = eval("document.forms[0]." + identifier + "sortcolumn");
    sortObj.value = sortcolumn;
    doSubmit("sorting_" + identifier);
}
function handleTableAllPages(identifier, allpages, page)
{
    var allPagesObj = eval("document.forms[0]." + identifier + "allpages");
    allPagesObj.value = allpages;
    handleTablePageing(identifier, page)
}

// DoubleList stuff
function handleDoubleListSwitch(from, to, resList, resField, skipSort,
                                actionButton)
{
    // Remove selected options from "from" list and add it to "to" list
    // Ignore categories (ends with --999)
    var j = 0;
    for (var i = 0; i < from.options.length; i++)
    {
        var option = new Option();
        option.value = from.options[i].value;
        option.text = from.options[i].text;
        if (from.options[i].selected && !from.options[i].value.match("--999$"))
        {
            to.options[to.options.length] = option;
        }
        else
        {
            from.options[j] = option;
            j++;
        }
    }
    from.options.length = j;

    if(!skipSort) {
      sortList(to);
    }

    // Update resulting value
    var resultArray = new Array();
    for(var i=0; i<resList.options.length; i++) {
        var str = resList.options[i].value;
        resultArray[i] = str.substring(str.indexOf("-")+1);
    }
    resField.value = resultArray.toString();

    if(actionButton != '') {
        var btn = eval("document.forms[0]." + actionButton);
        if(btn) {
            btn.disabled = resList.options.length == 0 ? 1 : 0;
        }
    }

    return false;
}
function handleMultipleListSwitch(from, to, tgtList, tgtField,
                    srcList, tgtLists, skipSort, categoryText)
{
    // Checks if srcList has category option (ends with '--999') selected
    // Does select srcList options but category
    var hasCategory = false;
    var selected = false;
    for (var i = 0; i < srcList.options.length; i++) {
        if (!hasCategory &&
                (hasCategory = srcList.options[i].value.match("--999$"))) {
            if (selected = srcList.options[i].selected) {
                // select all
                i = -1;
                continue;
            }
        }
        // select all
        if (selected) {
            srcList.options[i].selected = true;
        }
    }
    // Removes selected options from "from" list and add them to "to" list
    var fieldVal = tgtField.value;
    handleDoubleListSwitch(from, to, tgtList, tgtField, skipSort, '');
    if (selected) {
        srcList.options.length = 0;
        return false;
    }
    var addCategory = !hasCategory;
    for (var i = 0; i < tgtLists.length; i++) {
        if (tgtLists[i].options.length != 0) {
            addCategory = false;
            break;
        }
    }
    if (fieldVal != tgtField.value) {
        if (addCategory && categoryText != null) {
           // add
           var option   = new Option();
           option.value = "--999";
           option.text  = categoryText;
           srcList.options[srcList.options.length] = option;
        } else {
           // remove
           var j = 0;
           var newArray = new Array();
           for (var i = 0; i < srcList.options.length; i++) {
               if (!srcList.options[i].value.match("--999$")) {
                   newArray[j++] = srcList.options[i]
               }
           }
           for (var i = 0; i < newArray.length; i++) {
               srcList.options[i].value = newArray[i].value;
               srcList.options[i].text  = newArray[i].text;
           }
           srcList.options.length = newArray.length;
        }
        sortList(srcList);
    }
    return false;
}

// Sort list using array sort function
function sortList(list) {
    var sortingArray = new Array();
    for(var i=0; i<list.options.length; i++) {
        sortingArray[i] = list.options[i];
    }
    sortingArray.sort(function (o1, o2) {
        return o1.value < o2.value ? -1 : 1;
    });
    for(var i=0; i<list.options.length; i++) {
        var option = new Option();
        option.value = sortingArray[i].value;
        option.text = sortingArray[i].text;
        list.options[i] = option;
    }
}
// finds components by cIdPrefic+i id and returns array of found
function getComponentsArray(cIdPerfix, cCount)
{
    var components = new Array();
    for (var i = 0, j = 0; i < cCount; i++) {
        var component = getDocElement(cIdPerfix+i);
        if (component != null) {
            components[j++] = component;
        }
    }

    return components;
}
// moves the selected items up/down in the list
function handleDoubleListMove(list, isUp, resField)
{
    if(isUp) {
        for (var i = 1; i < list.options.length; i++) {
            if (list.options[i].selected) {
                var text = list.options[i-1].text;
                var value = list.options[i-1].value;

                list.options[i-1].value = list.options[i].value;
                list.options[i-1].text = list.options[i].text;
                list.options[i-1].selected = true;

                list.options[i].value = value;
                list.options[i].text = text;
                list.options[i].selected = false;
            }
        }
    } else {
       for (var i = list.options.length-2; i >= 0; i--) {
            if (list.options[i].selected) {
                var text = list.options[i+1].text;
                var value = list.options[i+1].value;

                list.options[i+1].value = list.options[i].value;
                list.options[i+1].text = list.options[i].text;
                list.options[i+1].selected = true;

                list.options[i].value = value;
                list.options[i].text = text;
                list.options[i].selected = false;
            }
        }
    }

    // Update resulting value
    var resultArray = new Array();
    for(var i=0; i<list.options.length; i++) {
        var str = list.options[i].value;
        resultArray[i] = str.substring(str.indexOf("-")+1);
    }
    resField.value = resultArray.toString();

    return false;
}

// DoubleGridList
function handleDoubleGridListSwitch(leftPane, rightPane, direction, ordered, insertOption)
{
	if (direction == 0 || direction == 1) {
		var from;
		var to;

		if (direction == 0) {
			from = rightPane;
			to = leftPane;
		} else if (direction == 1) {
			from = leftPane;
			to = rightPane;
		}

		// find selected rows
		var rowIds = getSelectedRows(from);
		if (rowIds == null) {
			// nothing found
			return false;
		}

		var moveToBottom = (insertOption == 'bottom') && ordered;

		// move row(-s)
	    for (i=0; i < rowIds.length; i++) {
			if (direction != 0 || !(from.getRowEA(rowIds[i], 'isAlwaysSelected'))) {
				from.moveRow(rowIds[i], "row_sibling", rowIds[i], to);
				if (to.getRowEA(rowIds[i], 'isReadOnly')){
					for (j=0; j < to.getColumnCount(); j++){
						to.cells(rowIds[i],j).setDisabled(true);
					}
				}
			   // commented due to performance issues (CQ #16864)
		       //if (moveToBottom) {
		         // Bug 14397. Do not move a row down if it's already at the
		         // bottom. That will mess up the row numbers due to a
		         // dhtmlXGridObject bug.
		         //var idx = to.getRowIndex(rowIds[i]);
		         //var tc = to.getRowsNum() - (idx + 1);

		         //for (j=0; j < tc; j++) {
		           //to.moveRowDown(rowIds[i]);
		         //}
		       //}
			}
	    }
	
		if (moveToBottom) {
			for (i=0; i < rowIds.length; i++) {
				to.moveRowToBottom(rowIds[i]);
			}
		}

		if (!ordered) {
			var colSortInd = to.__sortColumnInd;
			var colSortDir = to.__sortColumnDir;
			if ((colSortInd >= 0) && colSortDir) to.sortRows(colSortInd, to.__sortType[colSortInd], colSortDir);
		}

	} else if (direction == 2 || direction == 3) {
		var pane = rightPane;

		// find selected rows
		var rowIds = getSelectedRows(pane);
		if (rowIds == null) {
			// nothing found
			return false;
		}

		// move rows
		if (direction == 2) {
			// move row(-s) UP
			for (i=0; i < rowIds.length; i++) {
				// Conditions to make sure lower rows don't pass the
				// selected higher rows
				if (i == 0 || pane.getRowIndex(rowIds[i-1])
						< pane.getRowIndex(rowIds[i]) - 1) {
					pane.moveRowUp(rowIds[i]);
				}
			}
		} else if (direction == 3) {
			// move row(-s) DOWN
			var rnum = pane.getRowsNum();
			for (i=rowIds.length - 1; i >= 0; i--) {
				var idx = pane.getRowIndex(rowIds[i]);
				if ( idx + 1 < rnum&& (i == rowIds.length - 1
						|| pane.getRowIndex(rowIds[i+1]) > idx + 1)) {
					pane.moveRowDown(rowIds[i]);
				}
			}
		}
	}
	return false;
}

function getSelectedRows(grid) {
    // find selected rows
    var rowIdsStr = grid.getSelectedId();

    if (rowIdsStr == null) {
      // nothing found
      return null;
    }

    var ids = rowIdsStr.split(',');

    // sort the list by the order of the rows
    ids.sort(function(a, b) {
            return grid.getRowIndex(a) - grid.getRowIndex(b);
        });
    
    return ids;
}
function applyDoubleGridValues(name, grid, columns)
{
    var rowCount = grid.getRowsNum();
    var columnCount = grid.getColumnCount() + 1;

    var dataColumnCount = 0;
    var columnsPos = new Array();
    for (j=0; j < columnCount; j++) {
      if (columns[j]) {
        columnsPos[dataColumnCount] = j;
        dataColumnCount++;
      }
    }

    // Note: the only meta info we pass on server is the size of result Grid
    var value = "" + (dataColumnCount + 1) + "," + rowCount + ",";
    // pack values
    // In order to make value-holder smaller, structure of DoubleGridList is stored on server
    // We don't use escaping for now

    var ids = new Array();
    for (j=0; j < rowCount; j++) {
      ids[j] = grid.getRowId(j);
      value += ids[j] + ",";
      for (i=0; i < dataColumnCount; i++) {
        value += Url.encode(grid.cells(ids[j], columnsPos[i]).getValue()) + ",";
      }
    }

    value += "*";

    document.getElementById(name).value = value;
    //alert("DEBUG: submit value for DoubleGridList - \"" + value + "\"");
}

// Assignee List handler
function handelAssigneeSelection(list)
{
    var roles = new Array();
    var users = new Array();

    // Values of the list can be one of these:
    //  roles-<id>
    //  users-<id>
    //  ignore
    for (var i = 0; i < list.options.length; i++)
    {
    if(!list.options[i].selected) {
        continue;
    }

    // Get first 5 chars
    var value = list.options[i].value;
        var token = value.substring(0, 5);
    if(token == "roles") {
        roles[roles.length] = value.substring(6, value.length);
    } else if(token == "users") {
        users[users.length] = value.substring(6, value.length);
    }
    }

    var rolesField = eval("document.forms[0]." + list.name + "roles");
    rolesField.value = roles.toString();
    var usersField = eval("document.forms[0]." + list.name + "users");
    usersField.value = users.toString();
}

// Used to bring the focus to an object
// The object name must be unique on the page. If it is not we attempt to
// to hit the first one.
function requestFocus(name) {
    try {
        var obj = eval("document.forms[0]." + name);
        //alert(obj);

		// If the object is select do not redefine it
		if(typeof(obj.length) != 'undefined' && typeof(obj.options)=="undefined") {
            obj = obj[0];
        }

        // If the object is not fully visible do not set focus
        // because it causes page to scroll
        if(getTop(obj) + obj.offsetHeight > document.body.clientHeight ||
           getLeft(obj) + obj.offsetWidth > document.body.clientWidth) {
           return;
        }


		//obj.focus();
    } catch(e) {
        // Just ignore any error if we cannot set the focus.
    }
}

// Popup menu stuff
var currentOpenPopup;
var currentOpenSubPopup;
var hideLaterTimer;
var isInsideHeavyWeight;

function clearHideLater() {
  if(hideLaterTimer) {
        clearTimeout(hideLaterTimer);
  }
}

function hideLater() {
  clearHideLater();

  if(isInsideHeavyWeight) {
    return;
  }

  hideLaterTimer = setTimeout('hideAllPopups()', 1000);
}

function hideSubPopup() {
   if(currentOpenSubPopup) {
        currentOpenSubPopup.visibility='hidden';
        currentOpenSubPopup = null;
  }
}

function hideAllPopups() {
  clearHideLater();

  if(currentOpenPopup) {
        if(currentOpenPopup.hide) {
                currentOpenPopup.hide();
        } else {
                currentOpenPopup.visibility='hidden';
        }
        currentOpenPopup = null;
  }

  hideSubPopup();
}

function showTooltip(tooltipParent, tooltip) {
//  var tooltipParentObj = getDocElement(tooltipParent);
//  var tooltipObj = getDocElement(tooltip);
  var tooltipStyle = getDocElement(tooltip).style;

  tooltipStyle.visibility='visible';
}

function hideTooltip(tooltip) {
  var tooltipStyle = getDocElement(tooltip).style;

  tooltipStyle.visibility='hidden';
}

function showPopup(menu, subMenu, postUp, isSecondLevel,isHeavyWeight) {

   clearHideLater();

  // Remove all menus on click other then on the menu itself
  document.onclick = hideAllPopups;

  var menuObj = getDocElement(menu);
  var subMenuObj = getDocElement(subMenu);
  var subMenuStyleObj = getDocElement(subMenu).style;

  if(currentOpenPopup &&
     (currentOpenPopup == subMenuObj ||
     (currentOpenPopup.document && currentOpenPopup.document.sub_menu == subMenuObj))) {
        return;
  }

  if(isSecondLevel) {
        hideSubPopup();
  } else {
        hideAllPopups();
  }

  if(isSecondLevel) {
        if(postUp) {
                subMenuStyleObj.top = menuObj.offsetParent.offsetTop -
                                subMenuObj.offsetHeight + menuObj.offsetHeight;
        } else {
                subMenuStyleObj.top = menuObj.offsetParent.offsetTop;
        }
        subMenuStyleObj.left = menuObj.offsetWidth;
  } else {
        if(postUp) {
                subMenuStyleObj.top =
                        getTop(menuObj) - subMenuObj.offsetHeight;
        } else {
                subMenuStyleObj.top = getTop(menuObj) + menuObj.offsetHeight-2;
        }
        subMenuStyleObj.left = getLeft(menuObj);
  }

  if(!isHeavyWeight) {
        subMenuStyleObj.visibility='visible';
        if(isSecondLevel) {
                currentOpenSubPopup = subMenuStyleObj;
        } else {
                currentOpenPopup = subMenuStyleObj;
        }
  } else {
      currentOpenPopup = window.createPopup();
      var doc = currentOpenPopup.document;
      doc.write("<html>");
      doc.write("<head>");
      doc.write("<link rel='stylesheet' href='style.css' type='text/css'>");
      doc.write("<script language='JavaScript'>");
      doc.write("function exec(name) { eval('window.parent.' + name); }");
      doc.write("</script>");
      doc.write("</head>");
      doc.write("<body style='border: 0' scroll=no marginheight=0 " +
            "marginwidth=0 leftmargin=0 rightmargin=0 topmargin=0>");
      doc.write("<div " +
            "onmouseover='window.parent.isInsideHeavyWeight=true; window.parent.clearHideLater()' " +
            "onmouseout='window.parent.isInsideHeavyWeight=false; window.parent.hideLater()'>");
      doc.write(subMenuObj.innerHTML);
      doc.write("</div>");
      doc.write("</body>");
      doc.write("<script language=JavaScript src='general.js'></script>");
      doc.write("</html>");
      var left = getLeft(menuObj) + 2;
      var top = getTop(menuObj) + menuObj.offsetHeight - document.body.scrollTop + 2;
      if(isSecondLevel) {
          left += menuObj.offsetWidth - 2;
          top -= menuObj.offsetHeight + 2;
      }
      currentOpenPopup.document.sub_menu = subMenuObj;
      currentOpenPopup.show(left, top,
                            subMenuObj.offsetWidth, subMenuObj.offsetHeight,
                            document.body);
  }

  return true;
}

function getLeft(obj) {
  if(document.layers)
  {
        return(obj[x]);
  }
  else
  {
        return(getOffset(obj, 'offsetLeft'));
  }
}

function getTop(obj) {
  if(document.layers)
  {
        return(obj[y]);
  }
  else
  {
        return(getOffset(obj, 'offsetTop'));
  }
}

function getOffset(obj, attr) {
  return(obj.offsetParent ? (getOffset(obj.offsetParent, attr) +
        obj[attr]) : obj[attr]);
}

function getCheckedCheckboxes() {

    var cbox = eval("document.forms[0].checkbox");
    if (cbox != null) {
        var checkedCheckboxes = new Array();
        if(cbox.length) {
            for (i = 0, k = 0; i < cbox.length; i++) {
               if(cbox[i].checked) {
                   checkedCheckboxes[k] = cbox[i];
                   k++;
               }
             }
        } else {
            if(cbox.checked) {
                checkedCheckboxes[0] = cbox;
            }
        }
        return checkedCheckboxes;
    } else {
        return null;
    }
}

// BWB stuff
// Pastes text from source segments to the target segments
function selectBWBRow(rowId) {
  var cbox = eval('document.forms[0].checkbox');
  if (typeof(cbox.length) =='undefined') {
      cbox.checked=true;
      return;
  }  
        
  for(i=0; i < cbox.length; i++){
     if(cbox[i].value == rowId){
        cbox[i].checked=true;
     } else {
        cbox[i].checked=false;
     }
  }
}

function pasteFromSourceSegments(errorString)
{
    var checkedCheckboxes = getCheckedCheckboxes();

    if((checkedCheckboxes == null) || (checkedCheckboxes.length == 0)) {
        alert(errorString);
    } else {
        for (i = 0; i < checkedCheckboxes.length; i++) {
            pasteFromSourceSegment(checkedCheckboxes[i].value);
        }
    }

    hideAllPopups();
}

function performReportError(errorString, popupUrl, popupName, popupStyle)
{
    var checkedCheckboxes = getCheckedCheckboxes();

    if((checkedCheckboxes == null) || (checkedCheckboxes.length == 0)) {
        alert(errorString);
    } else {
        handleButton(true, true, popupUrl, popupName, popupStyle);
    }
}

function performActionOnSegments(errorString, submitUrl)
{
    var checkedCheckboxes = getCheckedCheckboxes();

    if((checkedCheckboxes == null) || (checkedCheckboxes.length == 0)) {
        alert(errorString);
    } else {
        doSubmit(submitUrl);
    }
}

// Opens the current page in the full window (popping out of a frame if it's in one)
function openFullWindow()
{
     if (top.location != self.location) {
        top.location = self.location;
     }
}

// Pastes text from source segment to the target segment
function pasteFromSourceSegment(segmentName)
{
    var srcSeg = eval("document.forms[0].src_segment_" + segmentName);
    var tgtSeg = eval("document.forms[0].tgt_segment_" + segmentName);

    // Our target may be readonly. Skip it in this case
    if(tgtSeg.readOnly) {
        return;
    }

    tgtSeg.value = srcSeg.value;

    // Mark as changed
    tgtSeg.onchange();
}

// Current target segment and it caret position
// Used to be able to paste lookup hits from TM/TD lookup windows
var currentTargetSegment;
var currentCaretPosition;

// Saves current target segment and it caret position
function saveCaretPosition(segment) {
    currentTargetSegment = segment;
    if(segment.createTextRange) {
        currentCaretPosition = document.selection.createRange().duplicate();
    }
}

// Implement all the machinery for tracking segment length
function checkTextLength(segment, callSCP, statusId, maxLength, okMsg, errMsg) {

     var msg;
     var statusLine = getDocElement(statusId);
     var curLength = segment.value.length;

     if(curLength <= maxLength) {
        msg = okMsg.replace("{0}", maxLength-curLength);
     } else {
        msg = errMsg.replace("{0}", curLength-maxLength);
     }

     statusLine.innerHTML = msg;
     statusLine.style.color = (curLength <= maxLength) ? "black" : "red";

     if(callSCP) {
        saveCaretPosition(segment);
     }
}

// Paste text to target segment. Used by BWB Segment TM and Term DB dialogs
function pasteToTargetSegment(segmentName, text, useCaret) {
     var tgtSeg = eval("document.forms[0].tgt_segment_" + segmentName);

     // Our target may be readonly. Skip it in this case
    if(tgtSeg == null || tgtSeg.readOnly) {
        return;
    }

    if (useCaret) {
        if(currentCaretPosition && tgtSeg == currentTargetSegment) {
            var caretPos = currentCaretPosition;
            caretPos.text =
                caretPos.text.charAt(caretPos.text.length - 1) == ' ' ?
                text + ' ' : text;
        } else {
            tgtSeg.value = tgtSeg.value + text;
        }
    } else {
        tgtSeg.value = text;
    }

    // Mark as changed
    tgtSeg.onchange();
}

function getDocElement(obj) {
    if(IE) {
        return eval("document.all." + obj);
    } else {
        return document.getElementById(obj);
    }
}

// Handles jumps from one difference to another in the diff viewer
var currentChange = -1;
function handleDiffJump(isPrev)
{
   var nextChange = currentChange + (isPrev ? -1 : 1);
   var nextChangeSet = getDocElement("change_" + nextChange);

   if(!nextChangeSet) {
       return;
   }

   location.hash='change_' + nextChange;
   currentChange = nextChange;

   // Adjust automatic positioning just a bit for better view
   document.body.scrollLeft = 0;
   document.body.scrollTop = document.body.scrollTop - 10;

   // Update cursor bar
   var diff_cursor = getDocElement('diff_cursor');
   var firstChange = (nextChangeSet.length ? nextChangeSet[0] : nextChangeSet);
   var lastChange = (nextChangeSet.length ?
                      nextChangeSet[nextChangeSet.length - 1] : nextChangeSet);

   var firstTop = getTop(firstChange);
   var lastTop = getTop(lastChange);

   diff_cursor.style.top = firstTop;
   diff_cursor.style.height = lastTop - firstTop + lastChange.offsetHeight
   diff_cursor.style.visibility='visible';
}


function isValidPathOnIE(val) 
{
    if (IE) {
        if (val.charAt(0) != '\\') {
            if (val.length < 2 || val.charAt(1) != ':') {
                return false;
            }
        }
    }

    return true;
}

// Handles adding a new element to an edit list.
// Returns true if element was successfully added.
// Returns false if an error was detected while adding the element.

function handleEditListAdd(list, textField, resField, convertToUpperCase,
                           separator, isFileInput, isSortable)
{
        var val = textField.value;

        // Trim it and check if it is empty
        val = val.replace(/^\s+/,'').replace(/\s+$/,'')
        if(val == '') {
            return false;
        }

        // Note: these IDs are defined in the EditableList widget -- this
        // code must match what's set up there
        var separatorDiv = getDocElement (list.name + "_edit_list_error_separator");
        var dupeDiv = getDocElement (list.name + "_edit_list_error_dupe");
        var invalidPathDiv = getDocElement (list.name + "_edit_list_error_invalid_path");
        var errorDisplayed = false;

        // Turn on the separator error if the value contains a separator
        if (val.indexOf (separator) != -1) {
                separatorDiv.style.display = "block";
                errorDisplayed = true;
        } else {
                separatorDiv.style.display = "none";
        }

        // Turn on the duplicate error if the value is a duplicate
        var dupe = false;
        for (var i=0; i<list.options.length; ++i) {
                if (list.options[i].value.toLowerCase() == val.toLowerCase()) {
                    dupe = true;
                }
        }
        if (dupe) {
                dupeDiv.style.display = "block";
                errorDisplayed = true;
        } else {
                dupeDiv.style.display = "none";
        }

        // Turn on the invalid path error if the value is an invalid path
        // (IE only). CQ 12540.
        // On IE, some invalid paths cause page submission to crash, so detect
        // invalid paths here and report errors on client side.
        // It seems that the only invalid paths that cause IE to crash are those
        // that don't start with a backslash or a drive letter (actually any
        // path with a colon as the second character seems to work).
        //
        // Firefox handles this case fine; submit of invalid paths works fine,
        // so this will be handled on the server instead.

        if (isFileInput && !isValidPathOnIE(val)) {
            invalidPathDiv.style.display = "block";
            errorDisplayed = true;
        }

        // If any error message was displayed, then don't actually add
        if (errorDisplayed) {
            return false;
        }

        if(convertToUpperCase) {
                val = val.toUpperCase();
        }

        // Add new option
        var option = new Option();
        option.value = val;
        option.text = val;
        list.options[list.options.length] = option;

        // Sort the list
        if(isSortable) {
            listBoxSort(list, true);
        }

        // Update resulting value
        var result = '';
        for(var i=0; i<list.options.length; i++) {
                if (i != 0) {
                 result += separator;
                }
               result += list.options[i].value;
        }

        if (!isFileInput) {
            // this is only appropriate for text input
            textField.value = '';
            textField.onkeyup();
        } else {
            var fileUploadDiv = getDocElement (list.name + "_in_progress");
            fileUploadDiv.style.display = "block";
        }
        resField.value = result;
        return true;
}

// handling new conditional/translatable tag
function handleCustomEditableListAdd(list, textField, resField,dropDown, result)
{

        var operation = dropDown.options[dropDown.value-1].text;

        var attributeName = textField.value;
        var attributeValue  = resField.value;

        textField.value = '';
        resField.value = '';


        // Trim it and check if it is empty
        attributeName = attributeName.replace(/^\s+/,'').replace(/\s+$/,'')
        if(attributeName == '') {
           return;
        }

        // Trim it and check if it is empty
        attributeValue = attributeValue.replace(/^\s+/,'').replace(/\s+$/,'')
        if(attributeValue == '') {
           return;
        }

        // Separator '\ue002' must match the separator in EditableCustomList
        attributeName = attributeName.toUpperCase();
        listItemText = attributeName + " " + operation + " " + attributeValue;
        listItemValue =
               attributeName + '\ue002' + operation + '\ue002' + attributeValue;

        // Add new option
        var option = new Option();
        option.text = listItemText;
        option.value = listItemValue;
        list.options[list.options.length] = option;

        // Sort the list
        listBoxSort(list, true);

        // Update resulting value
        var resultArray = new Array();
        for(var i=0; i<list.options.length; i++) {
           resultArray[i] = list.options[i].value;
        }

        result.value = resultArray.toString();

}

// Handles removing of an element from an list box
function handleCustomEditableListRemove(list, textField, resField,result)
{
        // Remove selected options from the list
        var j = 0;
        for (var i = 0; i < list.options.length; i++)
        {
                if (!list.options[i].selected)
                {
                        var option = new Option();
                        option.value = list.options[i].value;
                        option.text = list.options[i].text;

                        list.options[j] = option;
                        j++;
                }
        }
        list.options.length = j;

        // Update resulting value
        var resultArray = new Array();
        for(var i=0; i<list.options.length; i++) {
                resultArray[i] = list.options[i].value;
        }

        result.value = resultArray.toString();
}



// Handles removing of an element from an list box
function handleEditListRemove(list, textField, resField, separator)
{
        // Remove selected options from the list
        var j = 0;
        for (var i = 0; i < list.options.length; i++)
        {
                if (!list.options[i].selected)
                {
                        var option = new Option();
                        option.value = list.options[i].value;
                        option.text = list.options[i].text;

                        list.options[j] = option;
                        j++;
                }
        }
        list.options.length = j;

        // Update resulting value
        var result = '';
        for(var i=0; i<list.options.length; i++) {
                if (i != 0) {
                   result += separator;
                }
                result += list.options[i].value;
        }

        list.onchange();
        resField.value = result;
}


function swapElements(EL, one, two)
{
     var oneEL=document.all[one].style;
     var twoEL=document.all[two].style;
     if (EL.checked) {
       oneEL.display= "inline";
       twoEL.display= "none";
     }
     else {
       oneEL.display= "none";
       twoEL.display= "inline";
     }
}

// This is a refresh function to be called from textarea.onfocus()
// callback in BWB segments and click and edit functionality.
// NOTE: TM and TERM lookup segment constants must match to
//       bwb.MainView TM_LOOKUP_SEGMENT and TERM_LOOKUP_SEGMENT ones
// ADD: concordance search tool ability

function updateLookupWindows(tmUrl, tmName, termUrl, termName, concordanceUrl, concordanceName, segment)
{
     var val = document.forms[0].tm_lookup_segment.value;
     if(val != '' && val != segment) {
        // Different segment is displayed. Update.
        openStandardWindow(tmUrl, tmName, 'small');
     }
     val = document.forms[0].term_lookup_segment.value;
     if(val != '' && val != segment) {
        // Different segment is displayed. Update.
        openStandardWindow(termUrl, termName, 'small');
     }
     val = document.forms[0].concordance_lookup_segment.value;
     if(val != '' && val != segment) {
        // Different segment is displayed. Update.
        openStandardWindow(concordanceUrl, concordanceName, 'editorsize');
     }
}


// Change Assignees Logic

var roleString = "roleId";
var userString = "userId";

/**
 * Unchecks the role with the specified id.
 */
function uncheckRole(roleId) {

    var roles = eval("document.forms[0]." + roleString);

    // if there is a single role listed
    if (roles.length == undefined) {

        roles.checked = false;
        return;
    }

    // if there are more roles listed
    for (var i = 0; i < roles.length; i++) {

        if (roles[i].value == roleId) {

            roles[i].checked = false;
            return;
        }
    }
}

/**
 * Determines if the role with the specified id is checked.
 */
function roleChecked(roleId) {

    var roles = eval("document.forms[0]." + roleString);

    // if there is a single role listed
    if (roles.length == undefined) {

        return roles.checked;
    }

    // if there are more roles listed
    for (var i = 0; i < roles.length; i++) {

        if (roles[i].value == roleId) {

            return roles[i].checked;
        }
    }

    return false;
}

/**
 * Unchecks the users that belong to the specified role.
 */
function uncheckUsers(roleId) {

    var users = eval("document.forms[0]." + userString + roleId);

    // if there is a user listed in the specified role
    if (users.length == undefined) {

        users.checked = false;
        return;
    }

    // if there are more users listed in the specified role
    for (var i = 0; i < users.length; i++) {

        users[i].checked = false;
    }
}

/**
 * Checks all users with the same id (across all roles).
 */
function checkSameUsers(userId) {

    var elements = document.forms[0].elements;

    // search for users with the same id
    for (var i = 0; i < elements.length; i++) {

        elements[i].name.indexOf(userString)

        if (elements[i].name.indexOf(userString) != -1
            && elements[i].value == userId) {

            var roleId =
                elements[i].name.substring(userString.length, elements[i].name.length);

            if (!roleChecked(roleId)) {
                elements[i].checked = true;
            }
        }
    }
}
/**
 * Returns the base URL of World Server
   it looks like http://hostname/ws
*/
function getBaseURL() {

    var baseUrl = window.location.href;
    var index = baseUrl.indexOf('?');
    baseUrl = baseUrl.substring(0,index);
    var lastIndex = baseUrl.lastIndexOf('/');
    baseUrl = baseUrl.substring(0,lastIndex);
    return baseUrl;
}

/**
 * popus a small popup window of the specified size and lods an image
 * inside of thuis window
*/
function popupImageWindow(src, width, height) {
     var newWindow =
         window.open(src, 'wsImageWindow',
                     'toolbar=no,width='+width+',height='+height);
      newWindow.document.write('<html><head><title>Image<\/title><\/head>' +
                               '<body background="' + src +
                               '"><\/body><\/html>');
      newWindow.resizeBy(width - newWindow.document.body.clientWidth,
                         height - newWindow.document.body.clientHeight);
      newWindow.focus();
}

function chooseColumn(column, rows) {

    var disableColumn = (column == 1);

    document.forms[0].task_expected_duration.disabled = !disableColumn;
    document.forms[0].task_expected_duration_unit[0].disabled = !disableColumn;
    document.forms[0].task_expected_duration_unit[1].disabled = !disableColumn;
    document.forms[0].task_due_date.disabled = disableColumn;

    for (var i = 0; i < rows; i++) {

        var input = eval('document.forms[0].task_step_' + i + '_expected_duration');
        input.disabled = !disableColumn;

        input = eval('document.forms[0].task_step_' + i + '_expected_duration_unit[0]');
        input.disabled = !disableColumn;

        input = eval('document.forms[0].task_step_' + i + '_expected_duration_unit[1]');
        input.disabled = !disableColumn;

        input = eval('document.forms[0].task_step_' + i + '_due_date');
        input.disabled = disableColumn;
    }
}

function setDisabledElements(name, disable) {
    var form = document.forms[0];
    var elements = document.getElementsByName(name);
    for (i=0; i<elements.length; i++) {
        elements[i].disabled = disable;
    }

    // set disabled attr for check all box as well if it exits
    // The correct check all box will have id equal to name
    var checkAll = form.checkAllBox;
    if(checkAll.length) {
       for (i = 0; i < checkAll.length; i++) {
         if(checkAll[i].id == name) {
            checkAll = checkAll[i];
            break;
         }
       }
    }

    if (checkAll != null) {
        checkAll.disabled = disable;
    }
}

function validInputChar(e, charSet) {
	var key;
	var keychar;

	if (window.event)
	   key = window.event.keyCode;
	else if (e)
	   key = e.which;
	else
	   return true;

	keychar = String.fromCharCode(key);
	keychar = keychar.toLowerCase();

	if ((key==null) || (key==0) || (key==8) ||
	    (key==9) || (key==13) || (key==27) )
	   return true; // control keys
	else if ((charSet.indexOf(keychar) > -1))
	   return true; // permitted character
	else
	   return false;
}

function noEnter(aEvent) {
	return !(aEvent.keyCode == 13);
}

function loadSubset(destId, url)
{
    loadSubset(destId, url, null);
}

// AJAX enabler. Call this function with the id of the element whose contents
// you want to replace with the HTML that is returned from the given url. The
// url should return a HTML fragment that will be a child of the specified
// element.
function loadSubset(destId, url, dataFields)
{
    // we use a javascript feature here called "inner functions" using
    // these means the local variables retain their values after the
    // outer function has returned. this is useful for thread safety,
    // so reassigning the onreadystatechange function doesn't stomp
    // over earlier requests.

    function ajaxCallback()
    {
        if (ajaxRequestObj.readyState == 4) {
            if (ajaxRequestObj.status == 200) {
                document.getElementById(ajaxReplaceId).innerHTML =
                   ajaxRequestObj.responseText;
            } else {
                alert("There was a problem retrieving data:\n" +
                      ajaxRequestObj.status + ":\t" + ajaxRequestObj.statusText + "\n" +
                      ajaxRequestObj.responseText);
            }
        }
    }

    // use a local variable to hold our request and callback until the
    // inner function is called...
    var ajaxRequestObj = createAjaxRequestObject();
    var ajaxReplaceId = destId;

    // prepopulate query params with data from
    if (dataFields && dataFields.length > 0) {
        // add query string marker if it wasn't set previously
        if (url.indexOf("?") == -1) {
            url += '?';
        }
		
		url += getParamsAsString(dataFields);
    }

    sendAjaxRequest(ajaxRequestObj, url, ajaxCallback);
}

function getParamsAsString(dataFields){	
	var urlParams = "";
    if (dataFields && dataFields.length > 0) {
		
		function getParamAsSting(p){
			var useCurrentParam = ((p.type.toUpperCase() != "CHECKBOX") || (p.checked));
			var paramValue = p.value;
			if (useCurrentParam) {
				return "&" + paramName + "=" + Url.encode(paramValue);
			} 
			return "";			
		}
		
        for (i=0; i < dataFields.length; i++) {
            var paramObj = dataFields[i];

            var paramName;
            var paramField;
            if (paramObj instanceof Array) {
                paramName = paramObj[0];
                paramField = document.forms[0].elements[paramObj[1]];
            } else {
                paramName = paramObj;
                paramField = document.forms[0].elements[paramName];
            }
			
			if (typeof (paramField) != "undefined"){
				if (typeof (paramField.type) == "undefined" 
						&& typeof (paramField.length) != "undefined"){
					for (var j=0; j<paramField.length; j++){
						urlParams += getParamAsSting(paramField[j]);
					}
				} else {
					urlParams += getParamAsSting(paramField);
				}
			}

        }
    }
	
	return urlParams;
}

function createAjaxRequestObject()
{
    if (window.XMLHttpRequest) {
        // moz et al
        return new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        // ie
        return new ActiveXObject("Microsoft.XMLHTTP");
    }

    return null;
}

function sendAjaxRequest(ajaxRequestObj, url, ajaxCallback)
{

    function ajaxCallbackStub()
    {
        if (isValidResponse(ajaxRequestObj)) {
                // OK, do nothing
        }
    }

    if (!url) return;

    if (!ajaxRequestObj) ajaxRequestObj = createAjaxRequestObject();

    if (!ajaxCallback && ajaxRequestObj) ajaxCallback = ajaxCallbackStub;

    // should not happen
    if (!ajaxRequestObj && !ajaxCallback) return;

    ajaxRequestObj.onreadystatechange = ajaxCallback;
    ajaxRequestObj.open("GET", url, true);

    if (window.XMLHttpRequest) {
        // moz et al
        ajaxRequestObj.send(null);
    } else if (window.ActiveXObject) {
        // ie
        ajaxRequestObj.send();
    }
}

function isValidResponse(ajaxObj) {
    if (ajaxObj.readyState == 4) {
        if (ajaxObj.status == 200) {
            return true;
        } else {
            alert("There was a problem retrieving data:\n" +
                  ajaxObj.status + ":\t" + ajaxObj.statusText + "\n" +
                  ajaxObj.responseText);
        }
    }

    return false;
}

// Tool for URL encoding/decoding using UTF-8 charset
var Url = {

    // public method for url encoding
    encode : function (string) {
        return escape(this._utf8_encode(string));
    },

    // public method for url decoding
    decode : function (string) {
        return this._utf8_decode(unescape(string));
    },

    // private method for UTF-8 encoding
    _utf8_encode : function (string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    },

    // private method for UTF-8 decoding
    _utf8_decode : function (utftext) {
        var string = "";
        var i = 0;
        var c = c1 = c2 = 0;

        while ( i < utftext.length ) {

            c = utftext.charCodeAt(i);

            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            }
            else if((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i+1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            }
            else {
                c2 = utftext.charCodeAt(i+1);
                c3 = utftext.charCodeAt(i+2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }

        }

        return string;
    }

}

function handleClientFolderUpdate() {
    handleClientFolderUpdate(false);
}

function handleClientFolderUpdate(checkAutoFillMode) {
    if (__client_general_useLocationAutoFill && checkAutoFillMode) {
        // update Client Folder value from Client Name attribute
        document.getElementById('clientFolder').value = document.getElementById('name').value;
        // update Client AIS path in hint
    }

    var hintSpan = document.getElementById('clientFolder_hint_loc');
    if (hintSpan) {
        var clientsLocation = document.getElementById('clientsLocation').value;
        var clientFolder = document.getElementById('clientFolder').value;

        // apply the same rules for AIS paths as on server side  // actully we can use AJAX to handle this stuff, but it seems to be overhead
        // 1. validate clientsLocation
        if (clientsLocation.length > 0 && clientsLocation.charAt(clientsLocation.length - 1) != '/')
            clientsLocation += '/';
        // -- there is no need to validate clientFolder since it's forbidden to enter slashs for that field

        // 3. compose new path
        var newAISPath = clientsLocation + clientFolder;

        hintSpan.innerHTML = newAISPath;
    }
}

function trimString(str) {
    return str.replace(/^\s*/, "").replace(/\s*$/, "");
}

// Used to create dummy links (for arrows in Double Lists) that browser
// won't follow.
// On some pages (Quotes) in IE only, browser was still following the
// empty href link for arrows, leaving the current page, even if onclick
// javascript returned false.
//
// CQ 14352: HTTP 404 error when selecting values for
// multiselector project/quote attribute.

function noop()
{
}


// ================= File Upload helper methods
// QuoteBasedRenderer :: AJAX :: refresh component view with new model state
function ufcRefreshView(ufcName) {
    ufcUpdateModel(ufcName, "noop", null, null, true);
}

// QuoteBasedRenderer :: AJAX :: modify model state and optionally refresh component view
function ufcUpdateModel(ufcName, op, param, extParam, refreshView) {
    var ajaxObj = createAjaxRequestObject();

    function refreshViewFunc() {
        if (isValidResponse(ajaxObj)) {
            // in some cases renderer may want to paint it's state partitially into
            // some part of it's view in user browser
            var targetViewPaneId = ajaxObj.getResponseHeader("_ufc_custom_target_view_pane_id");
            // if not - just replace currently rendered view with new content
            if (!targetViewPaneId) {
                targetViewPaneId = ufcName + "_view";
            }

            var targetViewPane = document.getElementById(targetViewPaneId);
            if (targetViewPane) {
                var responseText = ajaxObj.responseText;
                if (responseText == '') {
                    targetViewPane.style.display = 'none';
                } else {
                    targetViewPane.style.display = 'block';
                }

                targetViewPane.innerHTML = responseText;
            }
        }
    }

    // user login session token
    var sessionToken = document.forms[0].elements[ufcName + "_sessionToken"].value;
    // user data session token
    var persistToken = document.forms[0].elements[ufcName + "_persistToken"].value;

    sendAjaxRequest(ajaxObj, "fileupload?" + ufcConstructQueryString(ufcName, sessionToken, persistToken, op, param, extParam, refreshView), refreshViewFunc);
}

// QuoteBasedRenderer :: AJAX :: construct query string for the File Upload Servlet
function ufcConstructQueryString(ufcName, sessionToken, persistToken, op, param, extParam, refreshView) {
    var queryString =
           "&name=" + ufcName + "&token=" + sessionToken + "&" + ufcName + "_persistToken=" + persistToken +
           "&renderModelState=" + refreshView;

    queryString += "&op=" + op;
    if (op == "removeEntry") {
        queryString += "&entryName=" + encodeURIComponent(param);
    } else if (op == "removeEntriesGroup") {
        queryString += "&entryNames=" + encodeURIComponent(param);
    } else {
        // unsupported operation, do nothing
    }

    // extended parameter, could be specific per File Upload Renderer
    if (extParam) {
        queryString += "&extParam=" + extParam;
    }

    return queryString;
}

// ================= File Upload :: Advanced File Upload Renderer helper methods
// AdvancedFileUploadRenderer :: delete entry
function ufcQbrRemoveEntry(ufcName, entryName, groupName) {
    // target view pane id will be passed as an external attribute for the AJAX FileUploadServlet
    ufcUpdateModel(ufcName, "removeEntry", entryName, ufcQbrGetGroupType(groupName), true);
}

// AdvancedFileUploadRenderer :: delete entry group
function ufcQbrRemoveEntryGroup(ufcName, groupName) {
    var entryNames = document.forms[0].elements[ufcName + "_" + groupName].value;
    entryNames = entryNames.replace(/\uE001\uE002/gm, ",");

    // target view pane id will be passed as an external attribute for the AJAX FileUploadServlet
    ufcUpdateModel(ufcName, "removeEntriesGroup", entryNames, ufcQbrGetGroupType(groupName), true);
}

// AdvancedFileUploadRenderer :: get group type by group name
function ufcQbrGetGroupType(groupName) {
    var entryType;
    if (groupName == "oldEntries") {
        entryType = "old";
    } else if (groupName == "userComputerEntries" || groupName == "aisEntries") {
        entryType = "new";
    }
    return entryType;
}

// AdvancedFileUploadRenderer :: update Upload button state to [enabled/disabled]
function ufcQbrUpdateUploadButton(ufcName) {
    var enabled = false;
    // weird, but getDocElement doesn't work, after we've added another one file uplaod entry...
    // so use document.getElementById
    var simpleItemUpload = document.getElementById(ufcName + "_item");
    var aisItemUpload = document.getElementById(ufcName + "_aisItem");

    var useSimpleUpload = ufcQbrIsSimpleMode(ufcName);

    if (useSimpleUpload) {
      // use file upload from user computer
      enabled |= simpleItemUpload.value.length > 0 &&
                 simpleItemUpload.parentNode.style.display != 'none';
    } else {
      // use file upload from WS/AIS
      enabled |= aisItemUpload.value.length > 0 &&
                 aisItemUpload.parentNode.parentNode.style.display != 'none';
    }

    if (useSimpleUpload) {
      // use file upload from user computer
      var count = document.forms[0].elements[ufcName + '_item_ext_count'].value;
      for (i=0; (i < count) && !enabled; i++) {
        var extItemUpload = getDocElement(ufcName + "_item_ext_" + i);
        if (extItemUpload) enabled |= extItemUpload.value.length > 0;
      }
    } else {
      // use file upload from WS/AIS
      var count = document.forms[0].elements[ufcName + '_aisItem_ext_count'].value;
      for (i=0; (i < count) && !enabled; i++) {
        var extAisUpload = getDocElement(ufcName + "_aisItem_ext_" + i);
        if (extAisUpload) enabled |= extAisUpload.value.length > 0;
      }
    }

    getDocElement(ufcName + "_upload").disabled = !enabled;
}

// AdvancedFileUploadRenderer :: add another upload field
function ufcQbrAddAnotherFileUploadField(ufcName, fieldNameSuffix, addAnotherLinkObj) {
    // find original upload pane/field
    var parent = addAnotherLinkObj.parentNode;
    var sourcePane = parent.firstChild;

    var sourceInputField = document.getElementById(ufcName + "_" + fieldNameSuffix);
    // prepare extended upload field counter
    var fieldCounter = document.forms[0].elements[ufcName + '_' + fieldNameSuffix + '_ext_count'];

    var sourceInputFieldId = sourceInputField.id;
    var newInputFieldId = ufcName + "_" + fieldNameSuffix + "_ext_" + fieldCounter.value;

    // update source field with new id to be copied for new upload field
    sourceInputField.id = newInputFieldId;
    sourceInputField.name = sourceInputField.id;

    // create new input field
    var newPane = sourcePane.cloneNode(true);
    // set original id/name back to source input field
    sourceInputField.id = sourceInputFieldId;
    sourceInputField.name = sourceInputField.id;
    // increase field counter
    fieldCounter.value++;

    if (fieldNameSuffix == 'aisItem') {
      // the code below might look ugly since it brokes mechanism encapsulation for popup link composing
      // at AIS Path Browser component
      // the only problem we have now is the need to keep the code in sync with AIS Path Browser component
      //getDocElement(newInputFieldId).setAttribute("targetFieldId", newInputFieldId);
    }

    // set new onclick handler for delete link - should remove the upload field instead of hiding it
    newPane.childNodes[newPane.childNodes.length - 2].onclick =
        function () {domRemoveNode(newPane); ufcQbrUpdateUploadButton(ufcName)};
    // make component visible (in case if source pane was previously hidden)
    newPane.style.display = 'block';
    parent.insertBefore(newPane, parent.lastChild);

    // clear previosly set value
    getDocElement(newInputFieldId).value = '';
}

// AdvancedFileUploadRenderer :: upload data
function ufcQbrDoUpload(ufcName) {
    var itemPath = getDocElement(ufcName + "_item").value;

    var invalidPathOnIE = (itemPath && itemPath.length > 0  && !isValidPathOnIE(itemPath));
    // count of field for file uploading from user computer
    var count = document.forms[0].elements[ufcName + '_item_ext_count'].value;
    for (i=0; (i < count) && !invalidPathOnIE; i++) {
        var elem = document.getElementById(ufcName + "_item_ext_" + i);
        if (elem) {
            var itemPath = elem.value;
            invalidPathOnIE |= (itemPath && itemPath.length > 0  && !isValidPathOnIE(itemPath));
        }
    }

    if (invalidPathOnIE) {
        getDocElement(ufcName + "_edit_list_error_invalid_path").
            style.display = 'block';
        return false;
    }

    getDocElement(ufcName + "_upload").disabled=true;
    getDocElement(ufcName + "_in_progress").style.display = 'block';

    var itemPane = document.getElementById(ufcName + "_item").parentNode;
    var aisItemPane = document.getElementById(ufcName + "_aisItem").parentNode.parentNode;

    // remove upload fields in inactive state
    if (ufcQbrIsSimpleMode(ufcName)) {
        domRemoveNode(aisItemPane);

        var count = document.forms[0].elements[ufcName + '_aisItem_ext_count'].value;
        for (i=0; (i < count) && invalidPathOnIE; i++) {
            var elem = getDocElement(ufcName + "_aisItem_ext_" + i);
            if (elem) domRemoveNode(elem.parentNode);
        }

        // remove file/ais upload fields if they were previously hidden
        if (itemPane.style.display == 'none') domRemoveNode(itemPane);
    } else {
        domRemoveNode(itemPane);

        var count = document.forms[0].elements[ufcName + '_item_ext_count'].value;
        for (i=0; i < count; i++) {
            var elem = getDocElement(ufcName + "_item_ext_" + i);
            if (elem) domRemoveNode(elem.parentNode);
        }

        // remove file/ais upload fields if they were previously hidden
        if (aisItemPane.style.display == 'none') domRemoveNode(aisItemPane);
    }

    doSubmit(ufcName + "_addfile");
}

// AdvancedFileUploadRenderer :: check what kind of data is going to be uploaded now - from user computer of AIS
function ufcQbrIsSimpleMode(ufcName) {
  return document.forms[0].elements[ufcName + "_uploadFilterMode"][0].checked;
}

// ========================= DOM Helper methods
function domClearContainerNode(node) {
  while (node.childNodes.length >= 1) {
    node.removeChild(node.firstChild);
  }
}

function domRemoveNodeById(nodeId) {
  domRemoveNode(getDocElement(nodeId));
}

// Note: removeNode function is already declared for IE 6.0
//       that's "dom" suffix is used for function name
function domRemoveNode(node) {
  if (node) {
    var parentNode = node.parentNode;
    if (parentNode) {
      parentNode.removeChild(node);
    }
  }
}

function domReplaceNode(oldNode, newNode) {
    if (oldNode && oldNode.parentNode) {
        oldNode.parentNode.replaceChild(newNode, oldNode);
    }
}