import {
  Component,
  EventEmitter,
  Input,
  OnDestroy,
  OnChanges,
  OnInit,
  Output,
  ApplicationRef,
  ChangeDetectorRef,
  ViewChild, ViewChildren
} from '@angular/core';
import * as _ from 'lodash';
import { NzMessageService } from 'ng-zorro-antd';

import {HttpClient} from '@angular/common/http';


import html2canvas from 'html2canvas';

const AnimationType = [
  {
    name: 'Slide',
    value: 'animated fadeInRight'
  },
  {
    name: 'Fade',
    value: 'animated fadeInDown'
  },
  {
    name: 'Zoom',
    value: 'animated zoomInUp'
  },
  {
    name: 'Jack',
    value: 'animated rotateIn' //  jackInTheBox
  },
  {
    name: 'Roll',
    value: 'animated rollIn'
  }
];


@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.scss']
})
export class FormComponent implements OnInit, OnChanges, OnDestroy {

  // 储存数据用
  saveKey = 'ww_text';
  // 储存对象
  item;
  @ViewChild('box', {static: true})
  box;
  @ViewChildren('list')
  list;
  curDom;
  itemBackup: any;

  isMovingItem = false;
  ratio: number;
  moveOffset: any;
  fontFamilyList: string[];
  fontSizeRange: number[];
  colorList: string[];
  MIN_FONT_SIZE = 1;
  MAX_FONT_SIZE = 12;
  isShowFontColorPane = false;
  isShowBGColorPane = false;
  isShowAnimationPane = false;
  isShowAnimationOrder = true;

  fontFamily: string;
  bgColor: string;
  fontSize: number;
  fontColor = 'black';
  position: any;
  curAnimationName: string;
  animations: any[];
  _selectedAnimation: any;
  extraData = {
    changeDirtyCount: 0
  };
  _curItem;
  set curItem(value) {
    let changed = false;
    if (_.get(value, 'id') !== _.get(this._curItem, 'id')) {
      changed = true;
    }
    this._curItem = value;
    if (changed) {
      this.onCurItemChanged();
    }
  }

  get curItem() {
    return this._curItem;
  }
  set selectedAnimation(value) {
    let changed = false;
    if (_.get(value, 'id') !== _.get(this._selectedAnimation, 'id')) {
      changed = true;
    }
    this._selectedAnimation = value;
    if (changed) {
      this.onSelectedAnimationChanged();
    }
  }

  get selectedAnimation() {
    return this._selectedAnimation;
  }

  AnimationType = AnimationType;

  uploadUrl;
  uploadData;

  constructor(private appRef: ApplicationRef,
              private http: HttpClient,
              private nzMessageService: NzMessageService,
              private changeDetectorRef: ChangeDetectorRef) {
    this.uploadUrl = (<any> window).courseware.uploadUrl();
    this.fontSizeRange = [];
    for (let i = this.MIN_FONT_SIZE; i <= this.MAX_FONT_SIZE; ++i) {
      this.fontSizeRange.push(i);
    }

    const color_black = '#111111';
    const color_gray = '#aaaaaa';
    const color_silver = '#dddddd';
    const color_navy = '#001f3f';
    const color_blue = '#0074d9';
    const color_aqua = '#7fdbff';
    const color_teal = '#39cccc';
    const color_olive = '#3d9970';
    const color_green = '#2ecc40';
    const color_lime = '#01ff70';
    const color_yellow = '#ffdc00';
    const color_orange = '#ff851b';
    const color_red = '#ff4136';
    const color_maroon = '#85144b';
    const color_fuchsia = '#f012be';
    const color_purple = '#b10dc9';

    // Ken 2018-10-30 14:37 宁波那边要加5个颜色
    this.colorList = [
      color_black,
      'white',
      '#595959',
      color_gray,
      color_silver,
      color_navy,
      color_blue,
      'blue',
      color_aqua,
      color_teal,
      '#64c0bd',
      color_olive,
      '#72ac4d',
      color_green,
      color_lime,
      'yellow',
      color_yellow,
      color_orange,
      '#f45970',
      color_red,
      '#be0712',
      color_maroon,
      color_fuchsia,
      color_purple
    ];

    this.fontFamilyList = [
      'Arial',
      'monospace',
      'ChalkboardSE-Regular'
    ];
  }

  init() {
    this.curItem = null;
    this.extraData.changeDirtyCount = 0;
    this.isMovingItem = false;
    this.item.contentObj.items = this.item.contentObj.items || [];
    // ver 区分数据
    this.item.contentObj.ver = this.item.contentObj.ver || 1;
    this.animations = this.item.contentObj.animations = this.item.contentObj.animations || [];

    // Ken 2018-09-14 09:33 为item添加id属性, 对于旧数据, 要自动添加此属性
    if (!_.get(this.item.contentObj.items, '[0].id')) {
      this.item.contentObj.items.forEach((item, index) => {
        item.id = index + 1;
      });
    }
    this.itemBackup = _.cloneDeep(this.item);

  }
  ngOnInit() {

    this.item = {
      contentObj: {}
    };
    this.init();
    // 获取存储的数据
    ( window as any).courseware.getData((data) => {

      if (data) {
        this.item = data;
      }
      this.init();
      this.changeDetectorRef.markForCheck();
      this.changeDetectorRef.detectChanges();
      this.refresh();

    }, this.saveKey);

  }


  ngOnChanges() {
  }

  ngOnDestroy() {
  }

  /**
   * 储存数据
   */
  save() {
    (window as any).courseware.setData(this.item, null, this.saveKey);
    this.refresh();
  }

  /**
   * 刷新 渲染页面
   */
  refresh() {
    setTimeout(() => {
      this.appRef.tick();
    }, 1);
  }


  resize(rect) {
    if (!this.box) {
      return;
    }
    this.ratio = rect.clientWidth / this.box.nativeElement.clientWidth;
    this.box.nativeElement.style.transform = `scale(${this.ratio})`;
  }

  onEdit(item, event) {
    item._inEdit = true;
    const dom = event.target;
    dom.setAttribute('contenteditable', '');
    dom.classList.add('p-edit');
    dom.focus();
    event.stopPropagation();
    event.preventDefault();
  }

  onBlur(item, dom) {
    if (dom.innerText) {
      if (item.text !== dom.innerText.trim()) {
        item.text = dom.innerText.trim();
        this.extraData.changeDirtyCount++;
      }
      item._inEdit = false;
      dom.removeAttribute('contenteditable');
      dom.classList.remove('p-edit');
    } else {
      this.onBtnDelete();
    }
  }

  onTitleChange() {
    this.extraData.changeDirtyCount = this.extraData.changeDirtyCount+1;
    this.createCover();
  }

  createCover() {
    html2canvas(document.getElementById("canvas")).then((canvas) => {
      // document.body.appendChild(canvas);
      const video_preview_thumb = canvas.toDataURL();
      const img = this.convertImageToBlob(video_preview_thumb);
      const formData = new FormData();
      const ext = img.type.replace('image/', '');
      formData.append('file', img, `cover.${ext}`);

      this.http.post(this.uploadUrl, formData).subscribe(
        (res: any) => {
          (window as any).courseware.sendEvent("screenshot", {"url": res.url}, this.saveKey);
        },
        (err) => {
          console.log(err);
          this.nzMessageService.error('封面截取失败');
        }
      );
    });
  }

  convertImageToBlob(data) {
    const imgType = data.substring(data.indexOf(':') + 1, data.indexOf(';'));
    const binary = atob(data.split(',')[1]);
    const array = [];
    let i = 0;
    while (i < binary.length) {
      array.push (binary.charCodeAt(i));
      i++;
    }
    return new Blob([ new Uint8Array(array) ], {type: imgType});
  }

  onSelect(item, event) {
    this.curItem = item;
    this.curDom = event.target;
    this.fontSize = this.curItem.fontSize;
    this.fontFamily = this.curItem.fontFamily;
    event.stopPropagation();
  }

  onClickBox() {
    this.curItem = null;
  }

  onChangeFontFamily() {
    this.curItem.fontFamily = this.fontFamily;
    this.extraData.changeDirtyCount++;
  }

  onChangeFontSize(delta = 0) {
    if (!this.curItem) {
      return;
    }

    this.fontSize = this.fontSize + delta;
    this.fontSize = Math.max(this.MIN_FONT_SIZE, this.fontSize);
    this.fontSize = Math.min(this.MAX_FONT_SIZE, this.fontSize);

    this.curItem.fontSize = this.fontSize;
    this.extraData.changeDirtyCount++;
  }

  onChangeFontColor() {
    if (!this.curItem) {
      return;
    }
    this.curItem.color = this.fontColor;
    this.extraData.changeDirtyCount++;
  }

  onChangeColor(color) {
    if (this.isShowBGColorPane) {
      this.item.contentObj.bgColor = color;
      this.extraData.changeDirtyCount++;
    } else if (this.isShowFontColorPane) {
      this.fontColor = this.curItem.color = color;
      this.extraData.changeDirtyCount++;
    }
  }

  absolute2Relative(value) {
    return value * this.ratio;
  }

  relative2Absolute(value) {
    return value / this.ratio;
  }

  onMouseDown(item, event) {
    if (item !== this.curItem) {
      return;
    }
    if (this.curItem && !this.curItem._inEdit) {
      this.isMovingItem = true;
      this.moveOffset = {x: event.x, y: event.y};
    }
  }

  onMouseMove(event) {
    if (this.isMovingItem) {
      if (this.curItem) {
        this.curItem.position.left += this.relative2Absolute(event.x - this.moveOffset.x);
        this.curItem.position.top += this.relative2Absolute(event.y - this.moveOffset.y);
        this.moveOffset = {x: event.x, y: event.y};
        this.extraData.changeDirtyCount++;
      }
    }
  }

  onMouseUp(event) {
    this.isMovingItem = false;
  }

  onBtnSave() {
    this.createCover();
    this.save();
    this.extraData.changeDirtyCount = 0;
  }

  onMoveSentence(x, y, event) {
    if (this.curItem && !this.curItem._inEdit) {
      this.curItem.position.left += x;
      this.curItem.position.top += y;
      this.extraData.changeDirtyCount++;
      event.stopPropagation();
      event.preventDefault();
    }
  }

  onBtnMoveToCenter(isHorizontal, isVertical) {
    if (!this.curItem) {
      return;
    }
    const {clientWidth, clientHeight} = this.curDom;
    const {clientWidth: boxClientWidth, clientHeight: boxClientHeight} = this.box.nativeElement;
    if (isHorizontal) {
      this.curItem.position.left = (boxClientWidth - clientWidth) / 2;
    }
    if (isVertical) {
      this.curItem.position.top = (boxClientHeight - clientHeight) / 2;
    }
    this.extraData.changeDirtyCount++;
  }

  onNewSentence(event) {
    const left = this.relative2Absolute(event.layerX);
    const top = this.relative2Absolute(event.layerY);
    const id = _.get(_.last(this.item.contentObj.items), 'id') || 0;
    const item = {
      id: id + 1,
      color: this.fontColor,
      text: 'text',
      fontFamily: this.fontFamily || 'Arial',
      fontSize: this.fontSize || 6,
      _inEdit: false,
      position: {left, top}
    };
    this.item.contentObj.items.push(item);
    setTimeout(() => {
      item._inEdit = true;
      const dom = _.get(this.box.nativeElement.getElementsByClassName('p-selected'), '[0]');
      if (dom) {
        dom.setAttribute('contenteditable', '');
        dom.classList.add('p-edit');
        dom.focus();
        item.position.top -= (dom.clientHeight / 2);
        this.extraData.changeDirtyCount++;
        document.execCommand('selectAll', false, null);
      }
    }, 1);
    this.curItem = item;
    this.extraData.changeDirtyCount++;
  }

  onBtnDelete() {
    const removedItem = _.remove(this.item.contentObj.items, (i) => {
      return i === this.curItem;
    });

    if (removedItem) {
      this.extraData.changeDirtyCount++;
      _.remove(this.animations, {id: this.curItem.id});
      this.curItem = null;
    }
  }

  onBtnRestore() {
    this.extraData.changeDirtyCount = 0;
    this.curItem = null;
    this.item = _.cloneDeep(this.itemBackup);
    this.animations = this.item.contentObj.animations;
  }

  onBtnShowAnimationPane() {
    this.isShowAnimationPane = !this.isShowAnimationPane;
  }

  onBtnToggleDisplayAnimationOrder() {
    this.isShowAnimationOrder = !this.isShowAnimationOrder;
  }

  onBtnMoveAnimation(value) {
    // [value] -1: MoveUp, 1: MoveDown
    if (!this.selectedAnimation) {
      this.nzMessageService.error(`Please select an animation first`);
      return;
    }
    const index = _.findIndex(this.animations, this.selectedAnimation);
    const tmp = this.animations[index + value];
    if (tmp) {
      this.animations[index + value] = this.animations[index];
      this.animations[index] = tmp;
      this.extraData.changeDirtyCount++;
    } else {
      // this.nzMessageService.error(`MoveAnimation Error, index = ${index}, length = ${this.animations.length}`);
    }
  }

  onBtnRemoveAnimation() {
    const removed = _.remove(this.animations, {id: this.selectedAnimation.id});
    if (removed) {
      this.extraData.changeDirtyCount++;
    }
  }

  onClickAnimation(item) {
    this.selectedAnimation = item;
    this.curAnimationName = item.value;
  }

  onSetAnimation(item) {
    if (!this.curItem) {
      this.nzMessageService.warning('Please select a text which you want to set animation');
      return;
    }

    const animation = _.find(this.animations, {id: this.curItem.id});
    if (!animation) {
      this.animations.push({
        id: this.curItem.id,
        name: item.name,
        value: item.value,
        initStyle: {opacity: 0},
        beforeAnimation: {opacity: 1},
      });
      this.extraData.changeDirtyCount++;
    } else if (animation.name !== item.name) {
      animation.name = item.name;
      animation.value = item.value;
      this.extraData.changeDirtyCount++;
    }
  }

  // curItem changed
  onCurItemChanged() {
    if (!this.curItem) {
      this.selectedAnimation = null;
      this.curAnimationName = null;
      return;
    }
    this.selectedAnimation = _.find(this.animations, {id: this.curItem.id});
    if (this.selectedAnimation) {
      this.curAnimationName = this.selectedAnimation.value;
    }
  }

  // selectedAnimation changed
  onSelectedAnimationChanged() {
    if (!this.selectedAnimation) {
      return;
    }
    this.curItem = _.find(this.item.contentObj.items, {id: this.selectedAnimation.id});
  }

  getIndexOfAnimationByItem(item) {
    return _.findIndex(this.animations, {id: item.id});
  }

}