text: "use strict";
  (function(factory){
    // AMD
    if(typeof define === 'function' && define.amd) {
      define(['jquery', './jquery.enjoyhint.js', 'jquery.scrollto'], factory);
    }
    // CommonJS
    else if (typeof require === 'function' && typeof exports === 'object') {
      module.exports = factory(require('jquery'), require('./jquery.enjoyhint.js'), require('jquery.scrollto'));
    }
    // Global
    else {
      window.EnjoyHint = factory(jQuery)
    }
  })(function($){
    var EnjoyHint = function(configs) {
      var $event_element;
      var that = this;
      var _options = configs || {};
      var BTN_NEXT_TEXT = _options.btnNextText;
      var BTN_SKIP_TEXT = _options.btnSkipText;
    
      var SHAPE_BACKGROUND_COLOR = _options.backgroundColor || "rgba(0,0,0,0.6)";
    
      var body = "body"; // TODO: Is it possible case when we need to define enjoyhint somewhere else?
      var elementAvailableEventName = "enjoyhint-element-available";
    
      var defaults = {
        onStart: function() {},
    
        onEnd: function() {},
    
        onSkip: function() {},
  
        onNext: function () { },
  
        elementToScroll: document.body
      };
    
      var options = $.extend(defaults, _options);
      var data = [];
      var current_step = 0;
    
      var $body = $(body);
    
      /********************* PRIVATE METHODS ***************************************/
    
      var init = function() {
        if ($(".enjoyhint")) {
          $(".enjoyhint").remove();
        }
    
        $body.css({ overflow: "hidden" });
    
        $(document).on("touchmove", lockTouch);
    
        $body.enjoyhint({
          onNextClick: function() {
            nextStep();
          },
          onPrevClick: function(){
            prevStep();
          },
          onSkipClick: function() {
            options.onSkip();
            skipAll();
          },
          fill: SHAPE_BACKGROUND_COLOR,
          elementToScroll: options.elementToScroll
        });
      };
    
      var lockTouch = function(e) {
        e.preventDefault();
      };
    
      var destroyEnjoy = function() {
        $(".enjoyhint").remove();
        $body.css({ overflow: "auto" });
        $(document).off("touchmove", lockTouch);
      };
    
      that.clear = function() {
        var $nextBtn = $(".enjoyhint_next_btn");
        var $skipBtn = $(".enjoyhint_skip_btn");
        var $prevBtn = $(".enjoyhint_prev_btn");
  
        $prevBtn.removeClass(that.prevUserClass);
        $nextBtn.removeClass(that.nextUserClass);
        $nextBtn.text(BTN_NEXT_TEXT);
        $skipBtn.removeClass(that.skipUserClass);
        $skipBtn.text(BTN_SKIP_TEXT);
      };
    
      function hideCurrentHint(){
        $body.enjoyhint("render_circle", []);
        $("#enjoyhint_label").remove();
        $("#enjoyhint_arrpw_line").remove();
        $body.enjoyhint("hide_prev");
        $body.enjoyhint("hide_next");
        $body.enjoyhint("hide_skip");
      };
  
      var stepAction = function(unpause) {
        if (!(data && data[current_step])) {
          $body.enjoyhint("hide");
          options.onEnd();
          destroyEnjoy();
          return;
        }
        
        options.onNext();
    
        var $enjoyhint = $(".enjoyhint");
    
        $enjoyhint.removeClass("enjoyhint-step-" + current_step);
        $enjoyhint.removeClass("enjoyhint-step-" + (current_step + 1));
        $enjoyhint.removeClass("enjoyhint-step-" + (current_step + 2));
        $enjoyhint.addClass("enjoyhint-step-" + (current_step + 1));
  
        var step_data = data[current_step];
  
        $body.off(elementAvailableEventName);
  
        //loops waiting until specified element becomes visible
        var waitUntilAvailable = function (selector, interval) {
          if (interval == null)
            interval = 150; 
          
          var triggerIfAvailable = function () {
               if ($(selector).is(":visible")) {
                   $body.trigger(elementAvailableEventName);
               }
               else {
                   setTimeout(triggerIfAvailable, interval)
               }
           };
   
           setTimeout(triggerIfAvailable, 0);
        }
   
        //if pausedUntil was specified, hide current overlay and wait until specified event occurs
        if (!unpause && step_data.pausedUntil != null && step_data.pausedUntil.event != null) {
              //hide current overlay during waiting time
              $body.enjoyhint("hide");
              
             //if 'available' event was chosen wait for the custom event, which is triggered when the element becomes visible
              if (step_data.pausedUntil.event === 'available') {
                  $body.on(elementAvailableEventName, function () {
                      stepAction(true);      //restart the step without pause
                      $body.off(elementAvailableEventName);
                  });
  
                  //check if element is available every 150ms
                  waitUntilAvailable(step_data.pausedUntil.selector);
              }
              else {
                  //delay the actual action until 'the event' happens on body or selector
                  if (step_data.pausedUntil.selector == null) {
                    on(step_data.pausedUntil.event, function () {
                        stepAction(true);     //restart the step without pause
                        off(step_data.pausedUntil.event);
                    });
                  }
                  else {
                    $(step_data.pausedUntil.selector).on(step_data.pausedUntil.event, function () {
                        stepAction(true);     //restart the step without pause
                        $(step_data.pausedUntil.selector).off(step_data.pausedUntil.event)
                    });
                  }
              }
  
              //the rest of the logic will be executed whenever the step is restarted
              return;
        }
  
        var scrollSpeed = step_data.scrollAnimationSpeed;
    
        if (
          step_data.onBeforeStart &&
          typeof step_data.onBeforeStart === "function"
        ) {
          step_data.onBeforeStart();
        }
    
        var timeout = step_data.timeout || 0;
    
        setTimeout(function() {
          if (!step_data.selector) {
            for (var prop in step_data) {
              if (step_data.hasOwnProperty(prop) && prop.split(" ")[1]) {
                step_data.selector = prop.split(" ")[1];
                step_data.event = prop.split(" ")[0];
    
                if (
                  prop.split(" ")[0] == "next" ||
                  prop.split(" ")[0] == "auto" ||
                  prop.split(" ")[0] == "custom"
                ) {
                  step_data.event_type = prop.split(" ")[0];
                }
    
                step_data.description = step_data[prop];
              }
            }
          }
    
          setTimeout(function() {
            that.clear();
          }, 250);
  
          var isHintInViewport = $(step_data.selector).get(0).getBoundingClientRect();
          if(isHintInViewport.top < 0 || isHintInViewport.bottom > (window.innerHeight || document.documentElement.clientHeight)){
              hideCurrentHint();
              $(options.elementToScroll).scrollTo(step_data.selector, step_data.scrollAnimationSpeed || 250, {offset: -200});
          }
          else {
            // if previous button has been clicked and element are in viewport to prevent custom step scrollAnimationSpeed set scrollSpeed to default
            scrollSpeed = 250;
          }
    
          setTimeout(function() {
            var $element = $(step_data.selector);
            var event = makeEventName(step_data.event);
            $body.enjoyhint("show");
            $event_element = $element;
    
            if (step_data.event_selector) {
              $event_element = $(step_data.event_selector);
            }
            
            $event_element.off(event)
            $element.off("keydown");
  
            if (!step_data.event_type && step_data.event == "key") {
              $element.keydown(function(event) {
                if (event.which == step_data.keyCode) {
                  current_step++;
                  stepAction();
                }
              });
            }
    
            if (step_data.showNext !== true) {
              $body.enjoyhint("hide_next");
            }
            else {
              $body.enjoyhint("show_next");
            }
            
            $body.enjoyhint("hide_prev");
  
            if(current_step !== 0) {
              $body.enjoyhint("show_prev");
            }
  
            if (step_data.showPrev == false) {
              $body.enjoyhint("hide_prev");
          }
  
            if (step_data.showSkip == false) {
              $body.enjoyhint("hide_skip");
            } else {
              $body.enjoyhint("show_skip");
            }
    
    
            if (step_data.nextButton) {
              var $nextBtn = $(".enjoyhint_next_btn");
    
              $nextBtn.addClass(step_data.nextButton.className || "");
              $nextBtn.text(step_data.nextButton.text || "Next");
              that.nextUserClass = step_data.nextButton.className;
            }
  
            if (step_data.prevButton) {
              var $prevBtn = $(".enjoyhint_prev_btn");
  
              $prevBtn.addClass(step_data.prevButton.className || "");
              $prevBtn.text(step_data.prevButton.text || "Previous");
              that.prevUserClass = step_data.prevButton.className;
            }
  
            if (step_data.skipButton) {
              var $skipBtn = $(".enjoyhint_skip_btn");
    
              $skipBtn.addClass(step_data.skipButton.className || "");
              $skipBtn.text(step_data.skipButton.text || "Skip");
              that.skipUserClass = step_data.skipButton.className;
            }
    
            if (step_data.event_type) {
              switch (step_data.event_type) {
                case "auto":
                  $element[step_data.event]();
    
                  switch (step_data.event) {
                    case "click":
                      break;
                  }
                  current_step++;
                  stepAction();
                  return;
    
                case "custom":
                  on(step_data.event, function() {
                    current_step++;
                    off(step_data.event);
                    stepAction();
                  });
    
                  break;
    
                case "next":
                  $body.enjoyhint("show_next");
                  break;
              }
            } else {
                var alreadyTriggered = false;
                $event_element.one(event, function (e) {    //one should ensure that event is handled only once, but that's not always enough
                    if (alreadyTriggered)                   //make sure that the step is not changed twice handling the same event
                        return;
  
                    alreadyTriggered = true;                
                    if (step_data.keyCode && e.keyCode != step_data.keyCode) {
                      return;
                    }
  
                    $event_element.off(event);              //unregister the event
                    
                    current_step++;
                    stepAction();                           //move to the next step
              });
            }
  
            var max_habarites = Math.max(
              $element.outerWidth(),
              $element.outerHeight()
            );
            var radius = step_data.radius || Math.round(max_habarites / 2) + 5;
            var offset = $element.offset();
            var w = $element.outerWidth();
            var h = $element.outerHeight();
            var shape_margin =
              step_data.margin !== undefined ? step_data.margin : 10;
    
            var coords = {
              x: offset.left + Math.round(w / 2),
              y: offset.top + Math.round(h / 2) - $(document).scrollTop()
            };
    
            var shape_data = {
              enjoyHintElementSelector: step_data.selector,
              center_x: coords.x,
              center_y: coords.y,
              text: step_data.description,
              arrowColor: step_data.arrowColor,
              top: step_data.top,
              bottom: step_data.bottom,
              left: step_data.left,
              right: step_data.right,
              margin: step_data.margin,
              scroll: step_data.scroll,
              preventEvents: step_data.preventEvents
            };
  
            var customBtnProps = {
                nextButton: step_data.nextButton,
                prevButton: step_data.prevButton
            }
  
            if (shape_data.center_x === 0 && shape_data.center_y === 0) {
              $body.enjoyhint("hide");
              destroyEnjoy();
              return console.log("Error: Element position couldn't be reached");
            }
    
            if (step_data.shape && step_data.shape == "circle") {
              shape_data.shape = "circle";
              shape_data.radius = radius;
            } else {
              shape_data.radius = 0;
              shape_data.width = w + shape_margin;
              shape_data.height = h + shape_margin;
            }
    
            $body.enjoyhint("render_label_with_shape", shape_data, that.stop, customBtnProps);
            
          }, scrollSpeed + 20 || 270);
        }, timeout);
      };
    
      var nextStep = function() {
        current_step++;
        stepAction();
      };
  
      var prevStep = function() {
        current_step--;
        stepAction();
      };
    
      var skipAll = function() {
        var step_data = data[current_step];
        var $element = $(step_data.selector);
    
        off(step_data.event);
        $element.off(makeEventName(step_data.event));
    
        destroyEnjoy();
      };
    
      var makeEventName = function(name, is_custom) {
        return name + (is_custom ? "custom" : "") + ".enjoy_hint";
      };
    
      var on = function(event_name, callback) {
        $body.on(makeEventName(event_name, true), callback);
      };
    
      var off = function(event_name) {
        $body.off(makeEventName(event_name, true));
      };
    
      /********************* PUBLIC METHODS ***************************************/
    
      window.addEventListener(
        "resize",
        function() {
          if ($event_element != null) {
            $body.enjoyhint(
              "redo_events_near_rect",
              $event_element[0].getBoundingClientRect()
            );
          }
        },
        false
      );
    
      that.stop = function() {
        skipAll();
      };
    
      that.reRunScript = function(cs) {
        current_step = cs;
        stepAction();
      };
    
      that.runScript = function() {
        current_step = 0;
        options.onStart();
        stepAction();
      };
    
      that.resumeScript = function() {
        stepAction();
      };
    
      that.setCurrentStep = function(cs) {
        current_step = cs;
      };
    
      that.getCurrentStep = function() {
        return current_step;
      };
    
      that.trigger = function(event_name) {
        switch (event_name) {
          case "next":
            nextStep();
            break;
    
          case "skip":
            skipAll();
            options.onSkip();
            break;
    
          default: $body.trigger(makeEventName(event_name, true));
        }
      };
    
      that.setScript = function(_data) {
        if (!(_data instanceof Array) && _data.length < 1) {
          throw new Error("Configurations list isn't correct.");
        }
    
        data = _data;
      };
    
      //support deprecated API methods
      /**
       * Configure data list
       */
      that.set = function(_data) {
        that.setScript(_data);
      };
    
      that.setSteps = function(_data) {
        that.setScript(_data);
      };
    
      that.run = function() {
        that.runScript();
      };
    
      that.resume = function() {
        that.resumeScript();
      };
    
      init();
    };
    return EnjoyHint;
  })
  
  
  