function getServerParams(syncNode)
{
    var params = syncNode.getAttribute('upload') + "=1"
    
    // scan through the syncNode descendants for
    // nodes with 'uploadval' attributes
    
	var currNode = syncNode;
	
	while (currNode != null)
	{
		if (currNode.nodeType == 1)
		{
		    if (currNode.hasAttribute('uploadval'))
		    {
		        params += "&" + getUploadString(currNode);
		    }
		}
		
		// Depth first search for next node
		if (currNode.firstChild)
		{
		    currNode = currNode.firstChild;
		}
		else if (currNode.nextSibling)
		{
		    currNode = currNode.nextSibling;
		}
		else 
		{
		    while (!currNode.nextSibling && currNode.parentNode != syncNode)
		    {
		        currNode = currNode.parentNode;
		    }		
		    
		    if (currNode.nextSibling)
		    {
	            currNode = currNode.nextSibling;
	        }
	        else
	        {
		        break;
		    }
		}
    }
    
    return params;
}

function xmlToString(xml)
{
    var output = "<" + xml.nodeName;
    
    if (xml.attributes != null)
    {
        for (var i = 0; i < xml.attributes.length; i++)
        {
            output += " " + xml.attributes[i].name + "='" + xml.attributes[i].value + "'";
        }
    }
    
    output += ">";
    
    if (xml.childNodes != null)
    {
        for (var i = 0; i < xml.childNodes.length; i++)
        {
            if (xml.childNodes[i].nodeType == 1)
            {
                // element
                output += xmlToString(xml.childNodes[i]);
            }
            else if (xml.childNodes[i].nodeType == 3)
            {
                // text
                output += "<text>" + xml.childNodes[i].textContent + "</text>";
            }
        }
    }
        
    if (xml.nodeValue != null)
    {
        output += xml.nodeValue;
    }
    
    output += "</" + xml.nodeName + ">";

    return output;
}

function getUploadString(currNode)
{
    switch (currNode.nodeName.toLowerCase())
    {
    case 'textarea':
        return currNode.getAttribute('uploadval') + "=" + escape(currNode.value);
        break;
        
    case 'input':
        return currNode.getAttribute('uploadval') + "=" + escape(currNode.value);
        break;
        
    default:
        return currNode.nodeName + "=?";
        break;
    }
}

function newElement(type, attributes, textContent, children, innerHTML)
{
    var newNode = document.createElement(type);

	for (var a in attributes) 
	{
		newNode.setAttribute(a, attributes[a]);
    }
    
    if (textContent)
    {
        newNode.textContent = textContent;
    }
    
    for (var a in children)
    {
        if (children[a].nodeType != null)
        {
            // It's a node
            newNode.appendChild(children[a]);
        }
        else
        {
            newNode.appendChild(newElement(children[a][0], children[a][1], children[a][2], children[a][3], children[a][4]));
        }
    }
    
    if (innerHTML != null)
    {
        newNode.innerHTML = innerHTML;
    }
    
    return newNode;
}

function getGroupRoot(node, val)
{
    // Find the ancestor with the appropriate group value.
    while (node != null && node.getAttribute('group') != val)
    {
        node = node.parentNode;

        if (node.nodeType == 9)
        {
            node = null;
            break;
        }
    }

    return node;
}

function getUploadRoot(node)
{
    // Find the ancestor with the appropriate group value.
    while (node != null && !node.hasAttribute('upload'))
    {
        node = node.parentNode;

        if (node.nodeType == 9)
        {
            node = null;
            break;
        }
    }

    return node;
}

function getCardHTML(xml)
{
    var topLine = "<tr><td style=\"text-align:left;\">" + xml.getAttribute('name') + "</td><td style=\"text-align:right;\">" + convertCost(xml.getAttribute('cost')) + "</td></tr>";

    var childElems = new Array(
        ["table", {border:0, style:'font-size:12;width:180;'}, null, null, topLine],
        ["br", {}],
        ["br", {}],
        ["div", {}, xml.getAttribute('type')]);
        
    var rules = convertMarkup(xml.getAttribute('rules'));
    
    if (rules != null)
    {
        childElems = childElems.concat(rules);
    }
    else
    {
        childElems.push(["text", {}, xml.getAttribute('rules')]);
    }

    childElems.push(
        ["div", {style:"text-align:right;"}, xml.getAttribute('pt')]);
    
    var result = ["div", {style:"font-family:'Courier New';text-align:left;font-size:12;width:180;"}, null, childElems];

    return result;
}

function breakLine(input, maxLen)
{
    // Break the line of text
    var retval = [];
    
    var startpos = 0;
    var currpos = 0;
    var testpos = input.indexOf(' ', currpos);
    while (testpos >= 0)
    {
        // Find the next space that's under the maxLen
        while (testpos >= 0 && testpos - startpos < maxLen)
        {
            currpos = testpos + 1;
            testpos = input.indexOf(' ', currpos);
        }
        
        if (testpos < 0)
        {
            // Finish the line
            retval.push(["div", {}, input.slice(startpos, input.length)]);
        }
        else if (currpos == startpos)
        {
            // if it's a very long word, allow it anyway
            retval.push(["div", {}, input.slice(startpos, testpos)]);
            startpos = testpos;
            currpos = startpos + 1;
        }
        else
        {
            retval.push(["div", {}, input.slice(startpos, currpos)]);
            startpos = currpos;
            currpos = startpos + 1;
        }
        testpos = input.indexOf(' ', currpos);
    }
    
    return retval;
}

// Return the markup for a comment or card text.
// Convert <card>foo</card> to <button>foo</button>
// Convert <b>foo</b> to bold
// Convert <i>foo</i> to italic
// Convert <sym>*</sym> as appropriate
function convertMarkup(input)
{
    var result = null;
    var xmlDoc = null;
    
    // Ensure it's valid xml by enclosing in a root node
    input = "<root>" + input + "</root>";
    
    try
    {
        if (window.DOMParser)
        {
            parser = new DOMParser();
            xmlDoc = parser.parseFromString(input, "text/xml");
            if (xmlDoc.documentElement.nodeName == "parsererror")
            {
                xmlDoc = null;
            }
        }
        else 
        {
            // Internet Explorer
            xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
            xmlDoc.async = "false";
            xmlDoc.loadXML(input);
            if (xmlDoc.parseError.errorCode != 0)
                xmlDoc = null;
        } 
    }
    catch(e)
    {
        xmlDoc = null;
    }
        
    if (xmlDoc != null)
    {
        // Ignore the enclosing "document" element
        var result = convertNode(xmlDoc.firstChild);
    }
    
    return result;
}

function convertNode(inputNode)
{
    var output = new Array();
    
    // Parse through the xml
    // Throw out nodes that aren't permitted
    // Convert nodes that need converting.
    for (var i = 0; i < inputNode.childNodes.length; i++)
    {
        if (inputNode.childNodes[i].nodeType == 3)
        {
            // Text node - check for newlines and put in corresponding <br/>
            var startPos = 0;
            var currText = inputNode.childNodes[i].nodeValue;
            
            var currPos = currText.indexOf('\n');
            while (currPos > -1)
            {
                // Found an endline.
                var currTextNode = document.createTextNode(
                    currText.substring(startPos, currPos));
                var breakNode = newElement("br", {});
                
                // Prepend nodes for the text before the break, and the break.
                output.push(currTextNode);
                output.push(breakNode);

                startPos = currPos + 1;
                currPos = currText.indexOf('\n', startPos);
            }
            
            // Finally, replace the node value with the last bit of text
            var lastbit = currText.substring(startPos);
            if (lastbit != null && lastbit.length > 0)
            {
                output.push(document.createTextNode(lastbit));
            }
        }
        else if (inputNode.childNodes[i].nodeName == "card")
        {
            // Convert to a card
            var cardName = inputNode.childNodes[i].textContent;
            var newChild = newElement("a", {href:"?mtg_card_name=\"" + cardName + "\""}, cardName);
            output.push(newChild);
        }
        else if (inputNode.childNodes[i].nodeName == "sym")
        {
            // Convert to the appropriate symbol
            var hrefVal = getSymbolUrl(inputNode.childNodes[i].textContent);
            var newChild = newElement("img", {"src":hrefVal}, null);
            
            output.push(newChild);
        }
        else if (inputNode.childNodes[i].nodeName == "b" || inputNode.childNodes[i].nodeName == "i")
        {
            // These elements are fine.
            // Recursively add the children
            var newChildren = convertNode(inputNode.childNodes[i]);
            var currElem = output.push(
                newElement(inputNode.childNodes[i].nodeName, {}, null, newChildren));
        }
        else if (inputNode.childNodes[i].nodeName == "br")
        {
            // Break is fine.
            output.push(newElement("br", {}));
        }
        else
        {
            // Don't know the node type; ignore it.
        }
    }
    
    return output;
}

function convertCost(cost)
{
    var result = "";
    for (var i = 0; i < cost.length; i++)
    {
        var sym = cost[i];
        if ((i + 3 < cost.length) && cost[i] == '[' && cost[i + 3] == ']')
        {
            sym = cost.substring(i, i + 4);
            i += 3;
        }
        else if ((i + 4 < cost.length) && cost[i] == '(' && cost[i + 2] == '/' && cost[i + 4] == ')')
        {
            sym = cost.substring(i, i + 5);
            i += 4;
        }
        
        result += "<img src='" + getSymbolUrl(sym) + "'/>";
    }
    return result;
}

function getSymbolUrl(sym)
{
    // Remove any square brackets if necessary
    if (sym.length == 4 && sym[0] == '[' && sym[3] == ']')
    {
        sym = sym[1] + sym[2];
    }
    else if (sym.length == 5 && sym[0] == '(' && sym[2] == '/' && sym[4] == ')')
    {
        sym = sym[1] + sym[3];
    }
    
    switch (sym.toLowerCase())
    {
    case 'gr':
    case 'wg':
    case 'uw':
    case 'bu':
    case 'rb':
    case 'gb':
    case 'ug':
    case 'ru':
    case 'wr':
    case 'bw':
        // Got the hybrid symbols, but they're in the wrong order
        sym = sym[1] + sym[0];
        // Fall through
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
    case '10':
    case '11':
    case '12':
    case '13':
    case '14':
    case '15':
    case '16':
    case 'x':
    case 'r':
    case 'g':
    case 'w':
    case 'u':
    case 'b':
    case 's':
    case 'p':
    case 'rg':
    case 'gw':
    case 'wu':
    case 'ub':
    case 'br':
    case 'bg':
    case 'gu':
    case 'ur':
    case 'rw':
    case 'wb':
        hrefVal = "images/Mana" + sym.toLowerCase() + ".gif";
        break;

    case '2r':
    case '2g':
    case '2w':
    case '2u':
    case '2b':
        hrefVal = "images/Mana" + sym.toLowerCase() + ".png";
        break;

    case 't':
        hrefVal = "images/Tap.gif";
        break;
        
    case 'q':
        hrefVal = "images/Untap.gif";
        break;
    }
    
    return hrefVal;
}

function getWizardsUrl(cardname)
{
    // Convert spaces and hyphens to underscores, remove apostrophes and commas.
    cardname = cardname.replace(/\ /g, "_");
    cardname = cardname.replace(/-/g, "_");
    cardname = cardname.replace(/\'/g, "");
    cardname = cardname.replace(/,/g, "");
    
    return "http://www.wizards.com/global/images/magic/general/" + cardname + ".jpg";
}

function htmlspecialchars(string)
{
    var result = "";
    for (i = 0; i < string.length; i++)
    {
        switch (string[i])
        {
        case '<':
            result += "&lt;";
            break;

        case '>':
            result += "&gt;";
            break;
        
        case '\"':
            result += "&quot;";
            break;
            
        case "\'":
            result += "&#039;";
            break;
            
        case "&":
            result += "&amp;";
            break;
        
        default:
            result += string[i];
            break;
        }
    }
    
    return result;
}
