/*!
 * @preserve
 *
 * Readmore.js jQuery plugin
 * Author: @jed_foster
 * Project home: http://jedfoster.github.io/Readmore.js
 * Licensed under the MIT license
 *
 * Debounce function from http://davidwalsh.name/javascript-debounce-function
 */

/* global jQuery */

(function(factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // CommonJS
        module.exports = factory(require('jquery'));
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function($) {
    'use strict';

    var readmore = 'readmore',
        defaults = {
            speed: 100,
            collapsedHeight: 192,
            heightMargin: 16,
            moreLink: '<ul><li><a href="#" class="daha_fazlasi">Daha Fazlası <i class="fa fa-chevron-down" aria-hidden="true"></i></a></li></ul>',
            lessLink: '<ul><li><a href="#" class="daha_fazlasi">Daha Az Göster <i class="fa fa-chevron-up" aria-hidden="true"></i></a></li></ul>',
            embedCSS: true,
            startOpen: false,

            // callbacks
            blockProcessed: function() {},
            beforeToggle: function() {},
            afterToggle: function() {}
        },
        cssEmbedded = {},
        uniqueIdCounter = 0;

    function debounce(func, wait, immediate) {
        var timeout;

        return function() {
            var context = this, args = arguments;
            var later = function() {
                timeout = null;
                if (! immediate) {
                    func.apply(context, args);
                }
            };
            var callNow = immediate && !timeout;

            clearTimeout(timeout);
            timeout = setTimeout(later, wait);

            if (callNow) {
                func.apply(context, args);
            }
        };
    }

    function uniqueId(prefix) {
        var id = ++uniqueIdCounter;

        return String(prefix == null ? 'rmjs-' : prefix) + id;
    }

    function setBoxHeights(element) {
        var el = element.clone().css({
                height: 'auto',
                width: element.width(),
                maxHeight: 'none',
                overflow: 'hidden'
            }).insertAfter(element),
            expandedHeight = el.outerHeight(),
            cssMaxHeight = parseInt(el.css({maxHeight: ''}).css('max-height').replace(/[^-\d\.]/g, ''), 10),
            defaultHeight = element.data('defaultHeight');

        el.remove();

        var collapsedHeight = cssMaxHeight || element.data('collapsedHeight') || defaultHeight;

        // Store our measurements.
        element.data({
            expandedHeight: expandedHeight,
            maxHeight: cssMaxHeight,
            collapsedHeight: collapsedHeight
        })
        // and disable any `max-height` property set in CSS
            .css({
                maxHeight: 'none'
            });
    }

    var resizeBoxes = debounce(function() {
        $('[data-readmore]').each(function() {
            var current = $(this),
                isExpanded = (current.attr('aria-expanded') === 'true');

            setBoxHeights(current);

            current.css({
                height: current.data( (isExpanded ? 'expandedHeight' : 'collapsedHeight') )
            });
        });
    }, 100);

    function embedCSS(options) {
        if (! cssEmbedded[options.selector]) {
            var styles = ' ';

            if (options.embedCSS && options.blockCSS !== '') {
                styles += options.selector + ' + [data-readmore-toggle], ' +
                    options.selector + '[data-readmore]{' +
                    options.blockCSS +
                    '}';
            }

            // Include the transition CSS even if embedCSS is false
            styles += options.selector + '[data-readmore]{' +
                'transition: height ' + options.speed + 'ms;' +
                'overflow: hidden;' +
                '}';

            (function(d, u) {
                var css = d.createElement('style');
                css.type = 'text/css';

                if (css.styleSheet) {
                    css.styleSheet.cssText = u;
                }
                else {
                    css.appendChild(d.createTextNode(u));
                }

                d.getElementsByTagName('head')[0].appendChild(css);
            }(document, styles));

            cssEmbedded[options.selector] = true;
        }
    }

    function Readmore(element, options) {
        this.element = element;

        this.options = $.extend({}, defaults, options);

        embedCSS(this.options);

        this._defaults = defaults;
        this._name = readmore;

        this.init();

        // IE8 chokes on `window.addEventListener`, so need to test for support.
        if (window.addEventListener) {
            // Need to resize boxes when the page has fully loaded.
            window.addEventListener('load', resizeBoxes);
            window.addEventListener('resize', resizeBoxes);
        }
        else {
            window.attachEvent('load', resizeBoxes);
            window.attachEvent('resize', resizeBoxes);
        }
    }


    Readmore.prototype = {
        init: function() {
            var current = $(this.element);

            current.data({
                defaultHeight: this.options.collapsedHeight,
                heightMargin: this.options.heightMargin
            });

            setBoxHeights(current);

            var collapsedHeight = current.data('collapsedHeight'),
                heightMargin = current.data('heightMargin');

            if (current.outerHeight(true) <= collapsedHeight + heightMargin) {
                // The block is shorter than the limit, so there's no need to truncate it.
                if (this.options.blockProcessed && typeof this.options.blockProcessed === 'function') {
                    this.options.blockProcessed(current, false);
                }
                return true;
            }
            else {
                var id = current.attr('id') || uniqueId(),
                    useLink = this.options.startOpen ? this.options.lessLink : this.options.moreLink;

                current.attr({
                    'data-readmore': '',
                    'aria-expanded': this.options.startOpen,
                    'id': id
                });

                current.after($(useLink)
                    .on('click', (function(_this) {
                        return function(event) {
                            _this.toggle(this, current[0], event);
                        };
                    })(this))
                    .attr({
                        'data-readmore-toggle': id,
                        'aria-controls': id
                    }));

                if (! this.options.startOpen) {
                    current.css({
                        height: collapsedHeight
                    });
                }

                if (this.options.blockProcessed && typeof this.options.blockProcessed === 'function') {
                    this.options.blockProcessed(current, true);
                }
            }
        },

        toggle: function(trigger, element, event) {
            if (event) {
                event.preventDefault();
            }

            if (! trigger) {
                trigger = $('[aria-controls="' + this.element.id + '"]')[0];
            }

            if (! element) {
                element = this.element;
            }

            var $element = $(element),
                newHeight = '',
                newLink = '',
                expanded = false,
                collapsedHeight = $element.data('collapsedHeight');

            if ($element.height() <= collapsedHeight) {
                newHeight = $element.data('expandedHeight') + 'px';
                newLink = 'lessLink';
                expanded = true;
            }
            else {
                newHeight = collapsedHeight;
                newLink = 'moreLink';
            }

            // Fire beforeToggle callback
            // Since we determined the new "expanded" state above we're now out of sync
            // with our true current state, so we need to flip the value of `expanded`
            if (this.options.beforeToggle && typeof this.options.beforeToggle === 'function') {
                this.options.beforeToggle(trigger, $element, ! expanded);
            }

            $element.css({'height': newHeight});

            // Fire afterToggle callback
            $element.on('transitionend', (function(_this) {
                return function() {
                    if (_this.options.afterToggle && typeof _this.options.afterToggle === 'function') {
                        _this.options.afterToggle(trigger, $element, expanded);
                    }

                    $(this).attr({
                        'aria-expanded': expanded
                    }).off('transitionend');
                }
            })(this));

            $(trigger).replaceWith($(this.options[newLink])
                .on('click', (function(_this) {
                    return function(event) {
                        _this.toggle(this, element, event);
                    };
                })(this))
                .attr({
                    'data-readmore-toggle': $element.attr('id'),
                    'aria-controls': $element.attr('id')
                }));
        },

        destroy: function() {
            $(this.element).each(function() {
                var current = $(this);

                current.attr({
                    'data-readmore': null,
                    'aria-expanded': null
                })
                    .css({
                        maxHeight: '',
                        height: ''
                    })
                    .next('[data-readmore-toggle]')
                    .remove();

                current.removeData();
            });
        }
    };


    $.fn.readmore = function(options) {
        var args = arguments,
            selector = this.selector;

        options = options || {};

        if (typeof options === 'object') {
            return this.each(function() {
                if ($.data(this, 'plugin_' + readmore)) {
                    var instance = $.data(this, 'plugin_' + readmore);
                    instance.destroy.apply(instance);
                }

                options.selector = selector;

                $.data(this, 'plugin_' + readmore, new Readmore(this, options));
            });
        }
        else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
            return this.each(function () {
                var instance = $.data(this, 'plugin_' + readmore);
                if (instance instanceof Readmore && typeof instance[options] === 'function') {
                    instance[options].apply(instance, Array.prototype.slice.call(args, 1));
                }
            });
        }
    };

}));

