(function($){
var global_namespace = 'bos_gn';

// Don't run this function more than once.
//if (window[global_namespace]) return;

var nsCleanRegEx = /-/g,
    Namespace = function(parent_ns, name) {
      if (name) {
        name = name.replace(nsCleanRegEx, '_');
      }

      this._ns = {
        parent: parent_ns,
        children: {},
        path: '',
        defined: false
      };
      if (this._ns.parent) {
        this._ns.parent._ns.children[name] = this;
        this._ns.path =  (this._ns.parent._ns.path ? this._ns.parent._ns.path + '.' : '') + name;
      }
    },
    ns = window[global_namespace] = new Namespace(null);

$.extend(ns, {
  get: function(path) {
    var a_path = path.replace(nsCleanRegEx, '_').split('.'),
        cur_ns = ns,
        name;

    for(var i = 0; i < a_path.length; i++) {
      name = a_path[i];
      if (typeof cur_ns._ns.children[name] == 'undefined') {
        throw('undefined namespace '+ name + ' within path '+path);
      }
      cur_ns = cur_ns._ns.children[name];
    }
    return cur_ns;
  },

  shortcut: function(path, namespace) {
    var a_path = path.replace(nsCleanRegEx, '_').split('.'),
        cur_short = this,
        name;

    for (var i = 0; ; i++) {
      name = a_path[i];
      if (typeof cur_short[name] == 'undefined') {
        cur_short[name] = {};
      }

      if (i == a_path.length - 1) {
        if (typeof namespace == 'string') {
          //si : dans le namespace => ce qui suit le : c'est une fonction du namespace
          var fn = namespace.split(':');
          namespace = fn[0];
          fn = fn.length == 2 ? fn[1] : null;
          cur_short[name] = this.get(namespace);
          if (fn) cur_short[name] = cur_short[name][fn];
        } else {
          cur_short[name] = namespace;
        }
        break;
      }
      cur_short = cur_short[name];
    }
  }
});

Namespace.prototype.Declare = function (path, fn_callback) {
  path = path.replace(nsCleanRegEx, '_');

  var a_path = path.split('.');
  var cur_ns = this, name;
  for (var i = 0; i < a_path.length; i++) {
    name = a_path[i];
    if (typeof cur_ns._ns.children[name] == 'undefined') {
      new Namespace(cur_ns, name);
    }
    cur_ns = cur_ns._ns.children[name];
  }
  // In case a namespace is multiply loaded - we ignore the definition function
  // for all but the first call.
  if (fn_callback) {
    if (!cur_ns._ns.defined) {
//      cur_ns._ns.defined = true;
      fn_callback(cur_ns);
    }
  } else if (!cur_ns._ns.defined) {
    throw("Namespace '" + cur_ns._ns.path + "' forward reference.");
  }
  return cur_ns;
}

// Export names (for Google Closure optimizer)
var p = Namespace.prototype;
p['Declare'] = p.Declare;

})(jQuery);






(function($) {

/**
 *  namespaces (shortcut):
 *    bos
 *    bos.util.dico
 *    bos.util.mq
 *    bos.util.ajax -> util.ajax
 *    bos.util.ajax.context
 *      bos.util.ajax.context:success -> util.ajax.success
 *      bos.util.ajax.context:complete -> util.ajax.complete
 *      bos.util.ajax.context:fn_success  -> util.ajax.context
 *      bos.util.ajax.context:fn_complete -> util.ajax.contextComplete
 *    bos.util.context.proto  -> util.context
 *    bos.util.context.dico   -> util.contexts
 *    bos.util.data           -> util.data
 *
 *    bos.html
 *    bos.html.action.proto   -> html.action.proto, html.action
 *    bos.html.mod.proto
 *    bos.html.mod.dico       -> html.mods
 *    bos.html.list.proto
 *    bos.html.list.dico      -> html.lists
 *    bos.html.dialog         -> html.dialog
 *    bos.html.form           -> html.form
 *    bos.html.growl          -> html.growl
 *    bos.html.toolbar        -> html.toolbar
 *    bos.html.tab            -> html.tab
 *    bos.html.select         -> html.select
 *
 *    bos.pane
 *    bos.pane.content.proto
 *    bos.pane.content.dico   -> pane.contents
 *
 */


/**************************             BOS                   *******************************/
/**************************             BOS.UTIL              *******************************/
/**************************             BOS.UTIL.DICO         *******************************/
/**
 * gestion des dictionnaires
 */
bos_gn.Declare('bos.util.dico', function(ns) {
  $.extend(ns, {
    get: function(dico, key) {

      if (typeof dico[key] == 'undefined') {
        throw('key '+ key+' not found');
      }
      return dico[key];
    },
    add: function(dico, key, obj) {
      dico[key] = obj;
    },
    has: function (dico, key) {
      return (typeof dico[key] != 'undefined');
    }
  });
});
bos_gn.shortcut('util.dico', 'bos.util.dico');


/**************************             BOS                   *******************************/
/**************************             BOS.UTIL              *******************************/
/**************************             BOS.UTIL.MQ           *******************************/
/**
 * message queueing
 *
 *
 */
bos_gn.Declare('bos.util.mq', function(ns) {
  var _obj = {
    callback: null,
    params: null
  };
  $.extend(ns, {
    publish: function(el) {
      if (_obj.callback) {
        _obj.callback.call(el, _obj.params);

        _obj.callback = null;
        _obj.params = {};
      }
    },

    subscribe: function(callback, params) {
      _obj.callback = callback;
      _obj.params = params || {};
    }
  });
});
bos_gn.shortcut('util.mq', 'bos.util.mq');


/**************************             BOS                   *******************************/
/**************************             BOS.UTIL              *******************************/
/**************************             BOS.UTIL.AJAX         *******************************/
/**
 * gestion des appels ajax
 */
bos_gn.Declare('bos.util.ajax', function(ns) {
  var initialized = false;
  
  function init() {
    if (!initialized) {
      $.extend($.blockUI.defaults, def_options.block_options);
      initialized = true;
    }
  }

  var def_options = {
      data_type: 'html',
      //html element id
      el_id: null,
      //indique si on doit bloquer l'élément $(el).block()
      block_el: true,
      //vide l'élément avant de remettre le nouveau contenu
      empty_el: false,
      //success callback function on success
      callback: null,
      //complete callback function
      complete_callback: null,

      block_options: {message: '<img src="/bospmPlugin/images/loader.gif"/>',
                      css: {backgroundColor: 'transparent', border: 'none'}
      }
    };

  $.extend(ns, {
    /**
     * @params string url
     * @params object options
     *           - string el_id
     *           - fn callback
     *           - bool block_el
     *           - bool empty_el
     *           - fn complete_callback
     * @params array post_data
     */
    _send: function(url, options, post_data) {
      init();
      options = $.extend({}, def_options, options);

      var el_id = options['el_id'],
          $el, $el_blocked, context,
          hide_el = options['empty_el'];

      if (el_id) {

        if (typeof el_id == 'string') {
          $el = $('#'+el_id);
          if (!$el.length) {
            $el = el_id = null;
          }
        } else {
          $el = $(el_id);
        }
      }

      if (!el_id && !options['callback']) {
        throw('send action '+url+' has no callback or valid el_id');
      }
      
      //block element & remove data
      if ($el) {
        if (options['block_el']) {
          $el_blocked = $el.parents('div:first');
          if (!$el_blocked.length) $el_blocked = $('body');
          $el_blocked.block(options.block_options);
        }
        if (hide_el) $el.hide();
        context = $el.get(0);
      }

      url += (url.indexOf('?') == -1 ? '?' : '&')+'ts='+ new Date().getTime();

      $.ajax({
        url: url,
        dataType: options.data_type,
//        context: context,
        type: post_data ? 'post' : 'get',
        data: post_data,

        success: function(data, textStatus, XMLHttpRequest) {
          if ($el) {
            $el.html(data);
            if (hide_el && !$el.data('pane_hidden')) $el.show();
          }
          bos_gn.util.ajax.success(context);
          if (typeof options['callback'] == 'function') options['callback'].call(context, data, textStatus, XMLHttpRequest);
        },
        
        complete: function(XMLHttpRequest, textStatus) {

          if ($el && options['block_el']) $el.parents('div:first').unblock();
          if (typeof options['complete_callback'] == 'function') options['complete_callback'].call(context, data, textStatus, XMLHttpRequest);
          bos_gn.util.ajax.complete(context);
        }
      });

    }
  });

});
bos_gn.shortcut('util.ajax', 'bos.util.ajax');


/**************************             BOS                        *******************************/
/**************************             BOS.UTIL                   *******************************/
/**************************             BOS.UTIL.AJAX              *******************************/
/**************************             BOS.UTIL.AJAX.CONTEXT      *******************************/
/**
 * permet de gérer le context d'appel d'une action et de récupérer ce context à la récupération des données
 *
 * ex:
 *    bos_gn.pane.mods.get('BosmeCompany').edit({el_id: 'div_element', params: {fdv: 123}});
 *
 *    dans le résultat de l'action
 *    <script ...>
 *      bos_gn.util.ajax.context(fonction() {
 *        //this = el_id = 'div_element'
 *        var $ctx = $(this);
 *        $('my_trigger', $ctx).click(function() {
 *          ...
 *        });
 *      })
 *    </script>
 *
 */
bos_gn.Declare('bos.util.ajax.context', function(ns) {
  var current_context,
      pre_success_callbacks = [],
      post_success_callbacks = [],
      success_callbacks = [],
      complete_callbacks = [];

  $.extend(ns, {
    _run: function(callbacks) {
      var f;
      if (callbacks.length) {
        for(var i = 0; i < callbacks.length; i++) {
          f = callbacks[i];
          delete callbacks[i];
          if (current_context && typeof f == 'function') f.apply(current_context);
        }
      }
    },

    success: function(context) {
      current_context = context;
      bos_gn.util.ajax._runCallbacks(pre_success_callbacks);
      bos_gn.util.source.checkAndProcess();
      bos_gn.util.ajax._runCallbacks(success_callbacks);
      bos_gn.util.ajax._runCallbacks(post_success_callbacks);
      pre_success_callbacks = [];
      post_success_callbacks = [];
      success_callbacks = [];
    },

    complete: function () {
      bos_gn.util.ajax._runCallbacks(complete_callbacks);
      complete_callbacks = [];
      current_context = null;
    },

    get: function() {
      return current_context;
    },

    has: function() {
      return current_context ? true : false;
    },

    fn_success: function(callback, type) {
      if (current_context) {
        callback.apply(current_context);
      } else {
        if (typeof type == 'undefined') {
          success_callbacks.push(callback);
        } else {
          if (type == 'pre') pre_success_callbacks.push(callback);
          else post_success_callbacks.push(callback);
        }
      }
    },

    fn_complete: function(callback) {
      if (current_context) {
        callback.apply(current_context);
      } else {
        complete_callbacks.push(callback);
      }
    }

  });
});
bos_gn.shortcut('util.ajax.success',          'bos.util.ajax.context:success');
bos_gn.shortcut('util.ajax.complete',         'bos.util.ajax.context:complete');
bos_gn.shortcut('util.ajax.context',          'bos.util.ajax.context:fn_success');
bos_gn.shortcut('util.ajax.contextComplete',  'bos.util.ajax.context:fn_complete');
bos_gn.shortcut('util.ajax._runCallbacks',    'bos.util.ajax.context:_run');



/**************************             BOS                      *******************************/
/**************************             BOS.UTIL                 *******************************/
/**************************             BOS.UTIL.CONTEXT         *******************************/
/**************************             BOS.UTIL.CONTEXT.PROTO   *******************************/
bos_gn.Declare('bos.util.context.proto', function(ns) {

  $.extend(ns, {
    construct: function(ctx) {
      this.ctx = ctx;
      this.ctx_id = $(ctx).attr('id');
      this.funcs = {};
    },

    create: function(ctx) {
      return new ns.construct(ctx);
    }
  });

  ns.construct.prototype = {
    checkContextEqual: function(ctx_id) {
      if (this.ctx_id != ctx_id) {
        throw('context cannot change html element reference');
      }
    },
    renewContext: function(ctx) {
      this.ctx = ctx;
    },

    add: function(name, func) {
      this.funcs[name] = func;
      return this;
    },

    extend: function(funcs) {
      $.extend(this.funcs, funcs);
    },

    run: function(name) {
      var args = Array.prototype.slice.call(arguments);
      args.shift();
      this.funcs[name].apply(this.ctx, args);
    }
  };
});
bos_gn.shortcut('util.context',          'bos.util.context.proto');


/**************************             BOS                      *******************************/
/**************************             BOS.UTIL                 *******************************/
/**************************             BOS.UTIL.CONTEXT         *******************************/
/**************************             BOS.UTIL.CONTEXT.DICO    *******************************/
bos_gn.Declare('bos.util.context.dico', function(ns) {
  var dico = {};

  $.extend(ns, {
    add: function(name, ctx) {
      if (!ctx.nodeName) {
        throw('context must be a html element');
      }

      var $ctx = $(ctx), ctx_id = $ctx.attr('id');
      if (typeof  ctx_id == 'undefined') {
        throw('context must have an id attribute');
      }

      if ($('#'+ctx_id) > 1) {
        throw('context id must be unique');
      }

      if (typeof dico[name] == 'undefined') {
        dico[name] = bos_gn.util.context.create(ctx);
      } else {
        dico[name].checkContextEqual(ctx_id);
        dico[name].renewContext(ctx);
      }
      return dico[name];
    },

    get: function(name) {
      if (typeof dico[name] == 'undefined') {
        throw('context '+name+' not exists.');
      }
      return dico[name];
    }

  });
});
bos_gn.shortcut('util.contexts',          'bos.util.context.dico');


/**************************             BOS                   *******************************/
/**************************             BOS.UTIL              *******************************/
/**************************             BOS.UTIL.SOURCE         *******************************/
/**
 * gestion des appels ajax
 */
bos_gn.Declare('bos.util.source', function(ns) {
  var sources = {},
      templates = {},
      _tmpl_cache = {},
//      _proccessed_cache = {},
      elements_to_process = [],
      templates_to_process = [];

  $.extend(ns, {
    parseTemplate: function(str, data) {
      //@see http://www.west-wind.com/weblog/posts/509108.aspx
      var err = "";
      try {
          var func = _tmpl_cache[str];
          if (!func) {
            var strFunc =
              "var p=[],print=function(){p.push.apply(p,arguments);};" +
                          "with(obj){p.push('" +
              str.replace(/[\r\t\n]/g, " ")
                 .replace(/'(?=[^#]*#>)/g, "\t")
                 .split("'").join("\\'")
                 .split("\t").join("'")
                 .replace(/<#=(.+?)#>/g, "',$1,'")
                 .split("<#").join("');")
                 .split("#>").join("p.push('")
                 + "');}return p.join('');";

              //alert(strFunc);
              func = new Function("obj", strFunc);
              _tmpl_cache[str] = func;
          }
          return func(data);
      } catch (e) {err = e.message;}
      return "< # ERROR: " + err + " # >";
    },

    parseTemplateByNames: function(tpl_name, src_name, value, el_name) {
        return bos_gn.util.source.parseTemplate(templates[tpl_name], {src: sources[src_name], value: value, el_name: el_name});
    },

    getSrc: function(src) {
      return sources[src];
    },

    clear: function() {
      sources = {};
      templates = {};
    },
    addElementToProcess: function($el, options) {
      elements_to_process.push({$el: $el, options: options});
    },

    addTemplateToProcess: function(tpl) {
      templates_to_process.push(tpl);
    },


    process: function() {
      var self = this, cache_key;
      $.each(elements_to_process, function() {
        this.$el.append(self.parseTemplateByNames(this.options['bos_tpl'], this.options['bos_src'], this.options['val'], this.$el.attr('name')));
//        if (this.options['val'] !== null) {
//          this.$el.val(this.options['val']);
//        }
      });
      elements_to_process = [];
    },

    /**
     * @params string url
     * @params object options
     *           - string el_id
     *           - fn callback
     *           - bool block_el
     *           - bool empty_el
     *           - fn complete_callback
     * @params array post_data
     */
    checkAndProcess: function() {
      if (!elements_to_process.length) return;

      var params = {}, nb = 0;
      var srcs = [], tpls = [];
      $.each(elements_to_process, function() {
        var src = this.options['bos_src'], tpl = this.options['bos_tpl'];

        if (typeof sources[src] == 'undefined') {
          if($.inArray(src, srcs) == -1) {
            srcs.push(src);
            params['src['+nb+']'] = src;
            nb++;
          }
        }

        if (typeof templates[tpl] == 'undefined') {
          if ($.inArray(tpl, tpls) == -1) {
            tpls.push(tpl);
            params['tpl['+nb+']'] = tpl;
            nb++;
          }
        }
      });

      $.each(templates_to_process, function(key, val) {
        if (typeof templates[val] == 'undefined') {
          if ($.inArray(val, tpls) == -1) {
            tpls.push(val);
            params['tpl['+nb+']'] = val;
            nb++;
          }
        }
      });

      if (!nb) {
        this.process();
        return;
      }
      params['ts'] = new Date().getTime();
      var url = bos_gn.html.action.create('BosccWidget', 'sources').getUrl(params);

      //needed_sources = {};
      var self = this;
      $.ajax({
        url: url,
        type: 'get',
        dataType: 'json',
//        async: true,
        async: false,
        success: function(data, textStatus, XMLHttpRequest) {
          for(var d in data.srcs) {
            sources[d] = data.srcs[d];
          }
          for(var d in data.tpls) {
            templates[d] = data.tpls[d];
          }
          self.process();
        },
        complete: function() {
        }
      });

    }
  });

});
bos_gn.shortcut('util.source', 'bos.util.source');


/**************************             BOS                      *******************************/
/**************************             BOS.UTIL                 *******************************/
/**************************             BOS.UTIL.DATA            *******************************/
bos_gn.Declare('bos.util.data', function(ns) {
  var data = {};
  $.extend(ns, {
    set: function(name, value) {
      data[name] = value;
    },

    get: function(name) {
      if (typeof name == 'undefined') {
        return data;
      }
      if (typeof data[name] == 'undefined') {
        return null;
      } else {
        return data[name];
      }
    },

    reset: function(p_data) {
      if (typeof p_data == 'undefined') {
        data = {};
      } else {
        data = p_data;
      }
    }
  });
});
bos_gn.shortcut('util.data',          'bos.util.data');


/**************************             BOS                        *******************************/
/**************************             BOS.HTML                   *******************************/
/**************************             BOS.HTML.FORM              *******************************/
/**
 * form manager
 */
bos_gn.Declare('bos.html.form', function(ns) {

  var def_options = {
      //html element id
      el_id: null,
      //indique si on doit bloquer l'élément $(el).block()
      block_el: true,
      //vide l'élément avant de remettre le nouveau contenu
      empty_el: false,
      //params ajoutés à l'url
      params: null,
      //if submit_el, serialize the parent form
      submit_el : null,
      //indique en cas de submit_el (donc avec un form associé), que l'action doit utiliser l'url du form
      callback: null,
      //complete callback function
      complete_callback: null
    };

  $.extend(ns, {
    get: function (submit_el) {
      var $form,
          node_name = $(submit_el).get(0).nodeName;

      if ($(submit_el).is('form')) $form = $(submit_el);
      else if (/input|select|textarea/i.test(node_name)) $form = $(submit_el.form);
      else $form = $($(submit_el).parents('form').get(0));
      
      if (!$form.length) {
        throw('no form found with '+submit_el);
      }

      return $form;
    },

    submit: function(options) {
      options = $.extend({}, def_options, options);
      var $form = this.get(options['submit_el']),
          url = bos_gn.html.action.createUrl($form.attr('action'), null, 'post').getUrl(options['params']);
      
      bos_gn.util.ajax._send(url, options, $form.serializeArray());

    }
  });
});
bos_gn.shortcut('html.form', 'bos.html.form');



/**************************             BOS                        *******************************/
/**************************             BOS.HTML                   *******************************/
/**************************             BOS.HTML.DIALOG            *******************************/
bos_gn.Declare('bos.html.dialog', function(ns) {
  var def_dial_options = {
    modal: true,
    minHeight: 100,
    minWidth: 300,
    height: 300,
    width: 400,
    closeOnEscape: false
  };
  var def_options = {
      //params ajoutés à l'url
      params: null,
      //if submit_el, serialize the parent form
      submit_el : null,
      //indique en cas de submit_el (donc avec un form associé), que l'action doit utiliser l'url du form
      callback: null,
      //complete callback function
      complete_callback: null
    };
  $.extend(ns, {
    close: function() {
      $('#bos_dialog_div_element').dialog('close');
    },
    getDialogId: function() {
      return 'bos_dialog_div_element';
    },

    openUrl: function(url, options, dial_options) {
      options['el_id'] = this.getDialogId();
      options['block_el'] =  true;
      options = $.extend({}, def_options, options);
      url = bos_gn.html.action.createUrl(url).getUrl(options['params']);

      this.open(dial_options);
      bos_gn.util.ajax._send(url, options);
    },

    open: function(dial_options) {
      var selector = '#'+this.getDialogId();
      if ($(selector).length) {
        $(selector).dialog('destroy').empty().html('');
      } else {
        if ($.fn.jquery == '1.2.6') {
          $('body').append('<div id="'+ this.getDialogId()+'" title="dialog box" class="default"></div>');
        } else {
          $('body').append('<div id="'+ this.getDialogId()+'" title="dialog box"></div>');
        }
      }

      return $(selector).dialog($.extend({}, def_dial_options, dial_options));
    },

    openEl: function(el, options, dial_options) {
      this.open(dial_options);
      options['el_id'] = 'bos_dialog_div_element';
      options['block_el'] =  true;
      options['submit_el'] = el;
      bos_gn.html.form.submit(options);
    },

    openForm: function(url, params, dial_options, post_data) {
      this.open(dial_options);
      
      var options = {
        el_id: 'bos_dialog_div_element',
        block_el: true,
        callback: function() {
        $('form:first', this).submit(function() {
          bos_gn.html.dialog.openForm($(this).attr('action'), params, dial_options, $(this).serializeArray());
          return false;
        }); //end of submit

        } //end of callback
      };

      url = bos_gn.html.action.createUrl(url).getUrl(params);
      bos_gn.util.ajax._send(url, options, post_data);
    },

    formSaved: function(data) {
      var form_saved = $('#bos_dialog_div_element').dialog('option', 'form_saved');
      if (typeof form_saved == 'function') {
        form_saved.call(this, data);
      }
    }

  });

});
bos_gn.shortcut('html.dialog', 'bos.html.dialog');


/**************************             BOS                        *******************************/
/**************************             BOS.HTML                   *******************************/
/**************************             BOS.HTML.GROWL             *******************************/
/**
 *      bos.html.growl
 *      jGrowl notifications
 *      @see http://stanlemon.net/projects/jgrowl.html#options
 */
bos_gn.Declare('bos.html.growl', function(ns) {
  var initialized = false;
  function init() {
    if (!initialized) {
      initialized = true;
      $.jGrowl.defaults.theme = 'black';
    }
  }
  var def_options = {};

  $.extend(ns, {
    show: function(text, options) {
      init();
      $.jGrowl(text, $.extend({}, def_options, options));
    }
  });
});
bos_gn.shortcut('html.growl', 'bos.html.growl:show');



/**************************             BOS                        *******************************/
/**************************             BOS.HTML                   *******************************/
/**************************             BOS.HTML.MOD               *******************************/
/**************************             BOS.HTML.MOD.PROTO         *******************************/
/**
 *      modules prototype
 */
bos_gn.Declare('bos.html.mod.proto', function(ns) {
  ns.construct = function(actions) {
    if (typeof actions == 'undefined') return;
    for (var action in actions) {
      this[action] = actions[action];
    }
  }
});
bos_gn.shortcut('html.mod.proto', 'bos.html.mod.proto');



/**************************             BOS                        *******************************/
/**************************             BOS.HTML                   *******************************/
/**************************             BOS.HTML.ACTION            *******************************/
/**************************             BOS.HTML.ACTION.PROTO      *******************************/
/**
 *      bos.html.action.proto
 */
bos_gn.Declare('bos.html.action.proto', function(ns) {
  var path_info_prefix = '';

  $.extend(ns, {
    construct: function(url, params, method) {
      this.url = url;
      this.last_options = null;
      this.params = (typeof params == 'object' && params) ? params : {};
      this.method = method || 'get';
    },

    create: function(module, action, params, method) {
      return new ns.construct(path_info_prefix+'/'+module+'/'+action, params, method);
    },

    createUrl: function(url, params, method) {
      // Attend une URL complète (url_for)
      return new ns.construct(url, params, method);
    },

    setPathInfoPrefix: function(val) {
      path_info_prefix = val;
    }    
  });


  var def_options = {
      //html element id
      el_id: null,
      //indique si on doit bloquer l'élément $(el).block()
      block_el: true,
      //vide l'élément avant de remettre le nouveau contenu
      empty_el: false,
      //params ajoutés à l'url
      params: null,
      //si des post_data, alors action sera post
      post_data: null,
      //if submit_el, serialize the parent form
      submit_el : null,
      //indique en cas de submit_el (donc avec un form associé), que l'action doit utiliser l'url du form
      use_form_url: true,
      //success callback function on success
      callback: null,
      //complete callback function
      complete_callback: null
    };


  ns.construct.prototype = {
    getUrl: function(params) {
      if (typeof params == 'undefined') params = $.param(this.params);
      else if (typeof params == 'string') params = $.param(this.params)+'&'+params.replace('?', '');
      else if (typeof params == 'object') params = $.param($.extend({}, this.params, params));

      var query_string_sep = '';
      if (params.length && params.charAt(0) != '?') {
        query_string_sep = (this.url.lastIndexOf('?') == -1) ? '?' : '&';
      }
      return this.url + query_string_sep + params;
    },

    //show fn
    show: function(options) {
      if (typeof options == 'string') options = {params: options};
      options = $.extend({}, def_options, options);

      var url = this.getUrl(options['params']),
          $form;

      if (options['submit_el']) {
        $form = bos_gn.html.form.get(options['submit_el']);
        if (options['use_form_url'] && $form.attr('action')) {
          url = ns.createUrl($form.attr('action'), this.params).getUrl(options['params']);
        }
        bos_gn.util.ajax._send(url, options, $form.serializeArray());
      } else {
        bos_gn.util.ajax._send(url, options, options.post_data);
      }
      this.last_options = options;
    },

    //refresh fn
    refresh: function(options) {
      var post_data = null, url;

      if(this.last_options) {
        if (typeof this.last_options.params == 'string') {
          options.params = this.last_options.params + '&'+$.param(options.params);
        } else {
          options.params = $.extend({}, this.last_options.params, options.params);
        }
        options = $.extend({}, this.last_options, options);
      }

      if (options['submit_el']) {
        $form = bos_gn.html.form.get(options['submit_el']);
        post_data = $form.serializeArray();
        if (options['use_form_url'] && $form.attr('action')) {
          url = ns.createUrl($form.attr('action')).getUrl(options['params']);
        }
      } else {
        url = this.getUrl(options.params);
      }

      bos_gn.util.ajax._send(url, options, post_data);
    },

    //dialog fn
    dialog: function(options, dial_options, open_form) {
      if (typeof options == 'string') options = {params: options};
      options = $.extend({}, def_options, options, {el_id: 'bos_dialog_div_element', block_el: true});

      if (open_form) {
//    openForm: function(url, params, dial_options, post_data) {
        bos_gn.html.dialog.openForm(this.getUrl(), options['params'], dial_options);
      } else {
        bos_gn.html.dialog.open(dial_options);
        this.show(options);
      }
    }
  };
});
bos_gn.shortcut('html.action', 'bos.html.action.proto');
bos_gn.shortcut('html.action.proto', 'bos.html.action.proto');





/**************************             BOS                        *******************************/
/**************************             BOS.HTML                   *******************************/
/**************************             BOS.HTML.MOD               *******************************/
/**************************             BOS.HTML.MOD.DICO          *******************************/
/**
 *      bos.pane.mod.dico
 */
bos_gn.Declare('bos.html.mod.dico', function(ns) {
  var items = {};

  $.extend(ns, {
    add: function(module, actions) {
      bos_gn.util.dico.add(items, module, new bos_gn.html.mod.proto.construct(actions));
    },
    get: function(module) {
      return bos_gn.util.dico.get(items, module);
    },
    has: function(module) {
      return bos_gn.util.dico.has(items, module);
    },

    /**
     * string module: module name
     * string action: action name
     * object params
     * string method: get | post
     */
    addAction: function (module, action, params, method) {
      if (!bos_gn.util.dico.has(items, module)) bos_gn.util.dico.add(items, module, new bos_gn.html.mod.proto.construct());
      var mod = bos_gn.util.dico.get(items, module);
      mod[action] = bos_gn.html.action.create(module, action, params, method);
    }
  });

});
bos_gn.shortcut('html.mods', 'bos.html.mod.dico');




/**************************             BOS                        *******************************/
/**************************             BOS.HTML                   *******************************/
/**************************             BOS.HTML.LIST              *******************************/
/**************************             BOS.HTML.LIST.PROTO        *******************************/
/**
 *      bos.pane.list.proto
 */
bos_gn.Declare('bos.html.list.proto', function(ns) {
  ns.construct = function(lid, name) {
    if (!bos_gn.html.mods.has('BoslmController')) {
      bos_gn.html.mods.addAction('BoslmController', 'listw');
    }

    this.lid = lid;
    this.name = name;
    this.init_callback = null;
    this.init_callback_executed = false;
    this.sorted_field = null;
    this.sorted_type = 'desc';
    this.checkbox_col_selector = null;
  }

  $.extend(ns.construct.prototype, {
    show: function(params) {
      if (typeof params == 'string') {
        params += $.param({lid: this.lid});
      } else {
        params = $.extend(params, {lid: this.lid});
      }
      var options = {
        el_id: this.lid,
        params: params
      };
      bos_gn.html.mods.get('BoslmController').listw.show(options);
    },

    initCallback: function(callback) {
      this.init_callback = callback;
      if (!this.init_callback_executed) this.init_callback.call(this);
      this.init_callback_executed = false;
    },

    init: function() {
      if (this.sorted_field) {
        var $el = $('thead a[sorting_field="'+this.sorted_field+'"]', $('#'+this.lid));
        $el.html($el.html() + ' ('+this.sorted_type+')');
      }
      this.iconize();
      if (typeof this.init_callback == 'function') {
        this.init_callback.call(this);
        this.init_callback_executed = true;
      }
    },

    sort: function(sorting_el_column, type) {
      if ($(sorting_el_column).length) {
        var params = {
          s: $(sorting_el_column).attr('sorting_field'),
          r: $(sorting_el_column).attr('ref_col') ? $(sorting_el_column).attr('ref_col') : '',
          t: 'asc'
        };

        if (typeof type == 'undefined') {
          if (params.s == this.sorted_field) {
            params.t = this.sorted_type == 'desc' ? 'asc' : 'desc';
          }
        } else {
          params.t = type;
        }
        this.sorted_type = params.t;
        this.sorted_field = params.s;
        this.show(params);
      } else {
        this.sorted_type = 'desc';
        this.sorted_field = null;
      }

    },

    sortColumn: function(sql_column, type) {
      var sorting_el_column = $('thead th a[sorting_field='+sql_column+']' , '#'+this.lid);
      if (sorting_el_column.length) {
        this.sort(sorting_el_column, type);
      } else {
        throw('column '+sql_column +' not exists');
      }
    },

    page: function(page) {
      this.show({p: page});
    },

    refresh: function() {
      this.show();
    },

    getSelector: function() {
      return '#'+this.lid;
    },

    getJQuery: function() {
      return $(this.getSelector());
    },

    getElement: function() {
      return this.getJQuery().get(0);
    },

    iconize: function() {
      var $div = $('<div class="ui-widget-content ui-corner-all" style="cursor:pointer;width:16px;"><span class="ui-icon ui-icon-circle-triangle-e"></span></div>');
      $div.hover(function() {
        $(this).addClass('ui-state-hover');
      }, function() {
        $(this).removeClass('ui-state-hover');
      });

      this.getJQuery().find('td.boslm_iconize').each(function() {
        var $clone = $div.clone(true);

        $('span', $clone).text($(this).text());

        var $a = $('a', this);
        if ($a.length && $a.attr('onclick')) {
          $clone.bind('click', $a.attr('onclick'));
        }
        $(this).html($clone);
      });
      $div.remove();
    },


    checkboxes: function(action, options) {
      var def_options = {
        reset_checked_selector: null,
        page_selection_selector: null,
        //si la liste n'a pas de checkbox, créera la checkbox sur le col selector indiqué dans le context de la liste
        col_selector: null
      };


      if (typeof action == 'object' || typeof action == 'undefined') {
        options = action || {};
        action = 'install';
      }
      
      options = $.extend({}, def_options, options);

      switch (action) {
        case 'serialize':
          var checked_arr = this.getJQuery().data('checked_arr');
          this.getJQuery().data('checked_arr', []);

          return checked_arr.join(',');

        case 'clean':
          this.getJQuery().data('checked_arr', []);
          this.getJQuery().find(':checkbox').trigger('uncheck')
          break;

        case 'setTrigger':
          bos_gn.html.list.checkbox.setTrigger(this, this.checkbox_col_selector);
          break;

        //install
        default:
          if (options.reset_checked_selector) {
            var self = this;
            $(options.reset_checked_selector)
              .click(function() {
                self.getJQuery().data('checked_arr', []);
            });
          }

          if (options.page_selection_selector) {
            bos_gn.html.list.checkbox.setPageSelection(this, options.page_selection_selector);
          }

          this.checkbox_col_selector = options.col_selector;
//          bos_gn.html.list.checkbox.setTrigger(this);
          this.initCallback(function() {
            this.checkboxes('setTrigger');
          });
          break;
      }

    }
  });
});
bos_gn.shortcut('html.list.proto', 'bos.html.list.proto');


/**************************             BOS                        *******************************/
/**************************             BOS.HTML                   *******************************/
/**************************             BOS.HTML.LIST              *******************************/
/**************************             BOS.HTML.LIST.DICO         *******************************/
/**
 */
bos_gn.Declare('bos.html.list.dico', function(ns) {
  var items = {};

  $.extend(ns,{
    add: function(lid) {
      var item;
      if (!bos_gn.util.dico.has(items, lid)) {
        item = new bos_gn.html.list.proto.construct(lid);
        bos_gn.util.dico.add(items, lid, item);
      } else {
        item = bos_gn.util.dico.get(items, lid);
      }
      item.init();
    },

    sort: function(el) {
      var lid = $(el).parents('div.boslm_container').attr('id');
      this.get(lid).sort(el);
    },

    page: function(el, page) {
      this.get($(el).parents('div.boslm_container').attr('id')).page(page);
    },

    refresh: function(el) {
      this.get($(el).parents('div.boslm_container').attr('id')).refresh();
    },

    get: function(lid) {
      if (lid.jquery) {
        lid = lid.attr('id')
      }
      return bos_gn.util.dico.get(items, lid);
    }
  });

});
bos_gn.shortcut('html.lists', 'bos.html.list.dico');



/**************************             BOS                               *******************************/
/**************************             BOS.HTML                          *******************************/
/**************************             BOS.HTML.LIST                     *******************************/
/**************************             BOS.HTML.LIST.CHECKBOX            *******************************/
bos_gn.Declare('bos.html.list.checkbox', function(ns) {

  function setCheckboxTrigger(bos_gn_list) {
    //remet les checkbox à true, si la valeur de la checkbox existe dans le tableau
    //this = checkbox
    var val = $(this).val();
    var checked_arr = bos_gn_list.getJQuery().data('checked_arr');

    if ($.inArray(val, checked_arr) != -1) {
      $(this).attr('checked', true);
    }

    $(this).bind('click', function(event) {
      var checked_arr = bos_gn_list.getJQuery().data('checked_arr');
      if ($(this).attr('checked')) {
        if ($.inArray(val, checked_arr) == -1) {
          checked_arr.push(val);
        }
      } else {
        var el_ind = $.inArray(val, checked_arr);
        if (el_ind != -1) {
          //splice, supprimer des éléments à partir de l'index i (base 1)
          checked_arr.splice(el_ind, 1);
        }
      }
//      bos_gn_list.getJQuery().data('checked_arr', checked_arr);
      event.stopPropagation();
    })
    .bind('check', function() {
      var checked_arr = bos_gn_list.getJQuery().data('checked_arr');
      if ($.inArray(val, checked_arr) == -1) {
        checked_arr.push(val);
//        bos_gn_list.getJQuery().data('checked_arr', checked_arr);
      }
      $(this).attr('checked', true);

    })
    .bind('uncheck', function() {
      var checked_arr = bos_gn_list.getJQuery().data('checked_arr');
      var el_ind = $.inArray(val, checked_arr);
      if (el_ind != -1) {
        //splice, supprimer des éléments à partir de l'index i (base 1)
        checked_arr.splice(el_ind, 1);
//        bos_gn_list.getJQuery().data('checked_arr', checked_arr);
      }
      $(this).removeAttr('checked');
    });
  }
  
  $.extend(ns, {
    setPageSelection: function(bos_gn_list, page_selection_selector) {
      //attribut les fonctions de sélection de page "tous" "aucun"
      $(page_selection_selector).click(function() {
        if ($(this).attr('selector') == 'all') {
          bos_gn_list.getJQuery().find(':checkbox').trigger('check');
        } else {
          bos_gn_list.getJQuery().find(':checkbox:checked').trigger('uncheck');
        }
      }); //end of click
    },


    setTrigger: function(bos_gn_list, col_selector) {
      if (!bos_gn_list.getJQuery().data('checked_arr')) {
        bos_gn_list.getJQuery().data('checked_arr', []);
      }
      
      if (col_selector) {
        bos_gn_list.getJQuery().find(col_selector).each(function() {
          var $cb = $('<input type="checkbox" />').val($(this).text());
          $(this).html($cb);
          setCheckboxTrigger.call($cb.get(0), bos_gn_list);
        });
        
      } else {
        bos_gn_list.getJQuery().find(':checkbox').each(function() {
          setCheckboxTrigger.call(this, bos_gn_list)
        });
        
      }
    }
  });
});
bos_gn.shortcut('html.list.checkbox', 'bos.html.list.checkbox');





/**************************             BOS                        *******************************/
/**************************             BOS.HTML                   *******************************/
/**************************             BOS.HTML.TOOLBAR           *******************************/
bos_gn.Declare('bos.html.toolbar', function(ns) {

  $.extend(ns,{
    init: function(params) {
      bos_gn.util.ajax.context(function() {
        var $toolbar = $('.boswt_toolbar', this);
        if (!$toolbar.length) {
          $(this).data('toolbar_params', null);
        } else {
          $(this).data('toolbar_params', params);
          
          $('.tb_element_save', $toolbar).append('<input type="submit" style="display:none"/>');

          // Gérer le survol des éléments
          $('.tb_element', $toolbar).hover(
            function() {
              $(this).stop().fadeTo(200, 1);
              if ($(this).attr('alt')) $(this).siblings('.hover_info').html($(this).attr('alt'));
            },
            function() {
              $(this).stop().fadeTo(200, 0.5);
              if ($(this).attr('alt')) $(this).siblings('.hover_info').empty();
            }
          ).fadeTo(100, 0.5, function() {$toolbar.show();});
        }

      }, 'post');
    }
  });

});
bos_gn.shortcut('html.toolbar', 'bos.html.toolbar');



/**************************             BOS                        *******************************/
/**************************             BOS.HTML                   *******************************/
/**************************             BOS.HTML.TAB               *******************************/
bos_gn.Declare('bos.html.tab', function(ns) {
  $.extend(ns, {
    make: function (selector, use_cookie, options) {
      options = options || {};

      if (use_cookie) {
        var index = $.cookie($(selector).attr('id')+'_tab_selected');
        index = index === null || index === undefined ? 0 : index; // first tab selected by default
        index = parseInt(index, 10);

        $.extend(options, {
          select: function(event, ui) {
            $.cookie($(ui.panel).parent().attr('id')+'_tab_selected', ui.index);
          },
          selected: index
        });
//        options.cookie = {name: $(selector).attr('id'), expires: 30};
      }

      var tab_handler = '';
      $(selector).children('div').map(function() {
        tab_handler += '<li><a href="#'+this.id+'">'+$(this).attr('title')+'</a></li>';
        $(this).removeAttr('title');
      });

      tab_handler = '<ul>'+tab_handler+'</ul>';
      $(selector).prepend(tab_handler).tabs(options);
    }
  });
});
bos_gn.shortcut('html.tab', 'bos.html.tab:make');





/**************************             BOS                        *******************************/
/**************************             BOS.PANE                   *******************************/
/**************************             BOS.PANE.CONTENT           *******************************/
/**************************             BOS.PANE.CONTENT.PROTO     *******************************/
/**
 *      content manager
 */
bos_gn.Declare('bos.pane.content.proto', function(ns) {
/**
 * options
 *  - position
 *  - title
 *  - tab_title
 *  - closable
 *  - confirm_message
 *  - message
 *  - is_post
 *  - callback
 *  - id
 */
  ns.construct = function (module, action, id, options) {
    this.ma = bos_gn.html.mods.get(module)[action];
    this.id = id;
    this.options = options;
  }


  function initToolbar(pane) {
    bos_gn.util.ajax.context(function() {
      var $title = $('.boswt_toolbar .tab_title', this);
      if ($title.length) {
        $title.html(pane.options['title']);
      }
    });
  }

  var def_options = {
    params: null,
    reload: true,
    submit_el : null,
    post_data: null,
    callback: null
  };


  $.extend(ns.construct.prototype, {
    show: function (options) {
      if (typeof options == 'string') options = {params: options};
      options = $.extend({}, def_options, options);

      if (this.options['confirm_message']) {
        if (!confirm(this.options['message'])) return;
      }

      if (this.options['open_win']) {
        window.open(this.ma.getUrl(options['params'])).focus();

      } else {

        this._checkPane(options, options['submit_el'] || options['post_data']);
        if (options['reload']) {
          options['el_id'] = this.id;
          options['empty_el'] = true;

          initToolbar(this);
          this.ma.show(options);
        }
      }
    },
    

    refresh: function(options) {
      initToolbar(this);
      this.ma.refresh($.extend({params: {}}, options, {el_id: this.id}));
    },


//    _checkPane: function (url, reload, post_data) {
    _checkPane: function (options, post_data) {
      var url = this.ma.getUrl(options['params']);
      if (typeof(paneSplitter) == 'undefined') return;
      if (!paneSplitter.__getPaneReferenceFromContentId(this.id)) {
        var pane_opts = {
          id: this.id,
          position: this.options['position'],
          closable: this.options['closable'],
          htmlElementId: this.id
        }

        if (post_data) {
          $('body').append('<div id="'+this.id+'" />');
        } else {
          pane_opts['contentUrl'] = url;
        }
        paneSplitter.addContent(pane_opts['position'], new DHTMLSuite.paneSplitterContentModel(pane_opts));
        options['reload'] = true;
      } else {
        if (post_data) {
          options['reload'] = true;
        } else if (!paneSplitter.isUrlLoadedInPane(this.id, url)) {
          paneSplitter.loadContent(this.id, url);
          options['reload'] = true;
        }
      }
      paneSplitter.setContentTitle(this.id, this.options['title']);
      paneSplitter.setContentTabTitle(this.id, this.options['tab_title']);
      paneSplitter.showContent(this.id);
      if (!post_data) paneSplitter.setContentBosPane(this.id, this);
    }

  });
  
});
bos_gn.shortcut('pane.content.proto', 'bos.pane.content.proto');


/**************************             BOS                        *******************************/
/**************************             BOS.PANE                   *******************************/
/**************************             BOS.PANE.CONTENT           *******************************/
/**************************             BOS.PANE.CONTENT.DICO      *******************************/
/**
 *      bos.pane.content.dico
 */
bos_gn.Declare('bos.pane.content.dico', function(ns) {
  var items = {};

  $.extend(ns,{
    add: function(name, module, action, id, options) {
      bos_gn.util.dico.add(items, name, new bos_gn.pane.content.proto.construct(module, action, id, options));
    },

    get: function(name) {
      return bos_gn.util.dico.get(items, name);
    }
  });

});
bos_gn.shortcut('pane.contents', 'bos.pane.content.dico');




/**************************             BOS                        *******************************/
/**************************             BOS.HTML                   *******************************/
/**************************             BOS.HTML.SELECT            *******************************/
bos_gn.Declare('bos.html.select', function(ns) {
//    $def_options = array('context_id' => '<js>jQuery(this).val()</js>',
//                         'id_value' => 'r.id',
//                         'text_value' => 'r.description',
//                         'is_active' => true,
//                         'order_by' => 'r.ref_order',
//                         'include_blank' => true,
//                         'callback' => '');
  var def_params = {
    context_id: null,
    id_value: 'r.id',
    text_value: 'r.description',
    is_active: 1,
    order_by: 'r.ref_order, r.description',
    include_blank: 1
  };

  $.extend(ns, {
    renew: function(selector, url, params, callback) {
      $(selector).effect('pulsate', {times: 1, duration: 1});

      if (typeof url == 'object') {
        url = bos_gn.html.action.create(url.m, url.a).getUrl(params)
      } else {
        url = bos_gn.html.action.createUrl(url).getUrl(params);
      }

      bos_gn.util.ajax._send(url,
                             {
                               el_id: $(selector),
                               block_el: false,
                               callback: callback
                            });

    },

    renewRef: function (selector, context_id, params, callback) {
      params = $.extend({}, def_params, params);
      params['context_id'] = context_id;

      $(selector).stop().effect('pulsate', {times: 1, duration: 1});

      bos_gn.util.ajax._send(bos_gn.html.action.create('BospmModal', 'renewSelectRef').getUrl(params),
                             {
                               el_id: $(selector),
                               block_el: false,
                               callback: callback
                            });
    } //end of renewRef
  });
});
bos_gn.shortcut('html.select', 'bos.html.select');


})(jQuery)

