;(function ($, window, document, undefined) {

'use strict';

Foundation.libs.interchange = {
  name : 'interchange',

  version : '5.3.0',

  cache : {},

  images_loaded : false,
  nodes_loaded : false,

  settings : {
    load_attr : 'interchange',

    named_queries : {
      'default' : 'only screen',
      small : Foundation.media_queries.small,
      medium : Foundation.media_queries.medium,
      large : Foundation.media_queries.large,
      xlarge : Foundation.media_queries.xlarge,
      xxlarge: Foundation.media_queries.xxlarge,
      landscape : 'only screen and (orientation: landscape)',
      portrait : 'only screen and (orientation: portrait)',
      retina : 'only screen and (-webkit-min-device-pixel-ratio: 2),' +
        'only screen and (min--moz-device-pixel-ratio: 2),' +
        'only screen and (-o-min-device-pixel-ratio: 2/1),' +
        'only screen and (min-device-pixel-ratio: 2),' +
        'only screen and (min-resolution: 192dpi),' +
        'only screen and (min-resolution: 2dppx)'
    },

    directives : {
      replace: function (el, path, trigger) {
        // The trigger argument, if called within the directive, fires
        // an event named after the directive on the element, passing
        // any parameters along to the event that you pass to trigger.
        //
        // ex. trigger(), trigger([a, b, c]), or trigger(a, b, c)
        //
        // This allows you to bind a callback like so:
        // $('#interchangeContainer').on('replace', function (e, a, b, c) {
        //   console.log($(this).html(), a, b, c);
        // });

        if (/IMG/.test(el[0].nodeName)) {
          var orig_path = el[0].src;

          if (new RegExp(path, 'i').test(orig_path)) return;

          el[0].src = path;

          return trigger(el[0].src);
        }
        var last_path = el.data(this.data_attr + '-last-path'),
            self = this;

        if (last_path == path) return;

        if (/\.(gif|jpg|jpeg|tiff|png)([?#].*)?/i.test(path)) {
          $(el).css('background-image', 'url('+path+')');
          el.data('interchange-last-path', path);
          return trigger(path);
        }

        return $.get(path, function (response) {
          el.html(response);
          el.data(self.data_attr + '-last-path', path);
          trigger();
        });

      }
    }
  },

  init : function (scope, method, options) {
    Foundation.inherit(this, 'throttle random_str');

    this.data_attr = this.set_data_attr();
    $.extend(true, this.settings, method, options);
    this.bindings(method, options);
    this.load('images');
    this.load('nodes');
  },

  get_media_hash : function() {
      var mediaHash='';
      for (var queryName in this.settings.named_queries ) {
          mediaHash += matchMedia(this.settings.named_queries[queryName]).matches.toString();
      }
      return mediaHash;
  },

  events : function () {
    var self = this, prevMediaHash;

    $(window)
      .off('.interchange')
      .on('resize.fndtn.interchange', self.throttle(function () {
          var currMediaHash = self.get_media_hash();
          if (currMediaHash !== prevMediaHash) {
              self.resize();
          }
          prevMediaHash = currMediaHash;
      }, 50));

    return this;
  },

  resize : function () {
    var cache = this.cache;

    if(!this.images_loaded || !this.nodes_loaded) {
      setTimeout($.proxy(this.resize, this), 50);
      return;
    }

    for (var uuid in cache) {
      if (cache.hasOwnProperty(uuid)) {
        var passed = this.results(uuid, cache[uuid]);

        if (passed) {
          this.settings.directives[passed
            .scenario[1]].call(this, passed.el, passed.scenario[0], function () {
              if (arguments[0] instanceof Array) { 
                var args = arguments[0];
              } else { 
                var args = Array.prototype.slice.call(arguments, 0);
              }

              passed.el.trigger(passed.scenario[1], args);
            });
        }
      }
    }

  },

  results : function (uuid, scenarios) {
    var count = scenarios.length;

    if (count > 0) {
      var el = this.S('[' + this.add_namespace('data-uuid') + '="' + uuid + '"]');

      while (count--) {
        var mq, rule = scenarios[count][2];
        if (this.settings.named_queries.hasOwnProperty(rule)) {
          mq = matchMedia(this.settings.named_queries[rule]);
        } else {
          mq = matchMedia(rule);
        }
        if (mq.matches) {
          return {el: el, scenario: scenarios[count]};
        }
      }
    }

    return false;
  },

  load : function (type, force_update) {
    if (typeof this['cached_' + type] === 'undefined' || force_update) {
      this['update_' + type]();
    }

    return this['cached_' + type];
  },

  update_images : function () {
    var images = this.S('img[' + this.data_attr + ']'),
        count = images.length,
        i = count,
        loaded_count = 0,
        data_attr = this.data_attr;

    this.cache = {};
    this.cached_images = [];
    this.images_loaded = (count === 0);

    while (i--) {
      loaded_count++;
      if (images[i]) {
        var str = images[i].getAttribute(data_attr) || '';

        if (str.length > 0) {
          this.cached_images.push(images[i]);
        }
      }

      if (loaded_count === count) {
        this.images_loaded = true;
        this.enhance('images');
      }
    }

    return this;
  },

  update_nodes : function () {
    var nodes = this.S('[' + this.data_attr + ']').not('img'),
        count = nodes.length,
        i = count,
        loaded_count = 0,
        data_attr = this.data_attr;

    this.cached_nodes = [];
    this.nodes_loaded = (count === 0);

    while (i--) {
      loaded_count++;
      var str = nodes[i].getAttribute(data_attr) || '';

      if (str.length > 0) {
        this.cached_nodes.push(nodes[i]);
      }

      if(loaded_count === count) {
        this.nodes_loaded = true;
        this.enhance('nodes');
      }
    }

    return this;
  },

  enhance : function (type) {
    var i = this['cached_' + type].length;

    while (i--) {
      this.object($(this['cached_' + type][i]));
    }

    return $(window).trigger('resize').trigger('resize.fndtn.interchange');
  },

  convert_directive : function (directive) {

    var trimmed = this.trim(directive);

    if (trimmed.length > 0) {
      return trimmed;
    }

    return 'replace';
  },

  parse_scenario : function (scenario) {
    // This logic had to be made more complex since some users were using commas in the url path
    // So we cannot simply just split on a comma
    var directive_match = scenario[0].match(/(.+),\s*(\w+)\s*$/),
    media_query         = scenario[1];

    if (directive_match) {
      var path  = directive_match[1],
      directive = directive_match[2];
    }
    else {
      var cached_split = scenario[0].split(/,\s*$/),
      path             = cached_split[0],
      directive        = '';               
    }

    return [this.trim(path), this.convert_directive(directive), this.trim(media_query)];
  },

  object : function(el) {
    var raw_arr = this.parse_data_attr(el),
        scenarios = [], 
        i = raw_arr.length;

    if (i > 0) {
      while (i--) {
        var split = raw_arr[i].split(/\((.*?)(\))$/);

        if (split.length > 1) {
          var params = this.parse_scenario(split);
          scenarios.push(params);
        }
      }
    }

    return this.store(el, scenarios);
  },

  store : function (el, scenarios) {
    var uuid = this.random_str(),
        current_uuid = el.data(this.add_namespace('uuid', true));

    if (this.cache[current_uuid]) return this.cache[current_uuid];

    el.attr(this.add_namespace('data-uuid'), uuid);

    return this.cache[uuid] = scenarios;
  },

  trim : function(str) {

    if (typeof str === 'string') {
      return $.trim(str);
    }

    return str;
  },

  set_data_attr: function (init) {
    if (init) {
      if (this.namespace.length > 0) {
        return this.namespace + '-' + this.settings.load_attr;
      }

      return this.settings.load_attr;
    }

    if (this.namespace.length > 0) {
      return 'data-' + this.namespace + '-' + this.settings.load_attr;
    }

    return 'data-' + this.settings.load_attr;
  },

  parse_data_attr : function (el) {
    var raw = el.attr(this.attr_name()).split(/\[(.*?)\]/),
        i = raw.length, 
        output = [];

    while (i--) {
      if (raw[i].replace(/[\W\d]+/, '').length > 4) {
        output.push(raw[i]);
      }
    }

    return output;
  },

  reflow : function () {
    this.load('images', true);
    this.load('nodes', true);
  }

};

}(jQuery, window, window.document));