(function(jQuery) {
  /**
  * NodeOverflow class
  * @description
  */
  function NodeOverflow(options, currentObject) {
    var innerTestNode;
    var maxHeight;
    var limitedHeight;
    var limitedContent;
    var closestBlockParent;
    function CreateTestNode(currentObject) {
      var testNode = currentObject.cloneNode(true);
      jQuery(testNode).css({
        'visibility': 'hidden',
        'position': 'absolute',
        'width': jQuery(currentObject).width() + 'px'
      });
      jQuery(currentObject).parent().append(testNode);
      jQuery(options.limitedChildNode, testNode).html('');
      return jQuery(options.limitedChildNode,testNode);
    }
    function processChildNode(originNode, imageNode) {
      if ('block' == originNode.css('display')) {
        closestBlockParent = imageNode;
      }
      var innerContent = "";
      var originChildNodes = originNode[0].childNodes;
      for(var i = 0; i < originChildNodes.length; i++) {
        switch (originChildNodes[i].nodeType) {
          case 1:
            var newNode = originChildNodes[i].cloneNode(true);
            imageNode.append(newNode);
            jQuery(newNode).html('');
            if (false === processChildNode(jQuery(originChildNodes[i]), jQuery(newNode)))
            {
              return false;
            }
            break;
          case 3:
            if (false === processChildText(originChildNodes[i].nodeValue, imageNode))
            {
              return false;
            }
            break;
        }
      }
    }

    /**
    * processChildText method
    * @description
    */
    function processChildText(testText, parentNode) {
      var matchedWord = testText.split(/\b/);
      var cumulativeText = "";
      var currentWord = "";
      for (var i = 0; i < matchedWord.length; i++) {
        currentWord = matchedWord[i];
        if (i < matchedWord.length-1) {
          while (matchedWord[i+1].match(XRegExp("^\\p{L}+"))) {
            i++;
            currentWord = currentWord + matchedWord[i];
            if (i == matchedWord.length) {
              break;
            }
          }
        }
        else {
          currentWord = matchedWord[i];
        }
        parentNode[0].appendChild(document.createTextNode(cumulativeText + currentWord));
        closestBlockParent.append(' ' + options.unlimit.markup);

        //innerTestNode.append(' ' + options.unlimit.markup);
        if (limitedHeight >= innerTestNode[0].offsetHeight) {
          removeLastChild(parentNode[0]);
          removeLastChild(closestBlockParent[0]);
          removeLastChild(closestBlockParent[0]);
          cumulativeText += currentWord;
        }
        else {
          removeLastChild(parentNode[0]);
          removeLastChild(closestBlockParent[0]);
          removeLastChild(closestBlockParent[0]);
          parentNode[0].appendChild(document.createTextNode(cumulativeText));
          return false;
          break;
        }
      }
      parentNode[0].appendChild(document.createTextNode(cumulativeText));
    }

    /**
    * removeLastChild method
    * @description
    */
    function removeLastChild(DomNode) {
      if (0 < DomNode.childNodes.length) {
        DomNode.removeChild(DomNode.childNodes[DomNode.childNodes.length - 1]);
      }
    }

    /**
    * fillTestNode method
    * @description
    */
    function fillTestNode(sourceNode, parentNode) {
      processChildNode(sourceNode, parentNode);
      closestBlockParent.append(options.unlimit.markup);
      var savedSource = parentNode.html();
      if (! options.debug) {
        parentNode.parents(options.parentSelector).remove();
      }
      return savedSource;
    }

    //initialization code
    var lineHeight = jQuery(options.limitedChildNode,jQuery(currentObject))
        .css('line-height')
        .replace(/^(\d+)px$/,'$1');
    maxHeight = lineHeight * options.maxLine;
    limitedHeight = lineHeight * options.line;
    if (maxHeight < jQuery(options.limitedChildNode,jQuery(currentObject)).height()) {
      innerTestNode = CreateTestNode(currentObject);
      this.reducedText = fillTestNode(
          jQuery(options.limitedChildNode,jQuery(currentObject)),
          innerTestNode
        );
    }
    else {
      jQuery(options.unlimit.selector).parent().html('&nbsp;');
    }
  }

  /**
  * extend base jQuery object with the bind overflow plugin
  */
  jQuery.fn.NodeOverflow = function(options){
    var base_options = jQuery.fn.NodeOverflow.defaults;
    jQuery.extend(true,base_options, options);
    jQuery.extend(true,base_options, {parentSelector: jQuery(this).selector});
    options = base_options;
    return jQuery(this).each(function(i) {
      // Save the full content in the parent
      var CurrentCarousel = new NodeOverflow(
        options,
        this
      );
      jQuery(this).data(
        'fulltextsource',
        jQuery(options.limitedChildNode,this).html()
      );
      jQuery(this).data(
        'minifiedtextsource',
        CurrentCarousel.reducedText
      );

      jQuery(options.limitedChildNode,jQuery(this)).html(
        jQuery(this).data('minifiedtextsource')
      );

      jQuery(options.unlimit.selector, jQuery(this)).data('paragraph_selector',options.limitedChildNode);
      jQuery(options.unlimit.selector, jQuery(this)).data('parent_selector',options.parentSelector);


      if(undefined !== options.unlimit.toggle_link){
        jQuery(options.unlimit.selector, jQuery(this)).data('unlimit_text',jQuery(options.unlimit.selector, jQuery(this)).html());
        jQuery(options.unlimit.selector, jQuery(this)).data('limit_text',options.unlimit.toggle_link);
      }

      //bind a method on the ellipsis
      if (!options.unlimit.follow_link) {
        jQuery(options.unlimit.selector, jQuery(this)).click(function (){
          var parentParagraph =
            jQuery(
              jQuery(this).data('paragraph_selector'),
              jQuery(this).parents(
                jQuery(this).data('parent_selector')
              )
            );
          if (jQuery(this).hasClass('limit')) {
            jQuery(this).removeClass('limit');
            jQuery(this).html(jQuery(this).data('unlimit_text'));
            parentParagraph
              .html(
                parentParagraph.parents(
                  jQuery(this).data('parent_selector')
                )
                .data('minifiedtextsource')
              );
          }
          else {
            jQuery(this).addClass('limit');
            jQuery(this).html(jQuery(this).data('limit_text'));
            parentParagraph
              .html(
                parentParagraph.parents(
                  jQuery(this).data('parent_selector')
                )
                .data('fulltextsource')
              );
          }
          jQuery('.fiche_content_wrapper').css({zoom: .99});
          jQuery('.fiche_content_wrapper').css({zoom: 1});
          //jQuery(this).remove();
          return false;
        });
      }
    });
    return innerNode;
  };

  /**
  * default options for the node-overflow plugin
  */
  jQuery.fn.NodeOverflow.defaults = {
    limitedChildNode: '.article_content',
    line: 6,
    debug: false,
    maxLine: 8,
    unlimit:{
      follow_link: false,
      markup: '<span class="show">(...)</span>',
      selector: '.show'
    }
  };
})(jQuery);
