// <BEGIN COMMON METHODS>

// Convert an array to a nsIMutableArray
function arrayToNsIMutableArray(arr, wrapElements) {

    // If the array is null, then return a blank nsIMutableArray
    if (!arr) {
        return Components.classes["@mozilla.org/array;1"].createInstance(nsIMutableArray);
    }

    // If we are already a nsIArray, then return it now
    if (arr.QueryInterface && arr.enumerate) {
        return arr;
    }

    // Convert the array
    var newArr = Components.classes["@mozilla.org/array;1"].createInstance(nsIMutableArray);
    arr.forEach(function(element) {
        if (element instanceof String || typeof element === "string") {
            var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(nsISupportsString);
            if (element instanceof String) {

                // JavaScript has two types of strings: object and primitive; convert to primitive
                element = element.valueOf();
            }
            str.data = element;
            element = str;
        } else if (element instanceof Object && wrapElements) {
            element.wrappedJSObject = element;
        }
        newArr.appendElement(element, false);
    });
    return newArr;
}

// Convert an array into a nsISupportsArray
function arrayToNsISupportsArray(arr, wrapElements) {

    // If the array is null, then return a blank nsISupportsArray
    if (!arr) {
        return Components.classes["@mozilla.org/supports-array;1"].createInstance(nsISupportsArray);
    }

    // If we are already a nsISupportsArray, then return it now
    if (arr.QueryInterface && arr.DeleteLastElement) {
        return arr;
    }

    // Convert the array
    var newArr = Components.classes["@mozilla.org/supports-array;1"].createInstance(nsISupportsArray);
    arr.forEach(function(element) {
        if (element instanceof String || typeof element === "string") {
            var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(nsISupportsString);
            if (element instanceof String) {

                // JavaScript has two types of strings: object and primitive; convert to primitive
                element = element.valueOf();
            }
            str.data = element;
            element = str;
        } else if (element instanceof Object && wrapElements) {
            element.wrappedJSObject = element;
        }
        newArr.AppendElement(element);
    });
    return newArr;
}

// Convert a nsIArray to an array, optionally unwrapping elements and placing them
// into rewrap when rewrap is not null
function nsIArrayToArray(arr, rewrap) {

    // If array is null, return a blank array
    if (!arr) {
        return Array();
    }

    // If the array is not a nsIArray, then return it, assuming that it's already
    // a JavaScript array
    if (!arr.QueryInterface) {
        return arr;
    }

    // Convert the array
    var newArr = Array(arr.length);
    var arrEnum = arr.enumerate();
    var next;
    var i = 0;
    var notAStringArray = false;
    while (arrEnum.hasMoreElements()) {
        next = arrEnum.getNext();
        if (next.wrappedJSObject) {
            next = next.wrappedJSObject;

            // If we were given a rewrap array, then unwrap
            // this element now
            if (rewrap && next.wrappedJSObject) {
                next.wrappedJSObject = undefined;
                rewrap.push(next);
            }
        } else if (!notAStringArray) {
            try {

                // If this is a string, then extract the string
                next = next.QueryInterface(nsISupportsString).toString();
            } catch (e) {
                notAStringArray = true;
            }
        }
        newArr[i++] = next;
    }
    return newArr;
}

// <END COMMON METHODS>