/**
 * @license
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import {
  css,
  customElement,
  html,
  internalProperty,
  LitElement,
  property,
  PropertyValues,
} from 'lit-element';
import {StyleInfo, styleMap} from 'lit-html/directives/style-map';
import {Rect} from './util';

/**
 * Displays its slotted content at a given scale, centered over a given point,
 * while ensuring the content always fills the container. The content does not
 * have to be a single image, it can be arbitrary HTML. To prevent user
 * confusion, it should ideally be image-like, i.e. have limited or no
 * interactivity, as the component does not prevent events or focus from
 * reaching the slotted content.
 */
@customElement('gr-zoomed-image')
export class GrZoomedImage extends LitElement {
  @property({type: Number}) scale = 1;

  @property({type: Object})
  frameRect: Rect = {origin: {x: 0, y: 0}, dimensions: {width: 0, height: 0}};

  @internalProperty() protected imageStyles: StyleInfo = {};

  static styles = css`
    :host {
      display: block;
    }
    ::slotted(*) {
      display: block;
    }
    #clip {
      position: relative;
      width: 100%;
      height: 100%;
      overflow: hidden;
    }
    #transform {
      position: absolute;
      transform-origin: top left;
      will-change: transform;
    }
  `;

  render() {
    return html`
      <div id="clip">
        <div id="transform" style="${styleMap(this.imageStyles)}">
          <slot></slot>
        </div>
      </div>
    `;
  }

  updated(changedProperties: PropertyValues) {
    if (changedProperties.has('scale') || changedProperties.has('frameRect')) {
      this.updateImageStyles();
    }
  }

  private updateImageStyles() {
    const {x, y} = this.frameRect.origin;
    this.imageStyles = {
      'image-rendering': this.scale >= 1 ? 'pixelated' : 'auto',
      transform: `translate(${-x}px, ${-y}px) scale(${this.scale})`,
    };
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'gr-zoomed-image': GrZoomedImage;
  }
}
