/**
This library is intended to simplify use of AJAX in portlets (or any <div> displaying dynamic content). The principle is to refresh a given <div>
when a given action occured.
 
Usage: 
------
   * Add js/jalios/ajax-refresh.js
   * The <div> to be refreshed is tagged as "ajax-refresh-div" with a CSS class
   * The refresh trigger (eg a link or a form button) is tagged as "ajax-refresh" with a CSS class
   * When the user clicks on the trigger, the content of the <div> is refreshed with the target URL (i.e. href of the link or action + params of the form). 
   * The CSS class "confirm" can be used to ask the user to confirm the refresh of the <div>. 
     The title of the trigger element is used for the confirm message.

Example 1: 
----------
Refresh with a link

<% jcmsContext.addJavaScript("js/jalios/ajax-refresh.js"); %>  
<div class="ajax-refresh-div">
  <%= new Date() %><br/>
  <a class="ajax-refresh" href="testLink.jsp">Refresh</a>
</div>

Example 2: 
----------
Refresh with a form (with confirm)

<% jcmsContext.addJavaScript("js/jalios/ajax-refresh.js"); %>  
<div class="ajax-refresh-div">
	<% String text = request.getParameter("text"); %>
	<% if (Util.notEmpty(text)) { %>
	  Your text: <%= text %>
	<% } %>
	<form action="testForm.jsp">
		<input type="text" name="text" />
		<input type="submit" class="ajax-refresh confirm" title="Please, confirm the refresh" />
	</form>
</div>
 */

// ---------------------------------------
//  AJAX REFRESH 
// ---------------------------------------


'JCMS.ajax.Refresh'.namespace({
  jaliosRevision: '$Revision: 1.1 $',
  
  histIdx : 0,     // History index
  histInit: false, // History initalization
  
  init: function() {
    // Register RSH
    JCMS.History.observe(JCMS.ajax.Refresh._getRefreshHistory.bind());
    
    // Register on click
    Util.observeDocument('click', JCMS.ajax.Refresh.refresh.bindAsEventListener());
    
    // Logger Info
    JcmsLogger.info("AjaxRefresh", "Init AjaxRefresh");
    
    // Ajax Lazy -> Quid Lazy > Lazy ?
    $$('DIV.ajax-refresh-div.ajax-lazy').each(function(elm, idx){
      var jcmsId = elm.getJcmsId();
      if (!jcmsId){ return; } 
      var url = JcmsJsContext.getContextPath()+'/jcore/portal/ajaxPortal.jsp?portletId='+jcmsId + JCMS.ajax.Refresh._getJcmsUsage(elm,'&usage=');
      JCMS.ajax.Refresh._ajaxRequest(elm, url, false);
    });
    
  },

  /**
   * This function dispatches the click on "ajax-refresh" elements
   * @param event the event
   */
  refresh: function(event){
    if (!Util.isLeftClick(event)){
      return false;
    }

    var elt = Event.element(event); 
    var func;
 
    
    // Case 1. Retrieve target elt from a link
    var link = $(elt.fastUp('A', 'ajax-refresh', true));
    if (link) {
      func = JCMS.ajax.Refresh.refreshFromLink;
      elt = link;
    }
    
    // Case 2. Retrieve target elt from a form input
    else if (elt.tagName == 'INPUT' && elt.hasClassName('ajax-refresh')) {
      func = JCMS.ajax.Refresh.refreshFromInput;
    } 
    
    // Skip if no ajax-refresh elt
    if (!func) {
      return true;
    }
    
    // Skip if no ajax-refresh-div
    var refreshDiv = JCMS.ajax.Refresh._findRefreshDiv(elt);
    if (!refreshDiv) {
      return true;
    }
    
    // Call the function with confirm
    if (elt.hasClassName('confirm')) {
      var callback = function(confirm) {
        if (!confirm) { return false; } 
        func(elt, refreshDiv);
      }
      JCMS.window.Modal.confirm(elt.title , callback);
    }
    // Call the function (without confirm)
    else {
      func(elt, refreshDiv);
    }
    Event.stop(event);
    return false;
  },
  
  /**
   * This function refresh portlets with the given JcmsId
   * Note: should use handleAjaxPortletAction instead
   * @param jcmsId the Jcms Id
   * @param params additional parameters
   */
  refreshPortlet: function(jcmsId,params){
    params = params ? '&'+params : '';
    $$('DIV.ajax-refresh-div.ID_'+jcmsId).each(function(elm, idx){
      var url = JcmsJsContext.getContextPath()+'/jcore/portal/ajaxPortal.jsp?portletId='+jcmsId + JCMS.ajax.Refresh._getJcmsUsage(elm,'&usage=');
      JCMS.ajax.Refresh._ajaxRequest(elm,url+params,false);
    });
    return false;
  },
  
  /**
   * This function refresh given DIV with the given URL
   * @param refreshDiv the DIV to refresh
   * @param url the url to call (use JcmsJsContext.getContextPath()+'/')
   */
  refreshDIV: function(refreshDiv, url){
    JCMS.ajax.Refresh._ajaxRefresh(refreshDiv, url, false);
  },
  
  /**
   * This function refresh the div from the clicked link.
   * @param link the link
   * @param refreshDiv the refreshDiv (optional)
   * @return true if refresh has been performed
   */
  refreshFromLink: function (link, refreshDiv) {
    
    var history    = !link.hasClassName('ajax-action');
    refreshDiv = refreshDiv || JCMS.ajax.Refresh._findRefreshDiv(link);
    return JCMS.ajax.Refresh._ajaxRefresh(refreshDiv, link.href, history);
  },
  
  /**
   * This function refresh the div from the submitted form.
   * @param input the form input
   * @param refreshDiv the refreshDiv (optional)
   * @return true if refresh has been performed
   */
  refreshFromInput: function (input, refreshDiv) {
    refreshDiv = refreshDiv || JCMS.ajax.Refresh._findRefreshDiv(input);
    var form = input.form;
    var params = form.serialize({submit: input.name});
    var history = form.method == 'get';
    return JCMS.ajax.Refresh._ajaxRefresh(refreshDiv, form.action, history, params);
  },
  
  // -----------------------------------------------------
  //  INTERNAL
  // -----------------------------------------------------
  
  /**
   * Retrieve the usage for the given 
   *
   * @param elm the triggered element
   */
  _getJcmsUsage : function(element, prefix) {
    var prefix = prefix || '';
    var usageClass = $w(element.className).find(function(elm){ 
      return elm.startsWith('USAGE_');
    });
    
    return usageClass ? (prefix+usageClass.substring(6)) : '';
  },
  
  /**
   * Retrieve the ajax-refresh-div froml the current element.
   * This method is smart and can retrieve DIV throught contextual menus
   *
   * @param elm the triggered element
   */
  _findRefreshDiv: function(elm){
    var refreshDiv = elm.fastUp('DIV', 'ajax-refresh-div');
    
    // CtxMenu hack (for ctx links under body tag)
    if (!refreshDiv && CtxMenuManager.latestElement){
      refreshDiv = $(CtxMenuManager.latestElement).fastUp('DIV', 'ajax-refresh-div');
    }
    return refreshDiv
  },
    
  /**
   * Performs the AJAX refresh. If refreshDiv is a Portlet's Div then 
   * refresh the portlet with given parameters.
   * 
   * @param refreshDiv the div to be refreshed
   * @param url the url to be called
   * @param history update browser history
   * @param formParams the form parameters (optional)
   */
  _ajaxRefresh: function(refreshDiv, url, history, formParams){
    
    refreshDiv = $(refreshDiv);
    if (!refreshDiv) {
      JcmsLogger.warn("AjaxRefresh", "Cannot retrieve refresh div wrapper");
      return false;
    }
    
    // Magic Portlet Trick
    if (refreshDiv.hasClassName('Portlet') && refreshDiv.getJcmsId()){
      var qs  = url.indexOf('?') < 0 ? '' : url.substring(url.indexOf('?')+1);
      var id  = refreshDiv.getJcmsId();
      var usage = JCMS.ajax.Refresh._getJcmsUsage(refreshDiv);
      url = JcmsJsContext.getContextPath()+'/jcore/portal/ajaxPortal.jsp';
      
      if(formParams){
        formParams.portletId = id;
        if (usage){
          formParams.usage = usage;
        }
      } else {
        if (usage){
          var rg2 = new RegExp('usage=[^&]*','img');
          qs = (qs.match(rg2)) ? qs.replace(rg2,'usage='+usage) 
                               : 'usage='+usage+'&'+qs;
        }
        
        var rg1 = new RegExp('portletId=[^&]*','img');
        qs = (qs.match(rg1)) ? qs.replace(rg1,'portletId='+id) 
                             : 'portletId='+id+'&'+qs;
        url += '?'+qs;
      }
    }
    
    // Jcms Ajax Request
    return JCMS.ajax.Refresh._ajaxRequest(refreshDiv, url, history, formParams);
  },
  
  /**
   * Performs the AJAX request
   *.
   * @param refreshDiv the div to be refreshed
   * @param url the url to be called
   * @param history update browser history
   * @param formParams the form parameters (optional)
   */
  _ajaxRequest: function(refreshDiv, url, history, formParams){
    
    // Set history
    history = history == undefined ? true : history;
    
    // Init Jcms Request
    var jcmsRequest = new JcmsAjaxRequest();
    
    // Init RPC with jcmsRequest callback
    var funcRPC = function(){
      new Ajax.Request(url, {
        evalScripts: true,
        parameters:  formParams || {},
        onComplete:  jcmsRequest.asyncJsonCallBack.bind(jcmsRequest),
        onException: jcmsRequest._handleException.bind(jcmsRequest),
        onFailure:   jcmsRequest._handleException.bind(jcmsRequest)
      });
    }
     
    // Init CallBack
    var funcCallBack = function(transport, returnEffect){ 
      var response = transport.responseText;
      var html     = response.fastStrip();
      var jsCode   = '';
      
      // Extract and remove the div containing lazy javascript and css loading
      var jsHtml = '<div class="ajax-lazy-load">';
      var jsCodeIndexOf = html.indexOf(jsHtml);
      if (jsCodeIndexOf > 0) {
        jsCode = html.substring(jsCodeIndexOf + jsHtml.length,
                                html.lastIndexOf("</div>"));
        html = html.substring(0, jsCodeIndexOf);
      }

      // Remove the ajax-refresh div wrapper
      var rg = new RegExp('^<div[^>]*ajax-refresh[^>]*>(.*)','gi');
      if (html.match(rg)){
        html = html.replace(rg, '$1');
        html = html.substring(0, html.lastIndexOf("</div>"));
      }
      
      // Insert back the lazy loading javascript code
      html += jsCode;
      
      // Fix refresh div
      refreshDiv = $(refreshDiv);
      
      // Init history
      if (history){
        JCMS.ajax.Refresh._initRefreshHistory(refreshDiv);
      }
      
      // ScrollTo DIV
      if (refreshDiv.viewportOffset().top < 0){
        refreshDiv.scrollTo();
      }
      
      document.fire('refresh:before',{ wrapper: refreshDiv });
      
      // Update DIV content
      refreshDiv.update(html);
      
      // Update history
      if (history){
        JCMS.ajax.Refresh._setRefreshHistory(refreshDiv, url, formParams);
      }
      
      document.fire('refresh:after' ,{ wrapper: refreshDiv });
    }

    jcmsRequest.rpc      = funcRPC;
    jcmsRequest.callback = funcCallBack;
    jcmsRequest.asyncJsonCall();
    // jcmsRequest.timeout = 1000000;
    return true;
  },
  
  _initRefreshHistory: function(wrapper){
    if (JCMS.ajax.Refresh.histInit){ return; }
    
    JCMS.ajax.Refresh.histInit = { 
      'wrappperId'  : $(wrapper).identify()
    };
  },
  
  _setRefreshHistory: function(wrapper, url, formParams){
    
    JCMS.History.add("refresh-" + JCMS.ajax.Refresh.histIdx, { 
      'wrappperId'  : $(wrapper).identify(), 
      'url'         : url,
      'formParams'  : formParams
    });

    JCMS.ajax.Refresh.histIdx++;
  },
  
  _getRefreshHistory: function(newLocation, historyData){
    
    // Update with current history data
    if(historyData){
      if (!historyData.wrappperId){
        return;
      }
      
      // Check if id (sets by identify()) has been lost by back button
      var wrapper = $(historyData.wrappperId);
      if (!wrapper){
        JcmsLogger.warn("AjaxRefresh", "Cannot retrieve refresh div wrapper, html id lost by back button");
        return;
      }
      
      JCMS.ajax.Refresh._ajaxRequest($(historyData.wrappperId), historyData.url, false, historyData.formParams);
      return;
    }
    
    // Update with first backuped data
    if(JCMS.ajax.Refresh.histInit){
      var wrapper = $(JCMS.ajax.Refresh.histInit.wrappperId);
      var jcmsId = wrapper.getJcmsId();
      if (jcmsId){
        var url = JcmsJsContext.getContextPath()+'/jcore/portal/ajaxPortal.jsp?portletId='+jcmsId + JCMS.ajax.Refresh._getJcmsUsage(wrapper,'&usage=');
        JCMS.ajax.Refresh._ajaxRequest(wrapper, url, false);
      } else {
        document.location = document.location;
      }
    }
  }
  
});

// ---------------------------------------
//  EVENTS 
// ---------------------------------------

Event.observe(window, 'load'  , function() { JCMS.ajax.Refresh.init();   });
