/*
  Copyright (c) 2010 Astrata Software S.A. de C.V.
  Written by José Carlos Nieto <xiam@astrata.mx>

  Licensed under the MIT License
  Redistributions of files must retain the above copyright notice.
*/

(
  function($) {

    var methods = {

      // Class creation
      'init': function(options) {
        return this.each(
          function() {
            if ($(this).data('jsonrpc-bound') == undefined) {
              $(this).bind('submit', methods.submit);
              $(this).data('jsonrpc-bound', true);
            }
          }
        );
      },

      // Validation
      'validate': function() {
        return true;
      },

      'addMask': function() {
        if ($.browser.msie && $.browser.version.substr(0,1) < 8) {
          $(this).css('opacity', 0.5);
        } else  {
          LoadingMask.add(this);
        }
        //$(this).opacity(0.5);
      },

      'removeMask': function() {
        if ($.browser.msie && $.browser.version.substr(0,1) < 8) {
          $(this).css('opacity', 1);
        } else  {
          LoadingMask.remove(this);
        }
      },

      // onSubmit handler
      'submit': function(ev) {

        // console.log('submit');

        var $this = $(ev.currentTarget);
        
        if (!$this.data('locked')) {
          
          $.gritter.removeAll();

          // I don't know how to do this the proper way.
          $this.jsonRpc('lockSubmit');

          if ($this.jsonRpc('validate')) {
            
            /* Creating a hidden iframe */
            var iframe = null;

            for (var i = 0; iframe == null; i++) {

              var target = 'jq-hidden-'+i;

              if (!document.getElementById(target)) {

                if ($.browser.msie && $.browser.version.substr(0,1) < 8) {
                  var iframe = document.createElement('<iframe id="'+target+'" name="'+target+'" src="about:blank"></iframe>');
                  document.body.appendChild(iframe);
                  iframe = $(iframe);
                } else {
                
                  var iframe = $('<iframe>', {
                    'id':   target,
                    'name': target,
                    // Is opera?
                    'src':  $.browser.opera ? 'opera:about' : 'about:blank'
                  }).appendTo(document.body);
                }
              
                iframe.hide();
              }
            }

            while (!document.getElementById(target)) {
              // IE6 hack that waits for iframe to be appended 
            }

            iframe.bind(
              'load',
              methods.iframeLoad
            ); 

            iframe.data('form', $this);
        
            $this.attr('target', iframe.attr('name'));

            // Note the lack of $ 
            this.submit();

            $this.jsonRpc('lock');

          } else {

            // I still don't get it...
            $this.jsonRpc('unlockSubmit');

          }
        }

        // Prevent form submission.
        return false;
      },

      // iFrame Load
      'iframeLoad': function() {

        var form = $(this).data('form');

        window.setTimeout(
          function() {
            form.jsonRpc('unlock');
          }
        , 500);

        form.jsonRpc('unlockSubmit');

        var iframe = $(this);

        if (this.contentDocument) {
          var doc = this.contentDocument;
        } else if (this.contentWindow) {
          var doc = this.contentWindow.document;
        } else {
          var doc = this.document;
        }

        var response = doc.body.innerHTML;
        
        var txt = $('<textarea/>')[0];

        txt.innerHTML = response.replace(/</g, '&lt;').replace(/>/g, '&gt;');

        if (txt.value) {

          if (txt.value.match(/<pre/ig)) {
            txt.value = txt.value.replace(/<pre[^>]*?>/i, '').replace(/<\/pre>/i, '');
          }

          var json = $.parseJSON(txt.value);

          var callback = form.find('[name=callback]').val();

          if (callback) {
            callback = callback.split('.');
            var pointer = window;
            while (callback.length > 0) {
              pointer = pointer[callback.shift()];
            }
            pointer(json);
          } else {
            form.jsonRpc('rpc', json);
          }

        }
      },

      'rpcExecute': function(args) {
        if (typeof args != 'object') {
          args = [ args ];
        }

        for (var i = 0; i < args.length; i++) {
          eval(args[i]);
        }

      },

      'rpcReload': function() {
        window.location.reload();
      },

      'rpcRedirectTo': function(url) {
        window.location.href = url;
      },

      'rpcSimple' : function(json) {
        var json = eval('(' + json + ')');
        for (var method in json) {
          var args = json[method];
          var name = 'rpc'+method.charAt(0).toUpperCase()+method.substr(1);
          $(this).jsonRpc(name, args);
        }
      },


      'rpcSuccessMessage': function(message) {
        if ($.browser.msie && $.browser.version.substr(0,1) < 7) {
          alert(message);
        } else {
          $.gritter.add({
            title: 'Done!',
            text: message
          });
        }
      },
      
      'rpcErrorMessage': function(message) {
        if ($.browser.msie && $.browser.version.substr(0,1) < 7) {
          alert(message);
        } else {
          $.gritter.add({
            title: 'Sorry',
            text: message
          });
        }
      },

      'rpc': function(json) {

        if (!json.errorMessage && !json.inputError && !json.cancelReset) {
          $(this)[0].reset(); 
        }
        
        for (var method in json) {
          var args = json[method];
          var name = 'rpc'+method.charAt(0).toUpperCase()+method.substr(1);
          $(this).jsonRpc(name, args);
        }
      },

      'getFields': function() {
        var fields = [];
        
        $('input', this).each()

        return fields;
      },

      'getFields': function() {
        return $.merge($('input', this), $('select', this), $('textarea', this));
      },
 
      // Lock form
      'lock': function() {
        var $this = $(this);

        var fields = $this.jsonRpc('getFields');

        fields.each(
          function() {
            $(this).attr('readonly', 'readonly');
          }
        );
        // TODO: spinner
      },

      // Unlock form
      'unlock': function() {
        var $this = $(this);

        var fields = $this.jsonRpc('getFields');

        fields.each(
          function() {
            $(this).removeAttr('readonly');
          }
        );
        // TODO: remove spinner
      },

      // Unlocks buttons.
      'unlockSubmit': function() {
        this.jsonRpc('removeMask');

        $(this).data('locked', false);

        this.find('input').each(
          function() {
            var el = $(this);
            var blink = el.data('blink-default');
            if (blink != undefined) {
              if (el.val() == '') {
                el.val(blink);
              }
            }
          }
        );

        this.find('button').each(
          function() {
            var el = $(this);
            if (el.attr('type') == 'submit' || !el.attr('type')) {
              el.removeAttr('disabled');
            }
          }
        );
      },

      // Locks buttons.
      'lockSubmit': function() {

        this.jsonRpc('addMask');

        $(this).data('locked', true);

        $(this).find('input').each(
          function() {
            var el = $(this);
            var blink = el.data('blink-default');
            if (blink != undefined) {
              if (blink == el.val()) {
                el.val('');
              }
            }
          }
        );

        $(this).find('button').each(
          function() {
            var el = $(this);
            if (el.attr('type') == 'submit' || !el.attr('type')) {
              el.attr('disabled', 'disabled');
            }
          }
        );
      }

    };

    $.fn.jsonRpc = function(method) {
      if (methods[method]) {
        return methods[method].apply(this, Array.prototype.slice.call( arguments, 1 ));
      } else if (typeof method === 'object' || !method) {
        return methods.init.apply(this, arguments);
      } else {
        $.error('Method ' +  method + ' does not exist on jQuery.jsonRpc');
      }
    }
    
    $.fn.jsonRpcExec = function(json) {
      methods['rpcSimple'].call(this, json);
    }

  }
)(jQuery);

