;
(function ($, window, document, undefined) {
    'use strict';

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

        version: '5.5.0',

        cache: {},

        images_loaded: false,
        nodes_loaded: false,

        settings: {
            load_attr: 'interchange',

            named_queries: {
                'default': 'only screen',
                'small': Foundation.media_queries['small'],
                'small-only': Foundation.media_queries['small-only'],
                'medium': Foundation.media_queries['medium'],
                'medium-only': Foundation.media_queries['medium-only'],
                'large': Foundation.media_queries['large'],
                'large-only': Foundation.media_queries['large-only'],
                'xlarge': Foundation.media_queries['xlarge'],
                'xlarge-only': Foundation.media_queries['xlarge-only'],
                '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));
