(function (context, $) {

  "use strict";
  context.JK = context.JK || {};
  context.JK.AdjustGearSpeedDialog = function (app) {
    var AUDIO_DEVICE_BEHAVIOR = context.JK.AUDIO_DEVICE_BEHAVIOR;
    var gearUtils = context.JK.GearUtils;
    var logger = context.JK.logger;
    var rest = context.JK.Rest();
    var $dialog = null;
    var modUtils = context.JK.ModUtils;

    var $runTestBtn = null;
    var $scoreReport = null;
    var $speedOptions = null;
    var $saveBtn = null;
    var $cancelBtn = null;
    var $fairLabel = null;
    var $slowLabel = null;
    var $fastLabel = null;

    var startingFramesize = null;
    var startingBufferIn = null;
    var startingBufferOut = null;

    var frameBuffers = new context.JK.FrameBuffers(app);
    var gearTest = new context.JK.GearTest(app);

    var selectedDeviceInfo;
    var deviceInformation;
    var operatingSystem;
    var frameBuffers;
    var $frameBuffers;
    var gearTest;

    var $advanced;

    function attemptScore() {
      gearTest.attemptScore(selectedDeviceInfo);
    }

    function invalidateScore() {
      gearTest.invalidateScore();
    }

    function getGearTest() {
      return gearTest;
    }

    function updateDefaultBuffers() {
      gearUtils.updateDefaultBuffers(selectedDeviceInfo, frameBuffers)
    }

    function onFramesizeChanged() {
      //context.JK.prodBubble($resyncBtn, 'push-resync-when-done', {}, {positions:['top']});
      updateDefaultBuffers();
      context.jamClient.FTUESetFrameSize(frameBuffers.selectedFramesize());
      invalidateScore();
    }

    function onBufferInChanged() {
      //context.JK.prodBubble($resyncBtn, 'push-resync-when-done', {}, {positions:['top']});
      context.jamClient.FTUESetInputLatency(frameBuffers.selectedBufferIn());
      invalidateScore();
    }

    function onBufferOutChanged() {
      //context.JK.prodBubble($resyncBtn, 'push-resync-when-done', {}, {positions:['top']});
      context.jamClient.FTUESetOutputLatency(frameBuffers.selectedBufferOut());
      invalidateScore();
    }

    function freezeAudioInteraction() {
      logger.debug("adjustGearSpeed: freezing audio interaction");
      frameBuffers.disable();
      $speedOptions.iCheck('disable')
      $cancelBtn.on('click', false).addClass('disabled');
      $runTestBtn.on('click', false).addClass('disabled');
    }

    function unfreezeAudioInteraction() {
      logger.debug("adjustGearSpeed: unfreezing audio interaction");
      frameBuffers.enable();
      $speedOptions.iCheck('enable')
      $cancelBtn.off('click', false).removeClass('disabled')
      $runTestBtn.off('click', false).removeClass('disabled')
    }


    function updateDefaultLabel() {
      if(selectedDeviceInfo && (selectedDeviceInfo.input.info.type == 'Win32_wdm' ||  selectedDeviceInfo.output.info.type == 'Win32_wdm')) {

      }
      else {
      }
    }

    function translateFrameSizeToSpeed(framesize) {
      if(framesize == 2.5) {
        return 'fast'
      }
      else if(framesize == 5) {
        return 'fair'
      }
      else if (framesize == 10) {
        return "slow"
      }
      else {
        throw "unknown framesize in translateFrameSizeToSpeed: " + framesize
      }
    }

    function beforeShow() {
      selectedDeviceInfo = gearUtils.selectedDeviceInfo(context.jamClient.FTUEGetInputMusicDevice(), context.jamClient.FTUEGetOutputMusicDevice());
      deviceInformation = gearUtils.loadDeviceInfo();
      startingFramesize = context.jamClient.FTUEGetFrameSize();
      startingBufferIn = context.jamClient.FTUEGetInputLatency();
      startingBufferOut = context.jamClient.FTUEGetOutputLatency();
      var startingSpeed = translateFrameSizeToSpeed(startingFramesize)
      logger.debug("speed upon entry: " + startingSpeed)
      $speedOptions.filter('[value=' + startingSpeed + ']').iCheck('check')
      setBuffers(startingSpeed);
      updateDefaultLabel();
      invalidateScore();
      $saveBtn.on('click', false).addClass('disabled');
      app.user().done(function() {
        if(modUtils.getGear('show_frame_options')) {
          $advanced.show();
        }
      })
    }

    function beforeHide() {
    }

    function onCancel() {
      var scoring = gearTest.isScoring();

      if(!scoring) {
        logger.debug("resetting framesize/buffers on cancel of adjust-gear-speed")
        // make sure the frame/buffer values are the same as when entered
        context.jamClient.FTUESetFrameSize(startingFramesize);
        context.jamClient.FTUESetInputLatency(startingBufferIn);
        context.jamClient.FTUESetOutputLatency(startingBufferOut);
      }

      return !scoring;
    }

    function onSave() {

      if($(this).is('.disabled')) {
        logger.debug("cancelling save because not allowed yet")
        return;
      }

      context.jamClient.FTUESetFrameSize(frameBuffers.selectedFramesize());
      context.jamClient.FTUESetInputLatency(frameBuffers.selectedBufferIn());
      context.jamClient.FTUESetOutputLatency(frameBuffers.selectedBufferOut());

      app.layout.closeDialog('adjust-gear-speed-dialog')

      return false;
    }

    function onGearTestStarted(e, data) {
      renderScoringStarted();
    }

    function onGearTestDone(e, data) {
      renderScoringStopped();
      $saveBtn.off('click', false).removeClass('disabled');
      gearUtils.postDiagnostic(operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, true);
    }

    function onGearTestFail(e, data) {
      renderScoringStopped();
      $saveBtn.on('click', false).addClass('disabled');
      gearUtils.postDiagnostic(operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, true);
    }

    function renderScoringStarted() {
      freezeAudioInteraction();
    }

    function renderScoringStopped() {
      unfreezeAudioInteraction();
    }

    function setBuffers(speed) {
      var newFrameSize = null;
      if(speed == 'fast') {
        newFrameSize = 2.5
      }
      else if (speed == 'fair') {
        newFrameSize = 5
      }
      else if (speed == 'slow') {
        newFrameSize = 10
      }
      else {
        throw "unknown speed setting: " + speed;
      }

      frameBuffers.setFramesize(newFrameSize);
      jamClient.FTUESetFrameSize(newFrameSize);
      updateDefaultBuffers();
    }

    function onSpeedChanged() {

      setTimeout(function() {
        var speed = $dialog.find('.speed-option .iradio_minimal.checked input').val()

        setBuffers(speed);

        attemptScore();
      }, 1)

    }

    function initialize() {
      var dialogBindings = {
        'beforeShow': beforeShow,
        'beforeHide': beforeHide,
        'onCancel' : onCancel
      };

      app.bindDialog('adjust-gear-speed-dialog', dialogBindings);

      $dialog = $('#adjust-gear-speed-dialog');

      $runTestBtn = $dialog.find('.run-test-btn');
      $scoreReport = $dialog.find('.results');
      $saveBtn = $dialog.find('.btnSave')
      $cancelBtn = $dialog.find('.btnCancel')
      $slowLabel = $dialog.find('label[for="adjust-gear-speed-slow"]')
      $fairLabel = $dialog.find('label[for="adjust-gear-speed-fair"]')
      $fastLabel = $dialog.find('label[for="adjust-gear-speed-fast"]')

      operatingSystem = context.JK.GetOSAsString();

      $frameBuffers = $dialog.find('.frame-and-buffers');
      frameBuffers.initialize($frameBuffers);
      $(frameBuffers)
        .on(frameBuffers.FRAMESIZE_CHANGED, onFramesizeChanged)
        .on(frameBuffers.BUFFER_IN_CHANGED, onBufferInChanged)
        .on(frameBuffers.BUFFER_OUT_CHANGED, onBufferOutChanged)


      gearTest.initialize($scoreReport, true)
      $(gearTest)
        .on(gearTest.GEAR_TEST_START, onGearTestStarted)
        .on(gearTest.GEAR_TEST_DONE, onGearTestDone)
        .on(gearTest.GEAR_TEST_FAIL, onGearTestFail)

      $runTestBtn.click(attemptScore);

      $dialog.data('result', gearTest); // so that others can peek into gear test data after dialog is closed

      $advanced = $dialog.find('.advanced');
      $speedOptions = $dialog.find('.speed-option input');
      context.JK.checkbox($speedOptions).on('ifClicked', onSpeedChanged)

      $saveBtn.click(onSave)
    };


    this.getGearTest  = getGearTest;
    this.initialize = initialize;
  }

  return this;
})(window, jQuery);