/**
 * Wireframe foundation, extended by wireframe implementations for specific 
 * interfaces (web, phone, tablet etc)
 */

App.Wireframe = {};

/**
 * Utility methods
 */
App.Wireframe.Utils = {
  
  // Interface constants
  'INTERFACE_DEFAULT' : 'default', 
  'INTERFACE_PHONE' : 'phone', 
  'INTERFACE_TABLET' : 'tablet',
  'INTERFACE_PRINTER' : 'printer', 
  'INTERFACE_API' : 'api', 
  
  /**
   * Get error message from given response object
   *
   * @param Mixed response
   * @return string
   */
  'responseToErrorMessage' : function(response) {
    var error_message = '';
    
    if((response.status == 417 || response.status == 500) && response.responseText.substr(0, 1) == '{') {
      var error_object;
      eval('error_object = ' + response.responseText);
      
      if(typeof(error_object['type']) != 'undefined') {
        if(error_object['type'] == 'ValidationErrors') {
          error_message = App.lang('Please fix the following to continue:');
          
          if(Object.size(error_object['field_errors'])) {
            var counter = 1;
            
            error_message += '<br>';
            
            for(var field in error_object['field_errors']) {
              for(var i in error_object['field_errors'][field]) {
                if(typeof(error_object['field_errors'][field][i]) == 'string' && error_object['field_errors'][field][i]) {
                  error_message += '<br>' + counter++ + '. ' + error_object['field_errors'][field][i].clean();
                } // if
              } // for
            } // for
          } // if
        } // if
      } // if
      
      if(error_message == '') {
        error_message = error_object['message'];
      } // if
    } // if
    
    if(error_message == '') {
      if(response.responseText) {
        return response.responseText;
      } else {
        return response.status && response.statusText ? App.lang('An error occurred. Reason: :status (:status_code)', {
          'status_code' : response.status, 
          'status' : response.statusText 
        }) : App.lang('Unknown error occurred');
      } // if
    } else {
      return error_message;
    } // if
  },
  
  /**
   * Return asset URL by name, type, module and interface
   * 
   * @param String name
   * @param String m
   * @param String i
   */
  'assetUrl' : function (name, m, asset_type, i) {
    if(typeof(m) == 'undefined' || m == '') {
      m = App.Config.get('default_module') ? App.Config.get('default_module') : 'system';
    } // if
    
    if(typeof(i) == 'undefined' || i == '') {
      i = App.Config.get('prefered_interface') ? App.Config.get('prefered_interface') : 'default';
    } // if
    
    return App.Config.get('assets_url') + '/' + asset_type + '/' + m + '/' + i + '/' + name;    
  },
  
  /**
   * Return image URL by name, module and interface
   * 
   * @param String name
   * @param String m
   * @param String i
   */
  'imageUrl' : function(name, m, i) {
    return App.Wireframe.Utils.assetUrl(name, m, 'images', i);
  },

  /**
   * Return brand image url
   *
   * @param String name
   * @param Boolean include_timestamp
   * @return String
   */
  'brandImageUrl' : function (name, include_timestamp) {
    return App.Config.get('branding_url') + name + (include_timestamp ? '&timestamp=' + $.now() : '');
  },

  /**
   * Return edit icon URL
   * 
   * @returns String
   */
  'editIconUrl' : function() {
    return App.Wireframe.Utils.imageUrl('/icons/12x12/edit.png', 'environment');
  },
  
  /**
   * Return trash icon URL
   * 
   * @returns String
   */
  'trashIconUrl' : function() {
    return App.Wireframe.Utils.imageUrl('/icons/12x12/move-to-trash.png', 'system');
  },
  
  /**
   * Return delete icon URL
   * 
   * @returns String
   */
  'deleteIconUrl' : function() {
    return App.Wireframe.Utils.imageUrl('/icons/12x12/delete.png', 'environment');
  }
  
};

/**
 * Flash implementation
 */
App.Wireframe.Flash = function() {
  
  /**
   * Flash message instance
   *
   * @var jQuery
   */
  var message_flash;
  
  /**
   * Currently focused element
   *
   * @var jQuery
   */
  var currently_focused_item;
  
  /**
   * Show flash message box
   *
   * @var String message
   * @var Object parameters
   * @var Boolean is_error
   * @var Boolean auto_hide
   */
  var show_flash_message = function(message, parameters, is_error, auto_hide) {
    parameters = parameters || null;
    currently_focused_item = $(':focus');
    
    $('#wireframe_flash').remove();
    var flash_class = is_error ? 'error' : 'success';
    
    message_flash = $('<div id="wireframe_flash" class="' + flash_class + '">' + App.lang(message, parameters) + '</div>').appendTo('body');
    message_flash.css({
      'marginLeft' : -1 * parseInt(message_flash.outerWidth() / 2) + 'px', 
      'marginTop'  : -1 * parseInt(message_flash.outerHeight() / 2) + 'px'
    });
    
    // Hide
    message_flash.click(function () {
      if (currently_focused_item.length) {
        currently_focused_item.focus();
      } // if

      message_flash.fadeOut(50, function () {
        $(this).remove();
      });
    });
    
    if(auto_hide) {
      setTimeout(function () {
        message_flash.fadeOut(1000, function () {
          $(this).remove();
        });
      }, 2000);
    } else {
      jQuery(document).bind('mousemove', function () {
        setTimeout(function () {
          message_flash.fadeOut(2000, function () {
            $(this).remove();
          });
        }, 1300);
        jQuery(document).unbind('mousemove');
      });
    } // if
  }; // show_flash_message
  
  // Public interface
  return {
    
    /**
     * Display success message
     *
     * @param String message
     * @param Object parameters
     * @param Boolean auto_hide
     */
    success : function(message, paremeters, auto_hide) {
      show_flash_message(message, paremeters, false, auto_hide);
    },
    
    /**
     * Display error message
     *
     * @param String message
     * @param Object parameters
     * @param Boolean auto_hide
     */
    error : function(message, paremeters, auto_hide) {
      show_flash_message(message, paremeters, true, auto_hide);
    }
    
  };
  
}();

/**
 * Wireframe updates framework
 */
App.Wireframe.Updates = function() {
  
  /**
   * Interval that will trigger updates requests
   *
   * @var Interval
   */
  var updates_interval;
  
  /**
   * Object where we'll store registered update callbacks
   *
   * @var Object
   */
  var update_callbacks = {};
  
  /**
   * URL that's triggered to get notifications
   * 
   * @var String
   */
  var updates_url;
  
  // Public interface
  return {
    
    /**
     * Subscribe specific set of update callbacks
     *
     * @param String name
     * @param Function parepare_request
     * @param Function handle_response
     */
    'subscribe' : function(name, parepare_request, handle_response) {
      update_callbacks[name] = {
        'parepare_request' : parepare_request,
        'handle_response' : handle_response
      };
    },
    
    /**
     * Unsubscribe specific set of callbacks
     *
     * @param String name
     */
    'unsubscribe' : function(name) {
      if(typeof(update_callbacks[name]) == 'object') {
        update_callbacks[name] = null;
      } // if
    },
    
    /**
     * Start checking given URL for wireframe updates
     *
     * @param String url
     * @param Integer refresh_interfal
     */
    'start' : function(url, refresh_interval) {
      updates_url = url;
      
      if(typeof(refresh_interval) == 'undefined') {
        refresh_interval = 180000;
      } // if
      
      updates_interval = window.setInterval('App.Wireframe.Updates.get()', refresh_interval);
    },
    
    /**
     * Unregister interval
     */
    'stop' : function() {
      if(updates_interval) {
        window.clearInterval(updates_interval);
      } // if
    }, 
    
    /**
     * Call server and get updates
     * 
     * @param Object collected_data
     */
    'get' : function(collected_data) {
      if(typeof(collected_data) != 'object') {
        collected_data = {};
      } // if

      App.each(update_callbacks, function(key, callback) {
        if(typeof(callback) == 'object' && typeof(callback['parepare_request']) == 'function') {
          callback['parepare_request'](collected_data);
        } // if
      });
      
      var data = {
        'submitted' : 'submitted'
      };

      App.each(collected_data, function(k, v) {
        data['data[' + k + ']'] = v;
      });
      
      $.ajax({
        'url' : updates_url, 
        'type' : 'post', 
        'data' : data, 
        'success' : function(response) {
          if(typeof(response) != 'object') {
            response = {};
          } // if

          App.each(update_callbacks, function(key, callback) {
            if(typeof(callback) == 'object' && typeof(callback['handle_response']) == 'function') {
              callback['handle_response'](response);
            } // if
          });

          if(typeof(response['status_bar_badges']) == 'object' && response['status_bar_badges']) {
            App.each(response['status_bar_badges'], function(status_bar_item, badge_value) {
              App.Wireframe.Statusbar.setItemBadge('statusbar_item_' + status_bar_item, badge_value);
            });
          } // if
        }
      });
    }
    
  };
  
}();

/**
 * Event mangement system
 */
App.Wireframe.Events = function () {
  
  /**
   * Events container
   *
   * @var jQuery
   */
  var event_container = $('<div class="events_container"></div>');
  
  /**
   * Application namespace
   *
   * @var String
   */
  var base_namespace = '.activecollab_events';
  
  // Public interface
  return {
    
    /**
     * Bind event handler
     *
     * @param String event
     * @param Function callback
     */
    'bind' : function (event, callback) {
      var events = event.split(' ');
      var new_events = [];
      $.each(events, function (index, event_name) {
        if (event_name = $.trim(event_name)) {
          new_events.push(event_name + base_namespace);
        } // if
      });      
      
      event_container.bind(new_events.join(' '), callback);
    },
    
    /**
     * Unbind event handlers
     *
     * @param String event
     */
    'unbind' : function (event) {
      if (event == undefined) { 
        // unbind all
        event_container.unbind(base_namespace);
        return true;
      } // if
      
      var events = event.split(' ');
      var new_events = [];
      $.each(events, function (index, event_name) {
        if (event_name = $.trim(event_name)) {
          new_events.push(event_name + base_namespace);
        } // if
      });
          
      event_container.unbind(new_events.join(' '));
    },
    
    /**
     * Trigger specific event
     *
     * @param String event
     * @param mixed params
     */
    'trigger' : function (event, params) {
      
      // if we are in development, and console is availabled
      if (App.isInDevelopment() && typeof(console) != 'undefined' && console && console.log) {
        if (jQuery.inArray(event, ['history_state_changed', 'content_updated', 'single_content_updated', 'window_resize', 'keydown', 'window_resize_start', 'window_resize_end', 'navigate_away']) == -1) {
          console.log('EVENT triggered', event, params);
        } // if
      } // if
      
      if (event == undefined) { 
        event = ''; 
      } // if
      
      event_container.trigger(event+base_namespace, params);
    },
    
    /**
     * backup handlers with event
     */
    'backup' : function (event) {
      if (event == undefined) {
        event = '';
      } // if

      if (event.indexOf('.') == -1) {
        var namespace = base_namespace.substring(1);
        var event_name = event;
      } else {
        var event_name = $.trim(event.substr(0, event.indexOf('.')));
        var namespace = base_namespace.substring(1) + $.trim(event.substr(event.indexOf('.')));
      } // if
      
      var events = event_container.data('events');
      
      var matching_handlers = {};
      $.each(events, function (event_name, event_handlers) {
        $.each(event_handlers, function (handler_index, handler) {
          if ((handler.type == event_name || !event_name) && (handler.namespace == namespace)) {
            if (!matching_handlers[event_name]) {
              matching_handlers[event_name] = new Array ();
            } // if
            matching_handlers[event_name].push(handler);
          } // if
        });
      });
      
      return matching_handlers;
    },
    
    /**
     * Restore events
     */
    'restore' : function (backup) {
      $.each(backup, function (event_name, handlers) {
        $.each(handlers, function (handler_index, handler) {
          var temp_base_namespace = base_namespace.substr(1);
          
          if (handler.namespace.indexOf(temp_base_namespace) == 0) {
            if (handler.namespace != temp_base_namespace) {
              event_name = event_name + '.' + handler.namespace.substr(temp_base_namespace.length + 1);
            } // if
            App.Wireframe.Events.bind(event_name, handler['handler']);
          } // if
        });
      });
    }
  };
  
}();

/**
 * Default handler for flyout error (flash error message)
 *
 * @param Object event
 * @param string message
 * @param Object xhr
 */
App.Wireframe.Events.bind('async_operation_error', function(event, message, xhr) {
  App.Wireframe.Flash.error(message);
});

/**
 * Handle escape key
 *
 * @type {handleEscape}
 */
App.Wireframe.handleEscape = function () {

  /**
   * Handlers
   *
   * @type {Array}
   */
  var handlers = [];

  /**
   * Is tracking initalized
   *
   * @type {Boolean}
   */
  var initialized = false;

  /**
   * Start handling
   */
  var startHandling = function () {
    App.Wireframe.Events.bind('keydown.handleEscape', function (event, key_event) {
      if (!key_event || (key_event['keyCode'] != 27) || !handlers.length) {
        return true;
      } // if

      for (var index = (handlers.length - 1); index >= 0; index++) {
        if (handlers[index]['handler']() === false) {
          break;
        } // if
      } // for
    });

    initialized = true;
  }; // startHandling

  /**
   * Stop handling
   */
  var stopHandling = function () {
    App.Wireframe.Events.unbind('keydown.handleEscape');
    initialized = false;
  }; // stopHandling

  // public
  return {

    /**
     * Add handler
     *
     * @param scope
     * @param handler
     */
    'add' : function (scope, handler) {
      handlers.push({
        'handler' : handler,
        'scope' : scope
      });

      if (!initialized) {
        startHandling();
      } // if
    },

    /**
     * Remove scope
     *
     * @param String scope
     */
    'remove' : function (scope) {
      $.each(handlers, function (index, handler) {
        if (handler['scope'] == scope) {
          handlers.splice(index, 1);
        } // if
      });

      if (initialized && !handlers.length) {
        stopHandling();
      } // if
    }
  };
}();

// handle keydown event
$('body').keydown(function (event) {
  App.Wireframe.Events.trigger('keydown', arguments);
});