/* eslint-disable */
define(function (require, exports, module) {
  var kity = require('./kity');
  var Minder = require('./minder');
  var MinderNode = require('./node');

  var Renderer = kity.createClass('Renderer', {
    constructor: function (node) {
      this.node = node;
    },

    create: function (node) {
      throw new Error('Not implement: Renderer.create()');
    },

    shouldRender: function (node) {
      return true;
    },

    watchChange: function (data) {
      var changed;

      if (this.watchingData === undefined) {
        changed = true;
      } else if (this.watchingData != data) {
        changed = true;
      } else {
        changed = false;
      }

      this.watchingData = data;
    },

    shouldDraw: function (node) {
      return true;
    },

    update: function (shape, node, box) {
      if (this.shouldDraw()) this.draw(shape, node);
      return this.place(shape, node, box);
    },

    draw: function (shape, node) {
      throw new Error('Not implement: Renderer.draw()');
    },

    place: function (shape, node, box) {
      throw new Error('Not implement: Renderer.place()');
    },

    getRenderShape: function () {
      return this._renderShape || null;
    },

    setRenderShape: function (shape) {
      this._renderShape = shape;
    },
  });

  function createMinderExtension() {
    function createRendererForNode(node, registered) {
      var renderers = [];

      ['center', 'left', 'right', 'top', 'bottom', 'outline', 'outside'].forEach(function (section) {
        var before = 'before' + section;
        var after = 'after' + section;

        if (registered[before]) {
          renderers = renderers.concat(registered[before]);
        }
        if (registered[section]) {
          renderers = renderers.concat(registered[section]);
        }
        if (registered[after]) {
          renderers = renderers.concat(registered[after]);
        }
      });

      node._renderers = renderers.map(function (Renderer) {
        return new Renderer(node);
      });
    }

    return {
      renderNodeBatch: function (nodes) {
        var rendererClasses = this._rendererClasses;
        var lastBoxes = [];
        var rendererCount = 0;
        var i, j, renderer, node;

        if (!nodes.length) return;

        for (j = 0; j < nodes.length; j++) {
          node = nodes[j];
          if (!node._renderers) {
            createRendererForNode(node, rendererClasses);
          }
          node._contentBox = new kity.Box();
          this.fire('beforerender', {
            node: node,
          });
        }

        // 所有节点渲染器数量是一致的
        rendererCount = nodes[0]._renderers.length;

        for (i = 0; i < rendererCount; i++) {
          // 获取延迟盒子数据
          for (j = 0; j < nodes.length; j++) {
            if (typeof lastBoxes[j] == 'function') {
              lastBoxes[j] = lastBoxes[j]();
            }
            if (!(lastBoxes[j] instanceof kity.Box)) {
              lastBoxes[j] = new kity.Box(lastBoxes[j]);
            }
          }

          for (j = 0; j < nodes.length; j++) {
            node = nodes[j];
            renderer = node._renderers[i];

            // 合并盒子
            if (lastBoxes[j]) {
              node._contentBox = node._contentBox.merge(lastBoxes[j]);
              renderer.contentBox = lastBoxes[j];
            }

            // 判断当前上下文是否应该渲染
            if (renderer.shouldRender(node)) {
              // 应该渲染，但是渲染图形没创建过，需要创建
              if (!renderer.getRenderShape()) {
                renderer.setRenderShape(renderer.create(node));
                if (renderer.bringToBack) {
                  node.getRenderContainer().prependShape(renderer.getRenderShape());
                } else {
                  node.getRenderContainer().appendShape(renderer.getRenderShape());
                }
              }

              // 强制让渲染图形显示
              renderer.getRenderShape().setVisible(true);

              // 更新渲染图形
              lastBoxes[j] = renderer.update(renderer.getRenderShape(), node, node._contentBox);
            }

            // 如果不应该渲染，但是渲染图形创建过了，需要隐藏起来
            else if (renderer.getRenderShape()) {
              renderer.getRenderShape().setVisible(false);
              lastBoxes[j] = null;
            }
          }
        }

        for (j = 0; j < nodes.length; j++) {
          this.fire('noderender', {
            node: nodes[j],
          });
        }
      },

      renderNode: function (node) {
        var rendererClasses = this._rendererClasses;
        var i, latestBox, renderer;

        if (!node._renderers) {
          createRendererForNode(node, rendererClasses);
        }

        this.fire('beforerender', {
          node: node,
        });

        node._contentBox = new kity.Box();

        node._renderers.forEach(function (renderer) {
          // 判断当前上下文是否应该渲染
          if (renderer.shouldRender(node)) {
            // 应该渲染，但是渲染图形没创建过，需要创建
            if (!renderer.getRenderShape()) {
              renderer.setRenderShape(renderer.create(node));
              if (renderer.bringToBack) {
                node.getRenderContainer().prependShape(renderer.getRenderShape());
              } else {
                node.getRenderContainer().appendShape(renderer.getRenderShape());
              }
            }

            // 强制让渲染图形显示
            renderer.getRenderShape().setVisible(true);

            // 更新渲染图形
            latestBox = renderer.update(renderer.getRenderShape(), node, node._contentBox);

            if (typeof latestBox == 'function') latestBox = latestBox();

            // 合并渲染区域
            if (latestBox) {
              node._contentBox = node._contentBox.merge(latestBox);
              renderer.contentBox = latestBox;
            }
          }

          // 如果不应该渲染，但是渲染图形创建过了，需要隐藏起来
          else if (renderer.getRenderShape()) {
            renderer.getRenderShape().setVisible(false);
          }
        });

        this.fire('noderender', {
          node: node,
        });
      },
    };
  }

  kity.extendClass(Minder, createMinderExtension());

  kity.extendClass(MinderNode, {
    render: function () {
      if (!this.attached) return;
      this.getMinder().renderNode(this);
      return this;
    },
    renderTree: function () {
      if (!this.attached) return;
      var list = [];
      this.traverse(function (node) {
        list.push(node);
      });
      this.getMinder().renderNodeBatch(list);
      return this;
    },
    getRenderer: function (type) {
      var rs = this._renderers;
      if (!rs) return null;
      for (var i = 0; i < rs.length; i++) {
        if (rs[i].getType() == type) return rs[i];
      }
      return null;
    },
    getContentBox: function () {
      //if (!this._contentBox) this.render();
      return this.parent && this.parent.isCollapsed() ? new kity.Box() : this._contentBox || new kity.Box();
    },
    getRenderBox: function (rendererType, refer) {
      var renderer = rendererType && this.getRenderer(rendererType);
      var contentBox = renderer ? renderer.contentBox : this.getContentBox();
      var ctm = kity.Matrix.getCTM(this.getRenderContainer(), refer || 'paper');
      return ctm.transformBox(contentBox);
    },
  });

  module.exports = Renderer;
});
