// Copyright (c) Microsoft Corporation.  All rights reserved.
function jsonSerialize(obj)
{
	switch (typeof obj)
	{
		case "undefined":
			return "undefined";
			break;
		case "object":
			if (null==obj)
			{
				return "null";
			}
			else if (obj instanceof Array)
			{
				return jsonSerializeArray(obj);
			}
			else
			{
				return jsonSerializeObject(obj);
			}
			break;
		case "boolean":
			return obj.toString();
			break;
		case "number":
			return obj.toString();
			break;
		case "string":
			return "\""+obj.replace("\\", "\\\\").replace(/"/, "\\\"").replace("\b", "\\b").replace("\t", "\\t").replace("\n", "\\n").replace("\v", "\\v").replace("\f", "\\f").replace("\r", "\\r")+"\"";
			break;
		default:
			throw new Error("Can't serialize object of type "+typeof obj);
	}
}
function jsonSerializeArray(obj)
{
	var returnValue="[";
	var objLength=obj.length;
	var firstElement=true;
	for (var i=0; i < objLength;++i)
	{
		try
		{
			var serializedElement=jsonSerialize(obj[i]);
			if (!firstElement)
			{
				returnValue+=",";
			}
			returnValue+=serializedElement;
			firstElement=false;
		}
		catch (e) {  }
	}
	returnValue+="]";
	return returnValue;
}
function jsonSerializeObject(obj)
{
	var returnValue="{";
	var firstElement=true;
	for (prop in obj)
	{
		try
		{
			var serializedProp=jsonSerialize(prop);
			var serializedValue=jsonSerialize(obj[prop]);
			if (!firstElement)
			{
				returnValue+=",";
			}
			returnValue+=serializedProp;
			returnValue+=":";
			returnValue+=serializedValue;
			firstElement=false;
		}
		catch (e) {  }
	}
	returnValue+="}";
	return returnValue;
}
function jsonDeserialize(str)
{
	var result=new Object();
	var parsed=jsonDeserializePrefix(str, result);
	if (!parsed || (result.remain !=null && result.remain.length > 0))
	{
		throw new Error("Cannot deserialize this string");
	}
	return result.value;
}
function jsonDeserializePrefix(str, result)
{
	var re=new RegExp("^undefined(.*)");
	var reMatch=re.exec(str);
	if (null !=reMatch)
	{
		result.value=undefined;
		result.remain=reMatch[1];
		return true;
	}
	re=new RegExp("^null(.*)");
	reMatch=re.exec(str);
	if (null !=reMatch)
	{
		result.value=null;
		result.remain=reMatch[1];
		return true;
	}
	re=new RegExp("^true(.*)");
	reMatch=re.exec(str);
	if (null !=reMatch)
	{
		result.value=true;
		result.remain=reMatch[1];
		return true;
	}
	re=new RegExp("^false(.*)");
	reMatch=re.exec(str);
	if (null !=reMatch)
	{
		result.value=false;
		result.remain=reMatch[1];
		return true;
	}
	var num=parseFloat(str);
	if (!isNaN(num))
	{
		result.value=num;
		result.remain=str.slice(num.toString().length);
		return true;
	}
	re=new RegExp("^\"((?:(?:\\\\\")|(?:[^\"]))*)\"(.*)");
	reMatch=re.exec(str);
	if (null !=reMatch)
	{
		result.value=reMatch[1].replace("\\r", "\r").replace("\\f", "\f").replace("\\v", "\v").replace("\\n", "\n").replace("\\t", "\t").replace("\\b", "\b").replace("\\\"", "\"").replace("\\\\", "\\");
		result.remain=reMatch[2];
		return true;
	}
	re=new RegExp("^\\[(.*)");
	reMatch=re.exec(str);
	if (null !=reMatch)
	{
		result.value=new Array();
		strToParse=reMatch[1];
		do
		{
			if (strToParse.charAt(0)=="]")
			{
				result.remain=strToParse.slice(1);
				return true;
			}
			var tmp=new Object();
			var parsed=jsonDeserializePrefix(strToParse, tmp);
			if (parsed)
			{
				result.value.push(tmp.value);
				if (tmp.remain.charAt(0)==",")
				{
					strToParse=tmp.remain.slice(1);
				}
				else if (tmp.remain.charAt(0)=="]")
				{
					strToParse=tmp.remain;
				}
				else
				{
					parsed=false;
				}
			}
		} while (parsed);
		if (!parsed)
		{
			return false;
		}
	}
	re=new RegExp("^{(.*)");
	reMatch=re.exec(str);
	if (null !=reMatch)
	{
		result.value=new Object();
		strToParse=reMatch[1];
		do
		{
			if (strToParse.charAt(0)=="}")
			{
				result.remain=strToParse.slice(1);
				return true;
			}
			var tmp=new Object();
			var parsed=jsonDeserializePrefix(strToParse, tmp);
			if (parsed)
			{
				if ("string"==typeof tmp.value)
				{
					var propName=tmp.value;
				}
				else
				{
					return false;
				}
				if (tmp.remain.charAt(0)==":")
				{
					strToParse=tmp.remain.slice(1);
					parsed=jsonDeserializePrefix(strToParse, tmp);
					if (parsed)
					{
						result.value[propName]=tmp.value;
						if (tmp.remain.charAt(0)==",")
						{
							strToParse=tmp.remain.slice(1);
						}
						else if (tmp.remain.charAt(0)=="}")
						{
							strToParse=tmp.remain;
						}
						else
						{
							parsed=false;
						}
					}
				}
				else
				{
					parsed=false;
				}
			}
		} while (parsed);
		if (!parsed)
		{
			return false;
		}
	}
}

