<template>
  <div
    ref="panel"
    :class="panelClass"
    :style="panelStyle"
  >
    <button
      v-if="localHandle"
      :style="handleStyle"
      class="handle"
      @click="togglePanel()"
    >
      <span>
        <icon :name="statusIconDirection" />
        <icon :name="statusIconDirection" />
        <icon :name="statusIconDirection" />
      </span>
    </button>

    <header
      v-if="title || closable"
    >
      <h3
        v-if="title"
        v-text="title"
      />

      <TfButton
        v-if="closable"
        class="close"
        type="primary"
        icon="times"
        size="icon-no-fill"
        no-border
        @click="closePanel"
      />
    </header>

    <main
      class="panel-content"
    >
      <slot />
    </main>

    <footer
      slot="footer"
    />
  </div>
</template>

<script>
  export default {
    name: 'TfPanel2',

    props: {
      title: {
        type: String,
        default: '',
      },

      open: {
        type: Boolean,
        default: false,
      },

      closable: {
        type: Boolean,
        default: true,
      },

      handle: {
        type: Boolean,
        default: false,
      },

      // handle alias; TODO deprecate/remove at shared 3.0
      statusBar: {
        type: Boolean,
        default: false,
      },

      animate: {
        type: Boolean,
        default: true,
      },

      trigger: {
        type: String,
        default: null,
      },

      closeOnEscape: {
        type: Boolean,
        default: false,
      },

      position: {
        type: String,
        default: 'right',
      },

      fixedPosition: {
        type: Boolean,
        default: true,
      },

      top: {
        type: [String, Number],
        default: '0px',
      },

      maxWidth: {
        type: String,
        default: '557px',
      },

      minWidth: {
        type: String,
        default: '0px',
      },
    },
    data: () => ({
      handleLeftPosition: null,
      handleRightPosition: null,
    }),

    computed: {
      /**
       * Normalize top position to a string with `px` if needed
       * (Let's standardize on strings with units,
       * since the width props are strings,
       * but still backwards support number positions)
       *
       * @returns {string}
       */
      normalizedTop() {
        return typeof this.top === 'number'
          ? `${this.top}px`
          : this.top;
      },

      /**
       * Get the classes for the panel
       *
       * @returns {Array}
       */
      panelClass() {
        return [
          'panel',
          this.position,
          {
            open: this.open,
            animate: this.animate,
            'has-handle': this.handle,
            fixed: this.fixedPosition,
          },
        ];
      },

      /**
       * Get the inline styles for the panel
       *
       * @returns {object}
       */
      panelStyle() {
        return {
          width: this.maxWidth,
          minWidth: this.open ? this.minWidth : 0,
          top: this.normalizedTop,
          height: `calc(100% - ${this.normalizedTop})`,
        };
      },

      /**
       * Get the inline styles for the handle
       *
       * @returns {object}
       */
      handleStyle() {
        return {
          left: this.handleLeftPosition,
          right: this.handleRightPosition,
          height: `calc(100% - ${this.top}px)`,
        };
      },

      /**
       * Get right direction for carets
       *
       * @returns {string}
       */
      statusIconDirection() {
        if (
          (!this.open && this.position === 'left')
          || (this.open && this.position === 'right')
        ) {
          return 'caret-down';
        }
        return 'caret-up';
      },

      /**
       * Get handle boolean (backwards compatibility with old "status bar" boolean)
       *
       * @returns {boolean}
       */
      localHandle() {
        return this.statusBar || this.handle;
      },
    },

    watch: {
      /**
       * When the panel is opened we need to set the position of the 'handle'
       */
      open() {
        this.setHandlePosition();
      },
    },

    created() {
      if (this.closable) {
        if (this.closeOnEscape) {
          document.addEventListener('keyup', this.escapeKeyListener);
        }
        if (this.closeOnOutsideClick) {
          document.addEventListener('click', this.outsidePanelListener);
        }
      }
    },

    mounted() {
      if (this.localHandle) {
        window.addEventListener('resize', () => {
          this.setHandlePosition();
        });
        this.setHandlePosition();
      }
    },

    destroyed() {
      if (this.closable) {
        if (this.closeOnEscape) {
          document.removeEventListener('keyup', this.escapeKeyListener);
        }
        if (this.closeOnOutsideClick) {
          document.removeEventListener('click', this.outsidePanelListener);
        }
      }
      if (this.localHandle) {
        window.removeEventListener('resize', () => {
          this.setHandlePosition();
        });
      }
    },

    methods: {
      /**
       * set the position of the handle
       */
      setHandlePosition() {
        const windowWidth = window.innerWidth;
        const maxWidthHasPercentage = this.maxWidth.indexOf('%') > -1;
        const minWidth = this.minWidth.replace('px', '');
        let maxPixelWidth;

        if (maxWidthHasPercentage) {
          maxPixelWidth = (this.maxWidth.replace('%', '') / 100) * windowWidth;
        } else {
          maxPixelWidth = this.maxWidth.replace('px', '');
        }

        if (this.position === 'right') {
          if (this.open) {
            this.handleLeftPosition = 'auto';

            if (minWidth && maxPixelWidth < minWidth) {
              this.handleRightPosition = this.minWidth;
            } else {
              this.handleRightPosition = windowWidth - 10 < this.maxWidth.replace('px', '') ? `${windowWidth - 10}px` : this.maxWidth;
            }
          } else {
            this.handleLeftPosition = 'auto';
            this.handleRightPosition = '0px';
          }
        } else if (this.open) {
          if (minWidth && maxPixelWidth < minWidth) {
            this.handleLeftPosition = this.minWidth;
          } else {
            this.handleLeftPosition = windowWidth - 10 < this.maxWidth.replace('px', '') ? `${windowWidth - 10}px` : this.maxWidth;
          }
          this.handleRightPosition = 'auto';
        } else {
          this.handleLeftPosition = '0px';
          this.handleRightPosition = 'auto';
        }
      },

      /**
       * Close the panel
       */
      closePanel() {
        this.$emit('togglePanel', false);
      },

      /**
       * Toggle the panel
       */
      togglePanel() {
        this.$emit('togglePanel', !this.open);
      },

      /**
       * Close panel on escape key
       *
       * @param {object} event
       */
      escapeKeyListener(event) {
        if (event.keyCode === 27) {
          this.closePanel();
        }
      },

      /**
       * Return color value as reactive value
       *
       * @param {object} event
       */
      outsidePanelListener(event) {
        const { target } = event;
        const panel = this.$el;
        const isInPanel = this.isChildOf(target, panel);
        if (!isInPanel && this.closable) {
          this.closePanel();
        }
      },

      /**
       * Check if element is child of another element
       *
       * @param {object} child
       * @param {object} parent
       * @returns {boolean}
       */
      isChildOf(child, parent) {
        if (child.parentNode === parent) {
          return true;
        } if (child.parentNode === null) {
          return false;
        }
        return this.isChildOf(child.parentNode, parent);
      },
    },
  };
</script>
<style lang="scss" scoped>
@import 'src/assets/styles/mixins';
@import 'src/assets/styles/variables';

.panel {
  display: flex;
  flex-direction: column;
  right: 0;
  z-index: 100;
  max-width: 0;
  box-sizing: border-box;
  background: $tf-white;
  box-shadow: 0 0 6px 0 rgba($tf-black, .04), 0 2px 4px 0 rgba($tf-black, .12);
  border: solid 1px $tf-light-gray;
  color: $tf-black;
  text-align: center;
  overflow: hidden;
  position: relative;
  -ms-overflow-style: -ms-autohiding-scrollbar;

  &.fixed {
    position: fixed;
  }

  &:not(.fixed).has-handle {
    margin-left: 8px;
  }

  &.animate {
    transition: width .5s;
  }

  &.left {
    right: auto;
    left: 0;
  }

  &.open {
    max-width: 100%;
    overflow-y: auto;
  }
}

.panel-content {
  display: flex;
  flex: 1;
  flex-direction: column;
  overflow-y: auto;
}

.handle {
  background: $tf-light-blue;
  border: 0;
  border-left: 1px solid $tf-light-gray;
  border-right: 1px solid $tf-light-gray;
  overflow: hidden;
  cursor: pointer;
  height: calc(100% + 1px);
  margin-top: -1px;
  position: fixed;
  z-index: 10;
  width: 14px;
  padding: 0;

  &:focus {
    border-color: $tf-medium-gray;
    outline: none;
  }

  span {
    position: relative;
    left: -4px;
  }

  svg {
    color: $tf-light-gray;
    transform: rotate(-90deg);
    transform-origin: left top 0;
  }

  .left & {
    box-shadow: 4px 0 5px 0 rgba($tf-black, .25);
  }

  .right & {
    box-shadow: -4px 0 5px 0 rgba($tf-black, .25);
  }
}

header {
  margin: 0;
  padding: 4px 4px 4px 12px;
  background: $tf-extra-light-gray-2;
  border-bottom: 1px solid $tf-light-gray;
  display: flex;
  align-items: flex-start;
}

h3 {
  margin: 0;
  padding: 6px;
  font-size: 16px;
  line-height: 20px;
  font-weight: 600;
  text-align: left;
  flex-grow: 1;
}
</style>
