define(function(require, exports, module) {
    var kity = require('../core/kity');
    var utils = require('../core/utils');

    var Minder = require('../core/minder');
    var MinderNode = require('../core/node');
    var Command = require('../core/command');
    var Module = require('../core/module');
    var Renderer = require('../core/render');

    Module.register('Resource', function() {

        // String Hash
        // https://github.com/drostie/sha3-js/edit/master/blake32.min.js
        var blake32=(function(){var k,g,r,l,m,o,p,q,t,w,x;x=4*(1<<30);k=[0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19];m=[0x243F6A88,0x85A308D3,0x13198A2E,0x03707344,0xA4093822,0x299F31D0,0x082EFA98,0xEC4E6C89,0x452821E6,0x38D01377,0xBE5466CF,0x34E90C6C,0xC0AC29B7,0xC97C50DD,0x3F84D5B5,0xB5470917];w=function(i){if(i<0){i+=x}return("00000000"+i.toString(16)).slice(-8)};o=[[16,50,84,118,152,186,220,254],[174,132,249,109,193,32,123,53],[139,12,37,223,234,99,23,73],[151,19,205,235,98,165,4,143],[9,117,66,250,30,203,134,211],[194,166,176,56,212,87,239,145],[92,241,222,164,112,54,41,184],[189,231,28,147,5,79,104,162],[246,158,59,128,44,125,65,90],[42,72,103,81,191,233,195,13]];p=function(a,b,n){var s=q[a]^q[b];q[a]=(s>>>n)|(s<<(32-n))};g=function(i,a,b,c,d){var u=l+o[r][i]%16,v=l+(o[r][i]>>4);a%=4;b=4+b%4;c=8+c%4;d=12+d%4;q[a]+=q[b]+(t[u]^m[v%16]);p(d,a,16);q[c]+=q[d];p(b,c,12);q[a]+=q[b]+(t[v]^m[u%16]);p(d,a,8);q[c]+=q[d];p(b,c,7)};return function(a,b){if(!(b instanceof Array&&b.length===4)){b=[0,0,0,0]}var c,d,e,L,f,h,j,i;d=k.slice(0);c=m.slice(0,8);for(r=0;r<4;r+=1){c[r]^=b[r]}e=a.length*16;f=(e%512>446||e%512===0)?0:e;if(e%512===432){a+="\u8001"}else{a+="\u8000";while(a.length%32!==27){a+="\u0000"}a+="\u0001"}t=[];for(i=0;i<a.length;i+=2){t.push(a.charCodeAt(i)*65536+a.charCodeAt(i+1))}t.push(0);t.push(e);h=t.length-16;j=0;for(l=0;l<t.length;l+=16){j+=512;L=(l===h)?f:Math.min(e,j);q=d.concat(c);q[12]^=L;q[13]^=L;for(r=0;r<10;r+=1){for(i=0;i<8;i+=1){if(i<4){g(i,i,i,i,i)}else{g(i,i,i+1,i+2,i+3)}}}for(i=0;i<8;i+=1){d[i]^=b[i%4]^q[i]^q[i+8]}}return d.map(w).join("")}}());

        /**
         * 自动使用的颜色序列
         */
        var RESOURCE_COLOR_SERIES = [51, 303, 75, 200, 157, 0, 26, 254].map(function(h) {
            return kity.Color.createHSL(h, 100, 85);
        });

        /**
         * 在 Minder 上拓展一些关于资源的支持接口
         */
        kity.extendClass(Minder, {

            /**
             * 获取字符串的哈希值
             *
             * @param {String} str
             * @return {Number} hashCode
             */
            getHashCode: function(str) {
                str = blake32(str);
                var hash = 1315423911, i, ch;
                for (i = str.length - 1; i >= 0; i--) {
                    ch = str.charCodeAt(i);
                    hash ^= ((hash << 5) + ch + (hash >> 2));
                }
                return  (hash & 0x7FFFFFFF);
            },

            /**
             * 获取脑图中某个资源对应的颜色
             *
             * 如果存在同名资源，则返回已经分配给该资源的颜色，否则分配给该资源一个颜色，并且返回
             *
             * 如果资源数超过颜色序列数量，返回哈希颜色
             *
             * @param {String} resource 资源名称
             * @return {Color}
             */
            getResourceColor: function(resource) {
                var colorMapping = this._getResourceColorIndexMapping();
                var nextIndex;

                if (!colorMapping.hasOwnProperty(resource)) {
                    // 找不到找下个可用索引
                    nextIndex = this._getNextResourceColorIndex();
                    colorMapping[resource] = nextIndex;
                }

                // 资源过多，找不到可用索引颜色，统一返回哈希函数得到的颜色
                return RESOURCE_COLOR_SERIES[colorMapping[resource]] || kity.Color.createHSL(Math.floor(this.getHashCode(resource) / 0x7FFFFFFF * 359), 100, 85);
            },

            /**
             * 获得已使用的资源的列表
             *
             * @return {Array}
             */
            getUsedResource: function() {
                var mapping = this._getResourceColorIndexMapping();
                var used = [],
                    resource;

                for (resource in mapping) {
                    if (mapping.hasOwnProperty(resource)) {
                        used.push(resource);
                    }
                }

                return used;
            },

            /**
             * 获取脑图下一个可用的资源颜色索引
             *
             * @return {int}
             */
            _getNextResourceColorIndex: function() {
                // 获取现有颜色映射
                //     resource => color_index
                var colorMapping = this._getResourceColorIndexMapping();

                var resource, used, i;

                used = [];

                // 抽取已经使用的值到 used 数组
                for (resource in colorMapping) {
                    if (colorMapping.hasOwnProperty(resource)) {
                        used.push(colorMapping[resource]);
                    }
                }

                // 枚举所有的可用值，如果还没被使用，返回
                for (i = 0; i < RESOURCE_COLOR_SERIES.length; i++) {
                    if (!~used.indexOf(i)) return i;
                }

                // 没有可用的颜色了
                return -1;
            },

            // 获取现有颜色映射
            //     resource => color_index
            _getResourceColorIndexMapping: function() {
                return this._resourceColorMapping || (this._resourceColorMapping = {});
            }

        });


        /**
         * @class 设置资源的命令
         *
         * @example
         *
         * // 设置选中节点资源为 "张三"
         * minder.execCommand('resource', ['张三']);
         *
         * // 添加资源 "李四" 到选中节点
         * var resource = minder.queryCommandValue();
         * resource.push('李四');
         * minder.execCommand('resource', resource);
         *
         * // 清除选中节点的资源
         * minder.execCommand('resource', null);
         */
        var ResourceCommand = kity.createClass('ResourceCommand', {

            base: Command,

            execute: function(minder, resource) {
                var nodes = minder.getSelectedNodes();

                if (typeof(resource) == 'string') {
                    resource = [resource];
                }

                nodes.forEach(function(node) {
                    node.setData('resource', resource).render();
                });

                minder.layout(200);
            },

            queryValue: function(minder) {
                var nodes = minder.getSelectedNodes();
                var resource = [];

                nodes.forEach(function(node) {
                    var nodeResource = node.getData('resource');

                    if (!nodeResource) return;

                    nodeResource.forEach(function(name) {
                        if (!~resource.indexOf(name)) {
                            resource.push(name);
                        }
                    });
                });

                return resource;
            },

            queryState: function(km) {
                return km.getSelectedNode() ? 0 : -1;
            }
        });

        /**
         * @class 资源的覆盖图形
         *
         * 该类为一个资源以指定的颜色渲染一个动态的覆盖图形
         */
        var ResourceOverlay = kity.createClass('ResourceOverlay', {
            base: kity.Group,

            constructor: function() {
                this.callBase();

                var text, rect;

                rect = this.rect = new kity.Rect().setRadius(4);

                text = this.text = new kity.Text()
                    .setFontSize(12)
                    .setVerticalAlign('middle');

                this.addShapes([rect, text]);
            },

            setValue: function(resourceName, color) {
                var paddingX = 8,
                    paddingY = 4,
                    borderRadius = 4;
                var text, box, rect;

                text = this.text;

                if (resourceName == this.lastResourceName) {

                    box = this.lastBox;

                } else {

                    text.setContent(resourceName);

                    box = text.getBoundaryBox();
                    this.lastResourceName = resourceName;
                    this.lastBox = box;

                }

                text.setX(paddingX).fill(color.dec('l', 70));

                rect = this.rect;
                rect.setPosition(0, box.y - paddingY);
                this.width = Math.round(box.width + paddingX * 2);
                this.height = Math.round(box.height + paddingY * 2);
                rect.setSize(this.width, this.height);
                rect.fill(color);
            }
        });

        /**
         * @class 资源渲染器
         */
        var ResourceRenderer = kity.createClass('ResourceRenderer', {
            base: Renderer,

            create: function(node) {
                this.overlays = [];
                return new kity.Group();
            },

            shouldRender: function(node) {
                return node.getData('resource') && node.getData('resource').length;
            },

            update: function(container, node, box) {
                var spaceRight = node.getStyle('space-right');

                var overlays = this.overlays;

                /*  修复 resource 数组中出现 null 的 bug
                 *  @Author zhangbobell
                 *  @date 2016-01-15
                 */
                var resource = node.getData("resource").filter(function(ele) {
                    return ele !== null;
                });
                if (resource.length === 0) {
                    return;
                }
                var minder = node.getMinder();
                var i, overlay, x;

                x = 0;
                for (i = 0; i < resource.length; i++) {

                    x += spaceRight;

                    overlay = overlays[i];
                    if (!overlay) {
                        overlay = new ResourceOverlay();
                        overlays.push(overlay);
                        container.addShape(overlay);
                    }
                    overlay.setVisible(true);
                    overlay.setValue(resource[i], minder.getResourceColor(resource[i]));
                    overlay.setTranslate(x, -1);

                    x += overlay.width;
                }

                while ((overlay = overlays[i++])) overlay.setVisible(false);

                container.setTranslate(box.right, 0);

                return new kity.Box({
                    x: box.right,
                    y: Math.round(-overlays[0].height / 2),
                    width: x,
                    height: overlays[0].height
                });
            }
        });

        return {
            commands: {
                'resource': ResourceCommand
            },

            renderers: {
                right: ResourceRenderer
            }
        };
    });
});