/* global _ */
(function () {
    'use strict';

    /* jshint ignore:start */
    // Underscore's Template Module
    // Courtesy of underscorejs.org
    var _ = (function (_) {
        _.defaults = function (object) {
            if (!object) {
                return object;
            }
            for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {
                var iterable = arguments[argsIndex];
                if (iterable) {
                    for (var key in iterable) {
                        if (object[key] == null) {
                            object[key] = iterable[key];
                        }
                    }
                }
            }
            return object;
        };

        // By default, Underscore uses ERB-style template delimiters, change the
        // following template settings to use alternative delimiters.
        _.templateSettings = {
            evaluate    : /<%([\s\S]+?)%>/g,
            interpolate : /<%=([\s\S]+?)%>/g,
            escape      : /<%-([\s\S]+?)%>/g
        };

        // When customizing `templateSettings`, if you don't want to define an
        // interpolation, evaluation or escaping regex, we need one that is
        // guaranteed not to match.
        var noMatch = /(.)^/;

        // Certain characters need to be escaped so that they can be put into a
        // string literal.
        var escapes = {
            "'":      "'",
            '\\':     '\\',
            '\r':     'r',
            '\n':     'n',
            '\t':     't',
            '\u2028': 'u2028',
            '\u2029': 'u2029'
        };

        var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;

        // JavaScript micro-templating, similar to John Resig's implementation.
        // Underscore templating handles arbitrary delimiters, preserves whitespace,
        // and correctly escapes quotes within interpolated code.
        _.template = function(text, data, settings) {
            var render;
            settings = _.defaults({}, settings, _.templateSettings);

            // Combine delimiters into one regular expression via alternation.
            var matcher = new RegExp([
                (settings.escape || noMatch).source,
                (settings.interpolate || noMatch).source,
                (settings.evaluate || noMatch).source
            ].join('|') + '|$', 'g');

            // Compile the template source, escaping string literals appropriately.
            var index = 0;
            var source = "__p+='";
            text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
                source += text.slice(index, offset)
                    .replace(escaper, function(match) { return '\\' + escapes[match]; });

                if (escape) {
                    source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
                }
                if (interpolate) {
                    source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
                }
                if (evaluate) {
                    source += "';\n" + evaluate + "\n__p+='";
                }
                index = offset + match.length;
                return match;
            });
            source += "';\n";

            // If a variable is not specified, place data values in local scope.
            if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';

            source = "var __t,__p='',__j=Array.prototype.join," +
                "print=function(){__p+=__j.call(arguments,'');};\n" +
                source + "return __p;\n";

            try {
                render = new Function(settings.variable || 'obj', '_', source);
            } catch (e) {
                e.source = source;
                throw e;
            }

            if (data) return render(data, _);
            var template = function(data) {
                return render.call(this, data, _);
            };

            // Provide the compiled function source as a convenience for precompilation.
            template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';

            return template;
        };

        return _;
    })({});

    if (location.hostname === 'todomvc.com') {
        (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
        m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
        })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
        ga('create', 'UA-31081062-1', 'auto');
        ga('send', 'pageview');
    }
    /* jshint ignore:end */

    function redirect() {
        if (location.hostname === 'tastejs.github.io') {
            location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com');
        }
    }

    function findRoot() {
        var base = location.href.indexOf('examples/');
        return location.href.substr(0, base);
    }

    function getFile(file, callback) {
        if (!location.host) {
            return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.');
        }

        var xhr = new XMLHttpRequest();

        xhr.open('GET', findRoot() + file, true);
        xhr.send();

        xhr.onload = function () {
            if (xhr.status === 200 && callback) {
                callback(xhr.responseText);
            }
        };
    }

    function Learn(learnJSON, config) {
        if (!(this instanceof Learn)) {
            return new Learn(learnJSON, config);
        }

        var template, framework;

        if (typeof learnJSON !== 'object') {
            try {
                learnJSON = JSON.parse(learnJSON);
            } catch (e) {
                return;
            }
        }

        if (config) {
            template = config.template;
            framework = config.framework;
        }

        if (!template && learnJSON.templates) {
            template = learnJSON.templates.todomvc;
        }

        if (!framework && document.querySelector('[data-framework]')) {
            framework = document.querySelector('[data-framework]').dataset.framework;
        }

        this.template = template;

        if (learnJSON.backend) {
            this.frameworkJSON = learnJSON.backend;
            this.frameworkJSON.issueLabel = framework;
            this.append({
                backend: true
            });
        } else if (learnJSON[framework]) {
            this.frameworkJSON = learnJSON[framework];
            this.frameworkJSON.issueLabel = framework;
            this.append();
        }

        this.fetchIssueCount();
    }

    Learn.prototype.append = function (opts) {
        var aside = document.createElement('aside');
        aside.innerHTML = _.template(this.template, this.frameworkJSON);
        aside.className = 'learn';

        if (opts && opts.backend) {
            // Remove demo link
            var sourceLinks = aside.querySelector('.source-links');
            var heading = sourceLinks.firstElementChild;
            var sourceLink = sourceLinks.lastElementChild;
            // Correct link path
            var href = sourceLink.getAttribute('href');
            sourceLink.setAttribute('href', href.substr(href.lastIndexOf('http')));
            sourceLinks.innerHTML = heading.outerHTML + sourceLink.outerHTML;
        } else {
            // Localize demo links
            var demoLinks = aside.querySelectorAll('.demo-link');
            Array.prototype.forEach.call(demoLinks, function (demoLink) {
                if (demoLink.getAttribute('href').substr(0, 4) !== 'http') {
                    demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href'));
                }
            });
        }

        document.body.className = (document.body.className + ' learn-bar').trim();
        document.body.insertAdjacentHTML('afterBegin', aside.outerHTML);
    };

    Learn.prototype.fetchIssueCount = function () {
        var issueLink = document.getElementById('issue-count-link');
        if (issueLink) {
            var url = issueLink.href.replace('https://github.com', 'https://api.github.com/repos');
            var xhr = new XMLHttpRequest();
            xhr.open('GET', url, true);
            xhr.onload = function (e) {
                var parsedResponse = JSON.parse(e.target.responseText);
                if (parsedResponse instanceof Array) {
                    var count = parsedResponse.length;
                    if (count !== 0) {
                        issueLink.innerHTML = 'This app has ' + count + ' open issues';
                        document.getElementById('issue-count').style.display = 'inline';
                    }
                }
            };
            xhr.send();
        }
    };

    redirect();
    getFile('learn.json', Learn);
})();
