$(function () {

  'use strict';

  var console = window.console || { log: function () {} };
  var $image = $('#image');
  var $download = $('#download');
  var $dataX = $('#dataX');
  var $dataY = $('#dataY');
  var $dataHeight = $('#dataHeight');
  var $dataWidth = $('#dataWidth');
  var $dataRotate = $('#dataRotate');
  var $dataScaleX = $('#dataScaleX');
  var $dataScaleY = $('#dataScaleY');
  var $dataBrush = $('#dataBrush');
  var $dataBrushPoints = $('#dataBrushPoints');
  var $dataBrushColor = $('#dataBrushColor');
  var $dataBrushSize = $('#dataBrushSize');
  var $brushStatus = $('#brushStatus');
  var $imgContainer = $('.img-container');
  var $brushCanvas = $('#brushCanvas');
  var $brushSize = $('#brushSize');
  var $brushSizeText = $('#brushSizeText');
  var $brushColor = $('#brushColor');
  var $toggleBrush = $('#toggleBrush');
  var brushCanvas = $brushCanvas[0];
  var brushCtx = brushCanvas ? brushCanvas.getContext('2d') : null;
  var brushData = {
    enabled: false,
    size: 24,
    color: '#ff0000',
    points: []
  };
  var isDrawing = false;
  var options = {
        aspectRatio: NaN,
        autoCropArea: 1,
        preview: '.img-preview',
        crop: function (e) {
          $dataX.val(Math.round(e.x));
          $dataY.val(Math.round(e.y));
          $dataHeight.val(Math.round(e.height));
          $dataWidth.val(Math.round(e.width));
          $dataRotate.val(e.rotate);
          $dataScaleX.val(e.scaleX);
          $dataScaleY.val(e.scaleY);
        }
      };

  function syncBrushData() {
    if ($dataBrush.length) {
      $dataBrush.val(JSON.stringify({
        size: brushData.size,
        color: brushData.color,
        points: brushData.points
      }));
    }
    if ($dataBrushPoints.length) {
      $dataBrushPoints.val(encodeURIComponent(JSON.stringify(brushData.points)));
    }
    if ($dataBrushColor.length) {
      $dataBrushColor.val(brushData.color);
    }
    if ($dataBrushSize.length) {
      $dataBrushSize.val(brushData.size);
    }
  }

  function getImageData() {
    if (!$image.data('cropper')) {
      return null;
    }
    return $image.cropper('getImageData');
  }

  function getDisplayRect() {
    var imageData = getImageData();
    var imgEl;
    var imgRect;
    var canvasRect;
    if (!imageData || !brushCanvas) {
      return null;
    }
    imgEl = $imgContainer.find('.cropper-canvas img').get(0);
    if (!imgEl) {
      return null;
    }
    imgRect = imgEl.getBoundingClientRect();
    canvasRect = brushCanvas.getBoundingClientRect();
    return {
      left: imgRect.left - canvasRect.left,
      top: imgRect.top - canvasRect.top,
      width: imgRect.width,
      height: imgRect.height,
      naturalWidth: imageData.naturalWidth,
      naturalHeight: imageData.naturalHeight
    };
  }

  function ensureCanvasInCropper() {
    var $cropperContainer = $imgContainer.find('.cropper-container');
    if (!$cropperContainer.length || !$brushCanvas.length) {
      return;
    }
    if (!$brushCanvas.parent().is($cropperContainer)) {
      $brushCanvas.appendTo($cropperContainer);
      $brushCanvas.css({
        position: 'absolute',
        left: 0,
        top: 0,
        'z-index': 20
      });
    }
  }

  function updateCanvasSize() {
    var $cropperContainer = $imgContainer.find('.cropper-container');
    if (!brushCanvas || !$imgContainer.length || !$cropperContainer.length) {
      return;
    }
    var cropperWidth = Math.round($cropperContainer.innerWidth());
    var cropperHeight = Math.round($cropperContainer.innerHeight());
    brushCanvas.width = cropperWidth;
    brushCanvas.height = cropperHeight;
    $brushCanvas.css({
      left: '0px',
      top: '0px',
      width: cropperWidth + 'px',
      height: cropperHeight + 'px'
    });
  }

  function renderBrushOverlay() {
    var displayRect;
    if (!brushCtx) {
      return;
    }
    ensureCanvasInCropper();
    updateCanvasSize();
    displayRect = getDisplayRect();
    if (!displayRect || !displayRect.width || !displayRect.height) {
      return;
    }
    brushCtx.clearRect(0, 0, brushCanvas.width, brushCanvas.height);
    if (!brushData.points.length) {
      syncBrushData();
      renderBrushStatus();
      return;
    }

    var scaleX = displayRect.width / displayRect.naturalWidth;
    var scaleY = displayRect.height / displayRect.naturalHeight;
    $.each(brushData.points, function (i, point) {
      var drawX = displayRect.left + point.x * scaleX;
      var drawY = displayRect.top + point.y * scaleY;
      var drawR = Math.max(3, point.r * ((scaleX + scaleY) / 2));
      brushCtx.fillStyle = point.c || brushData.color;
      brushCtx.globalAlpha = 0.45;
      brushCtx.beginPath();
      brushCtx.arc(drawX, drawY, drawR, 0, Math.PI * 2, false);
      brushCtx.fill();
    });
    brushCtx.globalAlpha = 1;

    syncBrushData();
    renderBrushStatus();
  }

  function renderBrushStatus() {
    if (!$brushStatus.length) {
      return;
    }
    if (!brushData.enabled) {
      $brushStatus.text('未开启画笔');
      return;
    }
    $brushStatus.text('已绘制 ' + brushData.points.length + ' 笔，按住鼠标左键在图上涂抹');
  }

  function toNaturalPoint(e) {
    var displayRect = getDisplayRect();
    var rect;
    if (!displayRect || !displayRect.width || !displayRect.height || !brushCanvas) {
      return null;
    }
    rect = brushCanvas.getBoundingClientRect();
    var relX = e.clientX - rect.left;
    var relY = e.clientY - rect.top;
    if (relX < displayRect.left || relY < displayRect.top || relX > displayRect.left + displayRect.width || relY > displayRect.top + displayRect.height) {
      return null;
    }
    var naturalX = Math.round((relX - displayRect.left) * displayRect.naturalWidth / displayRect.width);
    var naturalY = Math.round((relY - displayRect.top) * displayRect.naturalHeight / displayRect.height);
    return {
      x: Math.max(0, Math.min(displayRect.naturalWidth - 1, naturalX)),
      y: Math.max(0, Math.min(displayRect.naturalHeight - 1, naturalY))
    };
  }

  function addBrushPoint(e) {
    var point = toNaturalPoint(e);
    var prev;
    var dx;
    var dy;
    if (!point) {
      return;
    }
    point.r = Math.max(4, Math.round(brushData.size / 2));
    point.c = brushData.color;
    prev = brushData.points.length ? brushData.points[brushData.points.length - 1] : null;
    if (prev) {
      dx = point.x - prev.x;
      dy = point.y - prev.y;
      if ((dx * dx + dy * dy) < (point.r * point.r) / 6) {
        return;
      }
    }
    brushData.points.push(point);
    renderBrushOverlay();
  }

  function setBrushMode(enabled) {
    brushData.enabled = !!enabled;
    if (brushData.enabled) {
      $brushCanvas.show().css('cursor', 'crosshair');
      $toggleBrush.text('关闭画笔').removeClass('btn-warning').addClass('btn-success');
    } else {
      isDrawing = false;
      $brushCanvas.hide();
      $toggleBrush.text('开启画笔').removeClass('btn-success').addClass('btn-warning');
    }
    renderBrushOverlay();
  }


  // Tooltip
  $('[data-toggle="tooltip"]').tooltip();


  // Cropper
  $image.on({
    'build.cropper': function (e) {
      console.log(e.type);
    },
    'built.cropper': function (e) {
      console.log(e.type);
      ensureCanvasInCropper();
      renderBrushOverlay();
    },
    'cropstart.cropper': function (e) {
      console.log(e.type, e.action);
    },
    'cropmove.cropper': function (e) {
      console.log(e.type, e.action);
    },
    'cropend.cropper': function (e) {
      console.log(e.type, e.action);
    },
    'crop.cropper': function (e) {
      console.log(e.type, e.x, e.y, e.width, e.height, e.rotate, e.scaleX, e.scaleY);
      renderBrushOverlay();
    },
    'zoom.cropper': function (e) {
      console.log(e.type, e.ratio);
      setTimeout(renderBrushOverlay, 0);
    }
  }).cropper(options);


  // Buttons
  if (!$.isFunction(document.createElement('canvas').getContext)) {
    $('button[data-method="getCroppedCanvas"]').prop('disabled', true);
  }

  if (typeof document.createElement('cropper').style.transition === 'undefined') {
    $('button[data-method="rotate"]').prop('disabled', true);
    $('button[data-method="scale"]').prop('disabled', true);
  }




  // Options
  $('.docs-toggles').on('change', 'input', function () {
    var $this = $(this);
    var name = $this.attr('name');
    var type = $this.prop('type');
    var cropBoxData;
    var canvasData;

    if (!$image.data('cropper')) {
      return;
    }

    if (type === 'checkbox') {
      options[name] = $this.prop('checked');
      cropBoxData = $image.cropper('getCropBoxData');
      canvasData = $image.cropper('getCanvasData');

      options.built = function () {
        $image.cropper('setCropBoxData', cropBoxData);
        $image.cropper('setCanvasData', canvasData);
      };
    } else if (type === 'radio') {
      options[name] = $this.val();
    }

    $image.cropper('destroy').cropper(options);
  });


  // Methods
  $('.docs-buttons').on('click', '[data-method]', function () {
    var $this = $(this);
    var data = $this.data();
    var $target;
    var result;

    if ($this.prop('disabled') || $this.hasClass('disabled')) {
      return;
    }

    if ($image.data('cropper') && data.method) {
      data = $.extend({}, data); // Clone a new one

      if (typeof data.target !== 'undefined') {
        $target = $(data.target);

        if (typeof data.option === 'undefined') {
          try {
            data.option = JSON.parse($target.val());
          } catch (e) {
            console.log(e.message);
          }
        }
      }

      if (data.method === 'rotate') {
        $image.cropper('clear');
      }

      result = $image.cropper(data.method, data.option, data.secondOption);

      if (data.method === 'rotate') {
        $image.cropper('crop');
      }

      switch (data.method) {
        case 'scaleX':
        case 'scaleY':
          $(this).data('option', -data.option);
          break;

        case 'getCroppedCanvas':
          if (result) {

            // Bootstrap's Modal
            $('#getCroppedCanvasModal').modal().find('.modal-body').html(result);

            if (!$download.hasClass('disabled')) {
              $download.attr('href', result.toDataURL('image/jpeg'));
            }
          }

          break;
      }

      if ($.isPlainObject(result) && $target) {
        try {
          $target.val(JSON.stringify(result));
        } catch (e) {
          console.log(e.message);
        }
      }

    }
  });

  $toggleBrush.on('click', function () {
    setBrushMode(!brushData.enabled);
  });

  $('#clearBrush').on('click', function () {
    brushData.points = [];
    renderBrushOverlay();
  });

  $brushSize.on('input change', function () {
    brushData.size = parseInt($(this).val(), 10) || 24;
    $brushSizeText.text(brushData.size);
    syncBrushData();
    renderBrushOverlay();
  });

  $brushColor.on('change input', function () {
    brushData.color = $(this).val() || '#ff0000';
    syncBrushData();
    renderBrushOverlay();
  });

  $brushCanvas.on('mousedown', function (e) {
    if (!brushData.enabled || e.which !== 1) {
      return;
    }
    isDrawing = true;
    addBrushPoint(e);
    e.preventDefault();
  }).on('mousemove', function (e) {
    if (!brushData.enabled || !isDrawing) {
      return;
    }
    addBrushPoint(e);
    e.preventDefault();
  }).on('mouseup mouseleave', function () {
    isDrawing = false;
  });

  $(window).on('resize', function () {
    renderBrushOverlay();
  });

  updateCanvasSize();
  renderBrushOverlay();
  renderBrushStatus();


  // Keyboard
  $(document.body).on('keydown', function (e) {

    if (!$image.data('cropper') || this.scrollTop > 300) {
      return;
    }

    switch (e.which) {
      case 37:
        e.preventDefault();
        $image.cropper('move', -1, 0);
        break;

      case 38:
        e.preventDefault();
        $image.cropper('move', 0, -1);
        break;

      case 39:
        e.preventDefault();
        $image.cropper('move', 1, 0);
        break;

      case 40:
        e.preventDefault();
        $image.cropper('move', 0, 1);
        break;
    }

  });


  // Import image
  var $inputImage = $('#inputImage');
  var URL = window.URL || window.webkitURL;
  var blobURL;

  if (URL) {
    $inputImage.change(function () {
      var files = this.files;
      var file;

      if (!$image.data('cropper')) {
        return;
      }

      if (files && files.length) {
        file = files[0];

        if (/^image\/\w+$/.test(file.type)) {
          blobURL = URL.createObjectURL(file);
          $image.one('built.cropper', function () {

            // Revoke when load complete
            URL.revokeObjectURL(blobURL);
          }).cropper('reset').cropper('replace', blobURL);
          $inputImage.val('');
        } else {
          window.alert('Please choose an image file.');
        }
      }
    });
  } else {
    $inputImage.prop('disabled', true).parent().addClass('disabled');
  }

});
