
/**
 * performs an *synced* request expecting "ret" object from backend
 * ret always contains three properties
 *   ret.errno   integer, 0 on success, positive on error
 *   ret.error   string, error message on error
 *   ret.data    mixed, can be anything
 *
 * @param  string   url   the url
 * @param  object   data  plain object or a form
 * @param  boolean  raw   dont parse result, just return ret
 * @param  string   meth  get,post if not set check form.method, default 'get'
 *
 * @return mixed          if raw is true "ret" is returned, else return data or false on error
 */

jQuery.request = function(url, data, raw, meth)
{
   var r = false;
   var req  = false;
   if(typeof raw == 'undefined') raw = false;
   
   if(typeof data == 'object' && !$.isPlainObject(data))
   {
      if(typeof meth === 'undefined')
         meth = (data.method !== undefined)? data.method : 'get';
      
      req = $(data).serialize();
   }
   else
   {
      req = data;
   }
   
   $.ajax({
      url : url,
      data : req,
      type : (typeof meth === 'undefined')? 'get' : meth,
      async : false,
      cache : false,
      dataType : 'json',
      success : function(obj) {
         if(raw)
         {
            r = obj;
         }
         else if(obj.errno)
         {
            alert(obj.error);
            return;
         }
         else
         {
            r = obj.data;
         }
      }
   });
   
   return r;
}

/**
 * centers an object on screen
 */
jQuery.fn.center = function ()
{
   var dy = (($(window).height() - this.outerHeight()) / 2) + $(window).scrollTop();
   var dx = (($(window).width()  - this.outerWidth()) / 2)  + $(window).scrollLeft();
   
   this.css({
      position : 'absolute',
      top      : dy,            
      left     : dx
   });
   
   return this;
}

jQuery.fn.fetchAttributes = function() {
   var s = $(arguments[0]);
   
   if(s.length <= 0)
      return this;
   
   if(s[0].attributes === undefined)
      return this;

   for(var i = 0; i < s[0].attributes.length; i++) {
      var attr = s[0].attributes[i];
      //$('body').append(this.length + ' ' + attr.nodeName);
      try {
         this.attr(attr.nodeName, attr.nodeValue);
      }
      catch(e) {
         //$('body').append(' <span style="color:red">err</span>');
      }
      //$('body').append('<br />');
   }
   
   return this;
}

jQuery.fn.copyAttributes = function() {
   var s = $(arguments[0]);
   
   if(s.length <= 0)
      return this;
   
   if(s[0].attributes === undefined)
      return this;

   for(var i = 0; i < s[0].attributes.length; i++) {
      var attr = s[0].attributes[i];
      
      try {
         this.attr(attr.nodeName, attr.nodeValue);
      }
      catch(e) {
      }
   }
   
   return this;
}

jQuery.fn.copyClasses = function() {
   var s = $(arguments[0]), _this = this;
   
   if(s.length <= 0)
      return this;
   
   var elem = s[0];
   
   jQuery.each((elem.className || "").split(/\s+/), function(i, className){
      _this.addClass(className);
   });
   
   return this;
}

/*
 * This is a shortcut for zebra striping a table.
 * Usage: $('<table>').zebra()
 */
jQuery.fn.zebra = function() {
   $('tbody tr:odd', this)
      .removeClass('tbd2')
      .addClass('tbd1');

   $('tbody tr:even', this)
      .removeClass('tbd1')
      .addClass('tbd2');
   
   return this;
}

/*
 * This is a shortcut to add a row to a table.
 * Usage: $('<table>').tr(<col1>, <col2>, ...)
 */
jQuery.fn.tr = function() {
   var tr = $('<tr></tr>');

   if(this.length != 1)
      return;
   
   if(arguments.length <= 0)
      return tr;
   
   if(this[0].tagName == 'TABLE') {
      tr.addClass($('tbody tr', this).length % 2 ? 'tbd1' : 'tbd2')
      
      var col = $('col', this);
   
      for(var i = 0; i < arguments.length; i++) {
         $('<td></td>')
            .html(arguments[i] || '')
            .copyAttributes(col.eq(i))
            .appendTo(tr);
      }
      
      $('tbody', this).append(tr);
   }
     
   else if(this[0].tagName == 'TR') {
      tr.copyClasses(this)
      
      var tds = $('td', this);
      
      for(var i = 0; i < arguments.length; i++) {
         $('<td></td>')
            .html(arguments[i] || '')
            .copyAttributes(tds[i])
            .appendTo(tr);
      }
      
      this.replaceWith(tr);
   }
   
   return tr;
}

jQuery.fn.filterByName = function(n) {
   var v = $([]);
   for(var i = 0; i < this.length; i++) {
      if($(this[i]).attr('name') == n)
         v.push(this[i]);
   }
   return v;
}

jQuery.fn.fill = function(o, clear) {
   if(!o)
      return this;
   
   var f = this.find('*').andSelf().filter(':input[name]');
   
   if(clear)
      f.val('');
   
   for(var n in o)
      f.filterByName(n).val(o[n]);
   
   return this;
}

jQuery.fn.toObject = function() {
   var f = this.find('*').andSelf().filter(':input[name]'), v = { }
 
   for(var i = 0; i < f.length; i++) {
      var q = $(f[i]);
      v[q.attr('name')] = q.val();
   }
   
   return v;
}

function sleep (n) {
   // Delay for a given number of seconds  
   // 
   // version: 909.322
   // discuss at: http://phpjs.org/functions/sleep    // +   original by: Christian Doebler
   // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
   // %          note: For study purposes. Current implementation could lock up the user's browser. 
   // %          note: Consider using setTimeout() instead.
   // *     example 1: sleep(1);    // *     returns 1: 0
   
   var start = new Date().getTime();
   while (new Date() < start + n) {}
   return 0;
}


/* Example $.request() 
 * 
 * $.request('/test', { id: 100 }, function(errno, x) {
 *  
 * });
 * 
 */

