(function (context, $) {

  "use strict";

  context.JK = context.JK || {};
  context.JK.Wizard = function (app) {

    var STEPS = null;
    var step = null;
    var previousStep  = null;
    var $dialog = null;
    var $templateButtons = null;
    var $wizardSteps = null;
    var $currentWizardStep = null;
    var $wizardButtons = null;
    var options = {};
    var $btnHelp = null;
    var $btnNext = null;
    var $btnBack = null;
    var $btnClose = null;
    var $btnCancel = null;
    var dialogName = null;
    var self = this;
    var $self = $(this);

    function totalSteps() {
      return context.JK.dkeys(STEPS).length;
    }

    function beforeHideStep() {
      var currentStep = getCurrentStep();
      if(currentStep === null) return;

      var stepInfo = STEPS[currentStep];

      if (!stepInfo) {
        throw "unknown step: " + currentStep;
      }

      if(stepInfo.beforeHide) {
        stepInfo.beforeHide.call(stepInfo);
      }
    }

    function beforeShowStep($step) {
      var stepInfo = STEPS[step];

      if (!stepInfo) {
        throw "unknown step: " + step;
      }

      stepInfo.beforeShow.call(stepInfo);
    }

    function back() {
      if ($(this).is('.disabled')) return false;
      previousStep = step;
      step = step - 1;
      moveToStep();
      return false;
    }

    function next() {
      if ($(this).is('.disabled')) return false;

      var stepInfo = STEPS[step];
      if(stepInfo.handleNext) {
        var result = stepInfo.handleNext.call(stepInfo);
        if(result === false) {return false;}
      }

      moveToNext();
      return false;
    }

    function moveToNext() {
      previousStep = step;
      step = step + 1;

      moveToStep();
    }

    function help() {
      if ($(this).is('.disabled')) return false;

      var stepInfo = STEPS[step];
      if(stepInfo.handleHelp) {
        var result = stepInfo.handleHelp.call(stepInfo);
        if(!result) {return false;}

        context.JK.popExternalLink(result);
      }

      return false;
    }

    function moveToStep() {
      var $nextWizardStep = $wizardSteps.filter($('[layout-wizard-step=' + step + ']'));

      beforeHideStep();

      $wizardSteps.hide();

      $currentWizardStep = $nextWizardStep;

      context.JK.GA.virtualPageView('/client/' + dialogName, dialogName + ": " + $currentWizardStep.attr('dialog-title'));

      $self.triggerHandler('step_changed', {step:step});

      // update buttons
      var $wizardButtonsContent = $(context._.template($templateButtons.html(), {}, {variable: 'data'}));

      $btnHelp = $wizardButtonsContent.find('.btn-help');
      $btnBack = $wizardButtonsContent.find('.btn-back');
      $btnNext = $wizardButtonsContent.find('.btn-next');
      $btnClose = $wizardButtonsContent.find('.btn-close');
      $btnCancel = $wizardButtonsContent.find('.btn-cancel');

      // hide help button if on last step
      if (step == totalSteps() - 1) {
          $btnHelp.hide();
      }
      // hide back button if 1st step or last step
      if (step == 0 || step == totalSteps() - 1) {
        $btnBack.hide();
      }
      // hide next button if on last step
      if (step == totalSteps() - 1) {
        $btnNext.hide();
      }
      // hide close if not on last step
      if (step != totalSteps() - 1) {
        $btnClose.hide();
      }
      // hide cancel if not on last step
      if (step == totalSteps() - 1) {
        $btnCancel.hide();
      }

      $btnHelp.on('click', help);
      $btnNext.on('click', next);
      $btnBack.on('click', back);
      $btnClose.on('click', function() {$self.triggerHandler('wizard_close'); return false;});
      $btnCancel.on('click', function() {$self.triggerHandler('wizard_cancel'); return false;});

      $wizardButtons.empty();
      $wizardButtons.append($wizardButtonsContent);

      beforeShowStep($currentWizardStep);
      $currentWizardStep.show();

    }

    // called by owner whenever
    function onCloseDialog() {
      beforeHideStep();
    }

    function onBeforeShow(args) {

      context._.each(STEPS, function(step) {
        // let every step know the wizard is being shown
        if(step.beforeWizardShow) {
          step.beforeWizardShow(args);
        }
      });

      $currentWizardStep = null;
      previousStep = null;

      step = args != null ? args.d1 : 0;
      if (!step) step = 0;
      step = parseInt(step);
      moveToStep();
    }

    function onAfterHide() {
      step = null;
    }

    function getNextButton() {
      return $btnNext;
    }

    function setNextState(enabled) {

      if(!$btnNext) return;

      if(enabled) {
        $btnNext.removeClass('disabled');
      }
      else {
        $btnNext.addClass('disabled');
      }

    }

    function setBackState(enabled) {

      if(!$btnBack) return;

      if(enabled) {
        $btnBack.removeClass('disabled');
      }
      else {
        $btnBack.addClass('disabled');
      }
    }

    function getCurrentStep() {
      if($currentWizardStep) {
        return parseInt($currentWizardStep.attr('layout-wizard-step'));
      }
      else {
        return null;
      }

    }

    function getCurrentWizardStep() {
      return $currentWizardStep;
    }

    function getDialog() {
      return $dialog;
    }

    function initialize(_$dialog, _$wizardSteps, _STEPS, _options) {
      $dialog = _$dialog;
      dialogName = $dialog.attr('layout-id');
      if (!dialogName) throw "no dialog name (layout-id) in wizard";
      $wizardSteps = _$wizardSteps;
      STEPS = _STEPS;

      $wizardButtons = $dialog.find('.wizard-buttons');
      $templateButtons = $('#template-wizard-buttons');

      if(_options) {_options = {}};
      options = _options;
    }

    this.getNextButton = getNextButton;
    this.setNextState = setNextState;
    this.setBackState = setBackState;
    this.moveToNext = moveToNext;
    this.getCurrentStep = getCurrentStep;
    this.getCurrentWizardStep = getCurrentWizardStep;
    this.onCloseDialog = onCloseDialog;
    this.onBeforeShow = onBeforeShow;
    this.onAfterHide = onAfterHide;
    this.getDialog = getDialog;
    this.initialize = initialize;

  }

})(window, jQuery);