var ID_DELIM = "|||";

function onFSCommand(command, args) {
  if (command == "eval"){
    eval(args);
    return;
  }
  if (this[command] == null) return;
  var obj = convertToObject(unescape(args));
  if (obj != null) {
    var callback = obj.callback;
    var flashId = obj.flashId;
    if (obj.flashId != null && callback != null) {
      callback = obj.flashId + ID_DELIM + callback;
    }
    if (obj.args == null) {
      eval(command + "(callback);");
    } else {
      eval(command + "(obj.args, callback);");
    }
  } else {
    eval(command + "();");
  }
}

var flashCallback;
var flashCallbacks = [];
function setAPICallback(id, callback) {
  flashCallback = callback;
  flashCallbacks[id] = callback;
}

function callFlash() {
  var method = arguments[0];
  var params = [];
  for (var i = 1; i < arguments.length; i++) {
    params.push(arguments[i]);
  }
  callbackFlash(flashCallback, {method:method, params:params});
}

function callFlashInstance() {
  var flashId = arguments[0];
  var method = arguments[1];
  var params = [];
  for (var i = 2; i < arguments.length; i++) {
    params.push(arguments[i]);
  }
  var callback = flashCallbacks[flashId];
  callbackFlash(callback, {method:method, params:params});
}

function callbackFlash(callback, returnValue) {
  var flashId = "flashObj";

  var arry = callback.split(ID_DELIM);
  
  if (arry.length > 1) {
    if (arry[0].length > 0) {
      flashId = arry[0];
    }
    callback = arry[1];
  }

  var fo = document[flashId];
  if (fo == null) fo = document.embeds[flashId];
  if (fo == null) fo = document.getElementById(flashId);

  if (fo[callback] != null) {
    return fo[callback](convertToXML(returnValue, "js2flash"));
  } else {
    try {
      fo.SetVariable(callback, convertToXML(returnValue, "js2flash"));
    } catch (e) {}
  }
}


function convertToXML(obj, rootName) {
	if (obj instanceof Function) return "";
  	var type = getType(obj);
  	var xml = "<"+type.name+rootName+">";
  
	if(type.sub) {
  		for (var i in obj) {
 		  xml += convertToXML(obj[i], i);
    	}
	}
	else if (type.name == "str") {
		obj = replaceEntities(obj);
		xml += obj;
	} 
	else {
		  xml += obj;
	}
	xml += "</"+type.name+rootName+">";
	return xml;
}

function replaceEntities(obj) {
	obj = obj.replace("&", "&amp;");
	obj = obj.replace("<", "&lt;");
	obj = obj.replace(">", "&gt;");	
	return obj;
}

var s_xml_types = new Array();	
s_xml_types.push({name:"str",type:String,sub:false});
s_xml_types.push({name:"boo",type:Boolean,sub:false});
s_xml_types.push({name:"num", type:Number,sub:false});
//s_xml_types.push({name:"date", type:Date,sub:false});
s_xml_types.push({name:"arr", type:Array,sub:true});
s_xml_types.push({name:"cda", type:CData, sub:false});
s_xml_types.push({name:"obj", type:Object,sub:true});

function getType(obj) {
        switch (typeof(obj)) {
		case "boolean":
			return {name:"boo",type:Boolean,sub:false};
		case "string":
			return {name:"str",type:String,sub:false};
		case "number":
			return {name:"num",type:Number,sub:false};
	}
	for (var i = 0; i < s_xml_types.length; i++) {
	  if (obj instanceof s_xml_types[i].type) {
	    return s_xml_types[i];
	  }
	}
	return {name:"obj", type:Object,sub:true};
}
function getTypeClass(name) {
  if (name == null) return null;

  name = name.toLowerCase();
	for (var i = 0; i < s_xml_types.length; i++) {
	  if (name == s_xml_types[i].name) {
	    return s_xml_types[i].type;
	  }
	}
	return null;
}

function convertToObject(node) {
//  try {
    if (node == null) {
      return;
    }
    
    if (node.substring != null) {
      node = parseXML(node);
    }
	  
	  if (node == null || node.childNodes == null || node.childNodes.length == 0) {
	    return null;
	  }

	  var type = getTypeClass(node.nodeName.substring(0,3));
	  if (type == null) {
	    type = Object;
	  }

		if (node.firstChild.nodeType == 3 || node.firstChild.nodeType == 4) {
			return getObjectForNode(type, node);

		} else {
		
  		var obj = new type();
	  	var children = node.childNodes;
		  for (var i = 0; i < children.length; i++) {
		    var name = children[i].nodeName;
		    name = name.substring(3, name.length);
			  obj[name] = convertToObject(children[i]);
	  	}
		  return obj;
		}
//	} catch (e) {
//    alert("Error creating object:" + e.message);
//	  return null;
//	}
}

function getObjectForNode(type, node) {
	if (type == Boolean) {
		if (node.firstChild.nodeValue == "true") {
			return new Boolean(1);
		}
		else {
			return new Boolean(0);
		}
	}
	else {
		return new type(node.firstChild.nodeValue);
	}
}

function parseXML(str) {
  if (window.ActiveXObject) {
    var xmldoc = new ActiveXObject("Microsoft.XMLDOM");
    try {
      xmldoc.setProperty("SelectionLanguage", "XPath");
    } catch (e) {} // i.e. 5 doesn't like setting the selection language
    xmldoc.async = false;

    xmldoc.loadXML(str);
    return xmldoc.documentElement;  
  } else if (DOMParser) {

    var parser = new DOMParser();
    var doc = parser.parseFromString(str, "text/xml");
    
    return doc.firstChild;
    
  } else {
    return makeXMLNode(str);
  }
}


function makeXMLNode(str) {
  var node = {};
  var nodeName = node.nodeName = getNodeName(str);
  node.nodeType = 1;
  node.childNodes = [];
  node.firstChild = null;
  var startTagEndIndex = nodeName.length + 2;
  var endTagIndex = str.lastIndexOf("</" + nodeName);
  var nodeData = str.substring(startTagEndIndex, endTagIndex);
  if (nodeData.substring(0, 9) == "<![CDATA[") {
    var child = {};
    child.nodeName = null;
    child.nodeType = 4;
    child.nodeValue = getCDATA(nodeName, str.substring(startTagEndIndex, str.length));
    node.childNodes = [child];
  } else if (nodeData.indexOf("<") > -1) {
    node.childNodes = getChildNodes(nodeData);
  } else if (nodeData.length == 0) {
    //do nothing, we want 0 children here
  } else {
    var child = {};
    child.nodeName = null;
    child.nodeType = 3;
    child.nodeValue = getNodeValue(nodeName, nodeData);
    node.childNodes = [child];
  }
  if (node.childNodes.length > 0) {
    node.firstChild = node.childNodes[0];
  }
  return node;
}

function getNodeName(str) {
  return str.substring(str.indexOf("<")+1, str.indexOf(">"));
}

function getChildNodes(nodeData) {
  var childNodes = [];
  var nodeName;
  var nextIndex;
  var endIndex;
  var dataLength;
  var nameLength;
  var startNodesArray;
  var endNodesArray;
  var startNodesLength;
  var endNodesLength;
  var endNodes;
  var startNodes;
  var endNode;
  var i;
  var j;
  while (nodeData.length > 0) {
    nodeName = getNodeName(nodeData);
    nameLength = nodeName.length;
    nextIndex = nodeData.indexOf("<"+nodeName, nameLength);
    endIndex = nodeData.indexOf("</"+nodeName, nameLength);
    if (endIndex < 0) return childNodes;
    if (nextIndex < 0 || endIndex < nextIndex) {
      dataLength = endIndex+nodeName.length+3;
      childData = nodeData.substr(0, dataLength);
      nodeData = nodeData.substr(dataLength);
      childNodes.push(makeXMLNode(childData));
    } else {
      endNodes = 0;
      startNodes = 0;
      startNodesArray = nodeData.split("<" + nodeName + ">");
      startNodesLength = startNodesArray.length;
      endNode = "</" + nodeName + ">";
      for (i = 0; i < startNodesLength; i++) {
        startNodes++;
        startNodesStr = startNodesArray[i];
        if (startNodesStr.indexOf(endNode) > -1) {
          endNodesArray = startNodesStr.split("</" + nodeName + ">");
          endNodesLength = endNodesArray.length;
          for (j = 0; j < endNodesLength; j++) {
            if (++endNodes == startNodes) {
              childData = startNodesArray.slice(0, startNodes).join("");
              dataLength = childData.length;
              nodeData = nodeData.substr(dataLength);
              childNodes.push(makeXMLNode(childData));
              return childNodes;
            }
          }
        }
      }
      childNodes.push(makeXMLNode(nodeData));
      nodeData = "";
    }
  }
  return childNodes;
}

function getCDATA(nodeName, nodeData) {
  var endCDATA = nodeData.indexOf("]]>", 9);
  if (endCDATA < 0) {
    return null;
  } else {
    return getNodeValue(nodeName, nodeData.substring(9, endCDATA));
  }
}

function getNodeValue(nodeName, nodeValue) {
  switch (nodeName.substr(0, 3)) {
    case "boo":
      return (nodeValue=="true");
    case "num":
      return Number(nodeValue);
    case "str":
      return String(nodeValue);
    default:
      return nodeValue;
  }
}

function CData(str) {
  this.data = str;
}

CData.prototype.toString = function() {
  return "<![CDATA[" + this.data + "]]>";
}

/*
var chunks = {}
function chunkCall(id, total, index, chunk) {
  if (chunks[id] == undefined) chunks[id] = [];
  chunks[id][index] = chunk;
  if (index == total) {
    eval(chunks[id].join(""));
    delete chunks[id];
  }
}
*/
