import Blockly, { WorkspaceSvg, Xml } from 'blockly';
const bct = require('@blockly/continuous-toolbox');
import 'blockly/javascript';
import './blockly-vex';

// Blockの読み込み
import './blocks/block';
import { Cpp } from './generators/cpp';

Blockly.HSV_SATURATION = 0.7;
Blockly.HSV_VALUE = 0.8;

// continuous-toolboxの為のパッチ当て --------
class CppContinuousToolbox extends bct.ContinuousToolbox {
  constructor(w: WorkspaceSvg) {
    Cpp.createVariableCategory(w);
    super(w);
  }
}
// -------------------------------------------

export class BlocklyApp {
  readonly workspace: WorkspaceSvg;

  constructor(parent: string | Element, toolbox: string) {
    this.workspace = Blockly.inject(parent, {
      plugins: {
        toolbox: CppContinuousToolbox,
        flyoutsVerticalToolbox: bct.ContinuousFlyout,
        metricsManager: bct.ContinuousMetrics,
      },
      toolbox: Xml.textToDom(toolbox),
      media: 'blockly-media/',
      renderer: 'zelos',
      theme: Blockly.Theme.defineTheme('ClassicHats', {
        base: Blockly.Themes.Classic,
        startHats: true,
      }),
      // ゴミ箱有効化
      trashcan: true,
      // コメント機能 未対応
      comments: false,
      // 拡大機能の有効化
      zoom: {
        controls: true,
        wheel: false,
        minScale: 0.3,
        maxScale: 2,
        pinch: true,
        startScale: 0.7,
        scaleSpeed: 1.1,
      },
      // 画面の移動機能の有効化
      move: {
        scrollbars: true,
        drag: true,
        wheel: false,
      },
      // 音を有効化
      sounds: true,
    });
    window.addEventListener('resize', () => Blockly.svgResize(this.workspace));
    this.setWorkspaceText(require('./default-workspace.xml?raw'));
    this.workspace.addChangeListener(Blockly.Events.disableOrphans);
  }

  /**
   * Blocklyのワークスペースを文字列に変換します。
   * setWorkspaceTextを使うことで復元できます
   */
  getWorkspaceText(): string {
    return Xml.domToText(Xml.workspaceToDom(this.workspace));
  }

  /**
   * Blocklyのワークスペースを設定します
   */
  setWorkspaceText(xmlText: string) {
    this.workspace.clear();
    Xml.domToWorkspace(Xml.textToDom(xmlText), this.workspace);
  }

  getCode(): string {
    return Cpp.workspaceToCode(this.workspace);
  }

  setVisible(visible: boolean) {
    this.workspace.setVisible(visible);
  }

  setHighlight(id: string, on: boolean) {
    if (on) {
      const block = this.workspace.getBlockById(id);
      const root = block.getRootBlock();
      for (const b of this.workspace.highlightedBlocks_) {
        if (root == b.getRootBlock()) {
          this.workspace.highlightBlock(b.id, false);
          break;
        }
      }
    }
    this.workspace.highlightBlock(id, on);
  }

  clearHighlight() {
    this.workspace.highlightBlock();
  }
}
