// Usage: codyhouse.co/license

// Utility function
function Util () {};
/* 
	class manipulation functions
*/
Util.hasClass = function(el, className) {
	return el.classList.contains(className);
};

Util.addClass = function(el, className) {
	var classList = className.split(' ');
    if(typeof el.classList !== 'undefined'){
        el.classList.add(classList[0]);
    }
 	if (classList.length > 1) Util.addClass(el, classList.slice(1).join(' '));
};

Util.removeClass = function(el, className) {
	var classList = className.split(' ');
    if(typeof el.classList !== 'undefined'){
        el.classList.remove(classList[0]);	
        if (classList.length > 1) Util.removeClass(el, classList.slice(1).join(' '));
    }
};

Util.getIndexInArray = function(array, el) {
    return Array.prototype.indexOf.call(array, el);
  };

// Check if Reduced Motion is enabled
Util.osHasReducedMotion = function() {
    if(!window.matchMedia) return false;
    var matchMediaObj = window.matchMedia('(prefers-reduced-motion: reduce)');
    if(matchMediaObj) return matchMediaObj.matches;
    return false; // return false if not supported
  }; 

(function () {
    "use strict";
    var TextAnim = function (element) {
        this.element = element;
        this.wordsWrapper = this.element.getElementsByClassName(' js-text-anim__wrapper');
        this.words = this.element.getElementsByClassName('js-text-anim__word');
        this.selectedWord = 0;
        // interval between two animations
        this.loopInterval = parseFloat(getComputedStyle(this.element).getPropertyValue('--text-anim-pause')) * 1000 || 1000;
        // duration of single animation (e.g., time for a single word to rotate)
        this.transitionDuration = parseFloat(getComputedStyle(this.element).getPropertyValue('--text-anim-duration')) * 1000 || 1000;
        // keep animating after first loop was completed
        this.loop = (this.element.getAttribute('data-loop') && this.element.getAttribute('data-loop') == 'off') ? false : true;
        this.wordInClass = 'text-anim__word--in';
        this.wordOutClass = 'text-anim__word--out';
        // check for specific animations
        this.isClipAnim = Util.hasClass(this.element, 'text-anim--clip');
        if (this.isClipAnim) {
            this.animBorderWidth = parseInt(getComputedStyle(this.element).getPropertyValue('--text-anim-border-width')) || 2;
            this.animPulseClass = 'text-anim__wrapper--pulse';
        }
        initTextAnim(this);
    };

    function initTextAnim(element) {
        // make sure there's a word with the wordInClass
        setSelectedWord(element);
        // if clip animation -> add pulse class
        if (element.isClipAnim) {
            Util.addClass(element.wordsWrapper[0], element.animPulseClass);
        }
        // init loop
        loopWords(element);
    };

    function setSelectedWord(element) {
        var selectedWord = element.element.getElementsByClassName(element.wordInClass);
        if (selectedWord.length == 0) {
            Util.addClass(element.words[0], element.wordInClass);
        } else {
            element.selectedWord = Util.getIndexInArray(element.words, selectedWord[0]);
        }
    };

    function loopWords(element) {
        // stop animation after first loop was completed
        if (!element.loop && element.selectedWord == element.words.length - 1) {
            return;
        }
        var newWordIndex = getNewWordIndex(element);
        setTimeout(function () {
            if (element.isClipAnim) { // clip animation only
                switchClipWords(element, newWordIndex);
            } else {
                switchWords(element, newWordIndex);
            }
        }, element.loopInterval);
    };

    function switchWords(element, newWordIndex) {
        // switch words
        Util.removeClass(element.words[element.selectedWord], element.wordInClass);
        Util.addClass(element.words[element.selectedWord], element.wordOutClass);
        Util.addClass(element.words[newWordIndex], element.wordInClass);
        // reset loop
        resetLoop(element, newWordIndex);
    };

    function resetLoop(element, newIndex) {
        setTimeout(function () {
            // set new selected word
            Util.removeClass(element.words[element.selectedWord], element.wordOutClass);
            element.selectedWord = newIndex;
            loopWords(element); // restart loop
        }, element.transitionDuration);
    };

    function switchClipWords(element, newWordIndex) {
        // clip animation only
        var startWidth = element.words[element.selectedWord].offsetWidth,
            endWidth = element.words[newWordIndex].offsetWidth;

        // remove pulsing animation
        Util.removeClass(element.wordsWrapper[0], element.animPulseClass);
        // close word
        animateWidth(startWidth, element.animBorderWidth, element.wordsWrapper[0], element.transitionDuration, function () {
            // switch words
            Util.removeClass(element.words[element.selectedWord], element.wordInClass);
            Util.addClass(element.words[newWordIndex], element.wordInClass);
            element.selectedWord = newWordIndex;

            // open word
            animateWidth(element.animBorderWidth, endWidth, element.wordsWrapper[0], element.transitionDuration, function () {
                // add pulsing class
                Util.addClass(element.wordsWrapper[0], element.animPulseClass);
                loopWords(element);
            });
        });
    };

    function getNewWordIndex(element) {
        // get index of new word to be shown
        var index = element.selectedWord + 1;
        if (index >= element.words.length) index = 0;
        return index;
    };

    function animateWidth(start, to, element, duration, cb) {
        // animate width of a word for the clip animation
        var currentTime = null;

        var animateProperty = function (timestamp) {
            if (!currentTime) currentTime = timestamp;
            var progress = timestamp - currentTime;

            var val = Math.easeInOutQuart(progress, start, to - start, duration);
            element.style.width = val + "px";
            if (progress < duration) {
                window.requestAnimationFrame(animateProperty);
            } else {
                cb();
            }
        };

        //set the width of the element before starting animation -> fix bug on Safari
        element.style.width = start + "px";
        window.requestAnimationFrame(animateProperty);
    };

    window.TextAnim = TextAnim;

    // init TextAnim objects
    var textAnim = document.getElementsByClassName('js-text-anim'),
        reducedMotion = Util.osHasReducedMotion();
    if (textAnim) {
        if (reducedMotion) return;
        for (var i = 0; i < textAnim.length; i++) {
            (function (i) { new TextAnim(textAnim[i]); })(i);
        }
    }
}());