// Learn cc.Class:
//  - https://docs.cocos.com/creator/manual/en/scripting/class.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html

const TmoSprite = require("./TmoSprite");

export default cc.Class({
    extends: cc.TiledObjectGroup,

    _init(groupInfo, mapInfo, texGrids, tiledMap) {
        const TiledMap = cc.TiledMap;
        const TMXObjectType = TiledMap.TMXObjectType;
        const Orientation = TiledMap.Orientation;
        const StaggerAxis = TiledMap.StaggerAxis;
        const TileFlag = TiledMap.TileFlag;
        const FLIPPED_MASK = TileFlag.FLIPPED_MASK;
        const FLAG_HORIZONTAL = TileFlag.HORIZONTAL;
        const FLAG_VERTICAL = TileFlag.VERTICAL;

        this._groupName = groupInfo.name;
        this._positionOffset = groupInfo.offset;
        this._mapInfo = mapInfo;
        this._properties = groupInfo.getProperties();
        this._offset = cc.v2(groupInfo.offset.x, -groupInfo.offset.y);
        this._opacity = groupInfo._opacity;

        let mapSize = mapInfo._mapSize;
        let tileSize = mapInfo._tileSize;
        let width = 0, height = 0;
        if (mapInfo.orientation === Orientation.HEX) {
            if (mapInfo.getStaggerAxis() === StaggerAxis.STAGGERAXIS_X) {
                height = tileSize.height * (mapSize.height + 0.5);
                width = (tileSize.width + mapInfo.getHexSideLength()) * Math.floor(mapSize.width / 2) + tileSize.width * (mapSize.width % 2);
            } else {
                width = tileSize.width * (mapSize.width + 0.5);
                height = (tileSize.height + mapInfo.getHexSideLength()) * Math.floor(mapSize.height / 2) + tileSize.height * (mapSize.height % 2);
            }
        } else if (mapInfo.orientation === Orientation.ISO) {
            let wh = mapSize.width + mapSize.height;
            width = tileSize.width * 0.5 * wh;
            height = tileSize.height * 0.5 * wh;
        } else {
            width = mapSize.width * tileSize.width;
            height = mapSize.height * tileSize.height;
        }
        this.node.setContentSize(width, height);

        let leftTopX = width * this.node.anchorX;
        let leftTopY = height * (1 - this.node.anchorY);

        let objects = groupInfo._objects;
        let aliveNodes = {};

        // 生成映射Map   { Texture2D: textureIndex }
        let textureIndexMap = new Map();
        let objectTextures = tiledMap.getObjectTextures();
        objectTextures.forEach((texture, idx) => textureIndexMap.set(texture, idx));

        for (let i = 0, l = objects.length; i < l; i++) {
            let object = objects[i];
            let objType = object.type;
            object.offset = cc.v2(object.x, object.y);

            let points = object.points || object.polylinePoints;
            if (points) {
                for (let pi = 0; pi < points.length; pi++) {
                    points[pi].y *= -1;
                }
            }

            if (Orientation.ISO !== mapInfo.orientation) {
                object.y = height - object.y;
            } else {
                let posIdxX = object.x / tileSize.height;
                let posIdxY = object.y / tileSize.height;
                object.x = tileSize.width * 0.5 * (mapSize.height + posIdxX - posIdxY);
                object.y = tileSize.height * 0.5 * (mapSize.width + mapSize.height - posIdxX - posIdxY);
            }

            if (objType === TMXObjectType.TEXT) {
                let textName = "text" + object.id;
                aliveNodes[textName] = true;

                let textNode = this.node.getChildByName(textName);
                if (!textNode) {
                    textNode = new cc.Node();
                }

                textNode.active = object.visible;
                textNode.anchorX = 0;
                textNode.anchorY = 1;
                textNode.angle = -object.rotation;
                textNode.x = object.x - leftTopX;
                textNode.y = object.y - leftTopY;
                textNode.name = textName;
                textNode.parent = this.node;
                textNode.color = object.color;
                textNode.opacity = this._opacity;
                textNode.setSiblingIndex(i);

                let label = textNode.getComponent(cc.Label);
                if (!label) {
                    label = textNode.addComponent(cc.Label);
                }

                label.overflow = cc.Label.Overflow.SHRINK;
                label.lineHeight = object.height;
                label.string = object.text;
                label.horizontalAlign = object.halign;
                label.verticalAlign = object.valign;
                label.fontSize = object.pixelsize;

                textNode.width = object.width;
                textNode.height = object.height;
            }

            if (objType === TMXObjectType.IMAGE) {
                let gid = object.gid;
                let grid = texGrids[(gid & FLIPPED_MASK) >>> 0];
                if (!grid) continue;
                let tileset = grid.tileset;
                let imgName = "img" + object.id;
                aliveNodes[imgName] = true;
                let imgNode = this.node.getChildByName(imgName);
                let imgWidth = object.width || grid.width;
                let imgHeight = object.height || grid.height;
                let tileOffsetX = tileset.tileOffset.x;
                let tileOffsetY = tileset.tileOffset.y;

                // Delete image nodes implemented as private nodes
                // Use cc.Node to implement node-level requirements
                if (imgNode instanceof cc.PrivateNode) {
                    imgNode.removeFromParent();
                    imgNode.destroy();
                    imgNode = null;
                }

                if (!imgNode) {
                    imgNode = new cc.Node();
                }

                if (Orientation.ISO == mapInfo.orientation) {
                    imgNode.anchorX = 0.5 + tileOffsetX / imgWidth;
                    imgNode.anchorY = tileOffsetY / imgHeight;
                } else {
                    imgNode.anchorX = tileOffsetX / imgWidth;
                    imgNode.anchorY = tileOffsetY / imgHeight;
                }
                imgNode.active = object.visible;
                imgNode.angle = -object.rotation;
                imgNode.x = object.x - leftTopX;
                imgNode.y = object.y - leftTopY;
                imgNode.name = imgName;
                imgNode.parent = this.node;
                imgNode.opacity = this._opacity;
                imgNode.setSiblingIndex(i);
                imgNode._tiledMap = tiledMap;


                let sp = imgNode.getComponent(TmoSprite);
                if (!sp) {
                    sp = imgNode.addComponent(TmoSprite);
                }
                let spf = sp.spriteFrame;
                if (!spf) {
                    spf = new cc.SpriteFrame();
                }

                if ((gid & FLAG_HORIZONTAL) >>> 0) {
                    spf.setFlipX(true);
                } else {
                    spf.setFlipX(false);
                }

                if ((gid & FLAG_VERTICAL) >>> 0) {
                    spf.setFlipY(true);
                } else {
                    spf.setFlipY(false);
                }

                let sourceImage = grid.tileset.sourceImage;
                spf.setTexture(sourceImage, cc.rect(grid));
                sp.spriteFrame = spf;
                sp.setVertsDirty();

                // object group may has no width or height info
                imgNode.width = imgWidth;
                imgNode.height = imgHeight;

                // 收集图集 更新textureIndexMap
                if (!textureIndexMap.has(sourceImage)) {
                    textureIndexMap.set(sourceImage, objectTextures.length);
                    objectTextures.push(sourceImage);
                }

                // 设置textureIndex
                let textureIndex = textureIndexMap.get(sourceImage);
                sp.setTextureIdx(textureIndex + 1);
            }
        }
        this._objects = objects;


        // destroy useless node
        let children = this.node.children;
        let uselessExp = /^(?:img|text)\d+$/;
        for (let i = 0, n = children.length; i < n; i++) {
            let c = children[i];
            let cName = c._name;
            let isUseless = uselessExp.test(cName);
            if (isUseless && !aliveNodes[cName]) c.destroy();
        }

    }
});
