/*
based on prototype's && moo.fx's ajax class
to be used with prototype.lite, in conjunction with moo.AJAX
this submits an iframe invisibly to the server, and expects a JSON object in return
handy, so that you do not have to care about posting forms, urlencoding, file uploads etc.
usage: <form method='post' onsubmit='new iframe(this); return false;'>

changelog:
17-01-06: initial release
18-01-06: added options initiator
          added IE5 support
		  added Opera support
01-03-06: added WORKING safari support! Major thanks to Charles Hinshaw and Phil Barrett!

*/
document.iframeLoaders = {};

iframe_GSA = function() { this.initialize.apply(this, arguments); };
iframe_GSA.prototype = {
	initialize: function(form, options,count){
		if (!options) options = {};
		this.form = form;
		this.uniqueId = count;
		document.iframeLoaders[this.uniqueId] = this;
		this.transport = this.getTransport();
		this.onComplete = options.onComplete || null;
		this.update = this.$(options.update) || null;
		this.updateMultiple = options.multiple || false;
		if (((navigator.vendor && (navigator.vendor.indexOf('Apple')) > -1) || window.opera)) // safari and opera only
     	  { // only change calls that contain 1 element and whose actions end with /Direct/Process
     	    var url = form.action;
     	    for(var i=0;i<form.elements.length;i++)
     	    {
     	        if(i == 0)
     	        {
     	            url = url + "?";
     	        }
     	        else
     	        {
     	            url = url + "&";
     	        }
     	        url = url + form.elements[i].name + "=" + escape(form.elements[i].value);
     	    }     	    
			
			var	doc = this.transport.contentWindow || this.transport.contentDocument; // retrieve the document of the iframe
			if (url.length < 80000) { // allow fallback to normal submission (80k is the max length for urls in safari)
				if (doc.document) // make sure we have the document and not the window
					doc = doc.document;
				
				try { // if this fails, fallback to normal submission
					doc.location.replace(url); // use location.replace to overwrite elements in history 
					return;
				} catch (e) { };
			}
		}
		form.target= 'frame_'+this.uniqueId;
		form.setAttribute("target", 'frame_'+this.uniqueId); // in case the other one fails.
		form.submit();
	},

	onStateChange: function() {
		this.transport = this.$('frame_'+this.uniqueId);
		try {	 
			var doc = this.transport.contentDocument.body.innerHTML; 
			this.transport.contentDocument.close(); }	// For NS6
		catch (e)
		{ 
			try
			{ 
				var doc = this.transport.contentWindow.document.body.innerHTML; 
				this.transport.contentWindow.document.close(); 
			} // For IE5.5 and IE6
			 catch (e)
			 {
				 try 
				 { 
					var doc = this.transport.document.body.innerHTML; 
					this.transport.document.body.close(); 
				 } // for IE5
				catch (e) 
				{
						try	
						{ 
						var doc = window.frames['frame_'+this.uniqueId].document.body.innerText; } // for really nasty browsers
						catch (e) { //alert(e); 
						} // forget it.
				 }
			}
		}
		this.transport.responseText = doc;
		if (this.onComplete) setTimeout(this.bind(function(){this.onComplete(this.transport);}, this), 10);
		if (this.update) setTimeout(this.bind(function(){this.update.innerHTML = this.transport.responseText;}, this), 10);
		if (this.updateMultiple){ setTimeout(this.bind(function(){ // JSON support!
				try	{ var hasscript = false; eval("var inputObject = "+this.transport.responseText);	// we're expecting a JSON object, eval it to inputObject
					for (var i in inputObject) { if (i == 'script') { hasscript = true; } // check if we passed some javascript along too
						else {if ( elm = this.$(i)) { elm.innerHTML = inputObject[i]; } else { 
						//alert("element "+i+" not found!"); 
						} } // if it's not script, update the corresponding div
					} if (hasscript) eval(inputObject['script']); // some on-the-fly-javascript exchanging support too
				} catch (e) { //alert('There was an error processing: '+this.transport.responseText); 
				} // in case of an error					
			}, this), 10);
		}	
	},

	getTransport: function() {
		var divElm = document.createElement('DIV'), frame;
		divElm.setAttribute('style', 'width: 0; height: 0; margin: 0; padding: 0; visibility: hidden; overflow: hidden');
		if (navigator.userAgent.indexOf('MSIE') > 0 && navigator.userAgent.indexOf('Opera') == -1) {// switch to the crappy solution for IE
			divElm.style.width = 0;
			divElm.style.height = 0;
			divElm.style.margin = 0;
			divElm.style.padding = 0;
			divElm.style.visibility = 'hidden';
			divElm.style.overflow = 'hidden';
			divElm.innerHTML = '<iframe name=\"frame_'+this.uniqueId+'\" id=\"frame_'+this.uniqueId+'\" src=\"about:blank\" onload=\"setTimeout(function(){document.iframeLoaders['+this.uniqueId+'].onStateChange()},20);"></iframe>';
		} else {
			frame = document.createElement("iframe");
			frame.setAttribute("name", "frame_"+this.uniqueId);
			frame.setAttribute("id", "frame_"+this.uniqueId);
			frame.addEventListener("load", this.bind(function(){ this.onStateChange(); }, this), false);
			divElm.appendChild(frame);
		}
        document.body.appendChild(divElm);
		return frame;
	},
  
  bind: function(functionObject, referenceObject) {
    return function() {
      return functionObject.apply(referenceObject, arguments);
    }
  },
  
  '$': function(id) {
    return document.getElementById(id);
  }
};

/***************************** JSON.js **************************/

var JSON_GSA = function () {
    var m = {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        s = {
            'boolean': function (x) {
                return String(x);
            },
            number: function (x) {
                return isFinite(x) ? String(x) : 'null';
            },
            string: function (x) {
                if (/["\\\x00-\x1f]/.test(x)) {
                    x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
                        var c = m[b];
                        if (c) {
                            return c;
                        }
                        c = b.charCodeAt();
                        return '\\u00' +
                            Math.floor(c / 16).toString(16) +
                            (c % 16).toString(16);
                    });
                }
                return '"' + x + '"';
            },
            object: function (x) {
                if (x) {
                    var a = [], b, f, i, l, v;
                    if (x instanceof Array) {
                        a[0] = '[';
                        l = x.length;
                        for (i = 0; i < l; i += 1) {
                            v = x[i];
                            f = s[typeof v];
                            if (f) {
                                v = f(v);
                                if (typeof v == 'string') {
                                    if (b) {
                                        a[a.length] = ',';
                                    }
                                    a[a.length] = v;
                                    b = true;
                                }
                            }
                        }
                        a[a.length] = ']';
                    } else if (x instanceof Object) {
                        a[0] = '{';
                        for (i in x) {
                            v = x[i];
                            f = s[typeof v];
                            if (f) {
                                v = f(v);
                                if (typeof v == 'string') {
                                    if (b) {
                                        a[a.length] = ',';
                                    }
                                    a.push(s.string(i), ':', v);
                                    b = true;
                                }
                            }
                        }
                        a[a.length] = '}';
                    } else {
                        return;
                    }
                    return a.join('');
                }
                return 'null';
            }
        };
    return {
        copyright: '(c)2005 JSON.org',
        license: 'http://www.crockford.com/JSON/license.html',
/*
    Stringify a JavaScript value, producing a JSON text.
*/
        stringify: function (v) {
            var f = s[typeof v];
            if (f) {
                v = f(v);
                if (typeof v == 'string') {
                    return v;
                }
            }
            return null;
        },
/*
    Parse a JSON text, producing a JavaScript value.
    It returns false if there is a syntax error.
*/
        eval: function (text) {
            try {
                return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
                        text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
                    eval('(' + text + ')');
            } catch (e) {
                return false;
            }
        },

        parse: function (text) {
            var at = 0;
            var ch = ' ';

            function error(m) {
                throw {
                    name: 'JSONError',
                    message: m,
                    at: at - 1,
                    text: text
                };
            }

            function next() {
                ch = text.charAt(at);
                at += 1;
                return ch;
            }

            function white() {
                while (ch) {
                    if (ch <= ' ') {
                        next();
                    } else if (ch == '/') {
                        switch (next()) {
                            case '/':
                                while (next() && ch != '\n' && ch != '\r') {}
                                break;
                            case '*':
                                next();
                                for (;;) {
                                    if (ch) {
                                        if (ch == '*') {
                                            if (next() == '/') {
                                                next();
                                                break;
                                            }
                                        } else {
                                            next();
                                        }
                                    } else {
                                        error("Unterminated comment");
                                    }
                                }
                                break;
                            default:
                                error("Syntax error");
                        }
                    } else {
                        break;
                    }
                }
            }

            function string() {
                var i, s = '', t, u;

                if (ch == '"') {
    outer:          while (next()) {
                        if (ch == '"') {
                            next();
                            return s;
                        } else if (ch == '\\') {
                            switch (next()) {
                            case 'b':
                                s += '\b';
                                break;
                            case 'f':
                                s += '\f';
                                break;
                            case 'n':
                                s += '\n';
                                break;
                            case 'r':
                                s += '\r';
                                break;
                            case 't':
                                s += '\t';
                                break;
                            case 'u':
                                u = 0;
                                for (i = 0; i < 4; i += 1) {
                                    t = parseInt(next(), 16);
                                    if (!isFinite(t)) {
                                        break outer;
                                    }
                                    u = u * 16 + t;
                                }
                                s += String.fromCharCode(u);
                                break;
                            default:
                                s += ch;
                            }
                        } else {
                            s += ch;
                        }
                    }
                }
                error("Bad string");
            }

            function array() {
                var a = [];

                if (ch == '[') {
                    next();
                    white();
                    if (ch == ']') {
                        next();
                        return a;
                    }
                    while (ch) {
                        a.push(value());
                        white();
                        if (ch == ']') {
                            next();
                            return a;
                        } else if (ch != ',') {
                            break;
                        }
                        next();
                        white();
                    }
                }
                error("Bad array");
            }

            function object() {
                var k, o = {};

                if (ch == '{') {
                    next();
                    white();
                    if (ch == '}') {
                        next();
                        return o;
                    }
                    while (ch) {
                        k = string();
                        white();
                        if (ch != ':') {
                            break;
                        }
                        next();
                        o[k] = value();
                        white();
                        if (ch == '}') {
                            next();
                            return o;
                        } else if (ch != ',') {
                            break;
                        }
                        next();
                        white();
                    }
                }
                error("Bad object");
            }

            function number() {
                var n = '', v;
                if (ch == '-') {
                    n = '-';
                    next();
                }
                while (ch >= '0' && ch <= '9') {
                    n += ch;
                    next();
                }
                if (ch == '.') {
                    n += '.';
                    while (next() && ch >= '0' && ch <= '9') {
                        n += ch;
                    }
                }
                if (ch == 'e' || ch == 'E') {
                    n += 'e';
                    next();
                    if (ch == '-' || ch == '+') {
                        n += ch;
                        next();
                    }
                    while (ch >= '0' && ch <= '9') {
                        n += ch;
                        next();
                    }
                }
                v = +n;
                if (!isFinite(v)) {
                    ////error("Bad number");
                } else {
                    return v;
                }
            }

            function word() {
                switch (ch) {
                    case 't':
                        if (next() == 'r' && next() == 'u' && next() == 'e') {
                            next();
                            return true;
                        }
                        break;
                    case 'f':
                        if (next() == 'a' && next() == 'l' && next() == 's' &&
                                next() == 'e') {
                            next();
                            return false;
                        }
                        break;
                    case 'n':
                        if (next() == 'u' && next() == 'l' && next() == 'l') {
                            next();
                            return null;
                        }
                        break;
                }
                error("Syntax error");
            }

            function value() {
                white();
                switch (ch) {
                    case '{':
                        return object();
                    case '[':
                        return array();
                    case '"':
                        return string();
                    case '-':
                        return number();
                    default:
                        return ch >= '0' && ch <= '9' ? number() : word();
                }
            }

            return value();
        }
    };
}();

