/**
 * Copyright (c) Tiny Technologies, Inc. All rights reserved.
 * Licensed under the LGPL or a commercial license.
 * For LGPL see License.txt in the project root for license information.
 * For commercial licenses see https://www.tiny.cloud/
 */

import Rect from 'tinymce/core/api/geom/Rect';
import Factory from 'tinymce/core/api/ui/Factory';
import LoadImage from '../core/LoadImage';
import CropRect from './CropRect';
import { Image, document } from '@ephox/dom-globals';

const create = function (settings) {
  const Control = Factory.get('Control');
  const ImagePanel = Control.extend({
    Defaults: {
      classes: 'imagepanel'
    },

    selection (rect) {
      if (arguments.length) {
        this.state.set('rect', rect);
        return this;
      }

      return this.state.get('rect');
    },

    imageSize () {
      const viewRect = this.state.get('viewRect');

      return {
        w: viewRect.w,
        h: viewRect.h
      };
    },

    toggleCropRect (state) {
      this.state.set('cropEnabled', state);
    },

    imageSrc (url) {
      const self = this, img = new Image();

      img.src = url;

      LoadImage.loadImage(img).then(function () {
        let rect, $img;
        const lastRect = self.state.get('viewRect');

        $img = self.$el.find('img');
        if ($img[0]) {
          $img.replaceWith(img);
        } else {
          const bg = document.createElement('div');
          bg.className = 'mce-imagepanel-bg';
          self.getEl().appendChild(bg);
          self.getEl().appendChild(img);
        }

        rect = { x: 0, y: 0, w: img.naturalWidth, h: img.naturalHeight };
        self.state.set('viewRect', rect);
        self.state.set('rect', Rect.inflate(rect, -20, -20));

        if (!lastRect || lastRect.w !== rect.w || lastRect.h !== rect.h) {
          self.zoomFit();
        }

        self.repaintImage();
        self.fire('load');
      });
    },

    zoom (value) {
      if (arguments.length) {
        this.state.set('zoom', value);
        return this;
      }

      return this.state.get('zoom');
    },

    postRender () {
      this.imageSrc(this.settings.imageSrc);
      return this._super();
    },

    zoomFit () {
      const self = this;
      let $img, pw, ph, w, h, zoom, padding;

      padding = 10;
      $img = self.$el.find('img');
      pw = self.getEl().clientWidth;
      ph = self.getEl().clientHeight;
      w = $img[0].naturalWidth;
      h = $img[0].naturalHeight;
      zoom = Math.min((pw - padding) / w, (ph - padding) / h);

      if (zoom >= 1) {
        zoom = 1;
      }

      self.zoom(zoom);
    },

    repaintImage () {
      let x, y, w, h, pw, ph, $img, $bg, zoom, rect, elm;

      elm = this.getEl();
      zoom = this.zoom();
      rect = this.state.get('rect');
      $img = this.$el.find('img');
      $bg = this.$el.find('.mce-imagepanel-bg');
      pw = elm.offsetWidth;
      ph = elm.offsetHeight;
      w = $img[0].naturalWidth * zoom;
      h = $img[0].naturalHeight * zoom;
      x = Math.max(0, pw / 2 - w / 2);
      y = Math.max(0, ph / 2 - h / 2);

      $img.css({
        left: x,
        top: y,
        width: w,
        height: h
      });

      $bg.css({
        left: x,
        top: y,
        width: w,
        height: h
      });

      if (this.cropRect) {
        this.cropRect.setRect({
          x: rect.x * zoom + x,
          y: rect.y * zoom + y,
          w: rect.w * zoom,
          h: rect.h * zoom
        });

        this.cropRect.setClampRect({
          x,
          y,
          w,
          h
        });

        this.cropRect.setViewPortRect({
          x: 0,
          y: 0,
          w: pw,
          h: ph
        });
      }
    },

    bindStates () {
      const self = this;

      function setupCropRect(rect) {
        self.cropRect = CropRect(
          rect,
          self.state.get('viewRect'),
          self.state.get('viewRect'),
          self.getEl(),
          function () {
            self.fire('crop');
          }
        );

        self.cropRect.on('updateRect', function (e) {
          let rect = e.rect;
          const zoom = self.zoom();

          rect = {
            x: Math.round(rect.x / zoom),
            y: Math.round(rect.y / zoom),
            w: Math.round(rect.w / zoom),
            h: Math.round(rect.h / zoom)
          };

          self.state.set('rect', rect);
        });

        self.on('remove', self.cropRect.destroy);
      }

      self.state.on('change:cropEnabled', function (e) {
        self.cropRect.toggleVisibility(e.value);
        self.repaintImage();
      });

      self.state.on('change:zoom', function () {
        self.repaintImage();
      });

      self.state.on('change:rect', function (e) {
        const rect = e.value;

        if (!self.cropRect) {
          setupCropRect(rect);
        }

        self.cropRect.setRect(rect);
      });
    }
  });

  return new ImagePanel(settings);
};

export default {
  create
};