"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.BlockDirection = exports.BlockFacingDirection = void 0;
const BlockProperty_1 = require("./BlockProperty");
const Database_1 = require("./Database");
const BlockRenderType_1 = require("./BlockRenderType");
const ste_events_1 = require("ste-events");
const Log_1 = require("../core/Log");
const ComponentizedBase_1 = require("./ComponentizedBase");
var BlockFacingDirection;
(function (BlockFacingDirection) {
    BlockFacingDirection[BlockFacingDirection["Down"] = 0] = "Down";
    BlockFacingDirection[BlockFacingDirection["up"] = 1] = "up";
    BlockFacingDirection[BlockFacingDirection["north"] = 2] = "north";
    BlockFacingDirection[BlockFacingDirection["south"] = 3] = "south";
    BlockFacingDirection[BlockFacingDirection["west"] = 4] = "west";
    BlockFacingDirection[BlockFacingDirection["east"] = 5] = "east";
})(BlockFacingDirection = exports.BlockFacingDirection || (exports.BlockFacingDirection = {}));
var BlockDirection;
(function (BlockDirection) {
    BlockDirection[BlockDirection["South"] = 0] = "South";
    BlockDirection[BlockDirection["West"] = 1] = "West";
    BlockDirection[BlockDirection["North"] = 2] = "North";
    BlockDirection[BlockDirection["East"] = 3] = "East";
})(BlockDirection = exports.BlockDirection || (exports.BlockDirection = {}));
class Block extends ComponentizedBase_1.default {
    get onTypeChanged() {
        return this._onTypeChanged.asEvent();
    }
    get onPropertyChanged() {
        return this._onPropertyChanged.asEvent();
    }
    get data() {
        return this._data;
    }
    set data(newData) {
        this._data = newData;
    }
    get surroundings() {
        if (this._surroundings !== undefined) {
            return this._surroundings;
        }
        this._ensureSurroundingsIfCube();
        return this._surroundings;
    }
    setType(blockType) {
        this._type = blockType;
        this._bedrockType = undefined;
        this._typeId = blockType.typeId;
    }
    get opaqueSideCount() {
        this._ensureSurroundingsIfCube();
        if (this._surroundings === undefined) {
            return 0;
        }
        let count = 0;
        const blockShortTypeName = this.shortTypeName;
        let adjacent = this._surroundings.left;
        if (adjacent === undefined ||
            adjacent.isEmpty ||
            (!adjacent.isOpaque && blockShortTypeName !== adjacent.shortTypeName)) {
            count++;
        }
        adjacent = this._surroundings.right;
        if (adjacent === undefined ||
            adjacent.isEmpty ||
            (!adjacent.isOpaque && blockShortTypeName !== adjacent.shortTypeName)) {
            count++;
        }
        adjacent = this._surroundings.up;
        if (adjacent === undefined ||
            adjacent.isEmpty ||
            (!adjacent.isOpaque && blockShortTypeName !== adjacent.shortTypeName)) {
            count++;
        }
        adjacent = this._surroundings.down;
        if (adjacent === undefined ||
            adjacent.isEmpty ||
            (!adjacent.isOpaque && blockShortTypeName !== adjacent.shortTypeName)) {
            count++;
        }
        adjacent = this._surroundings.forward;
        if (adjacent === undefined ||
            adjacent.isEmpty ||
            (!adjacent.isOpaque && blockShortTypeName !== adjacent.shortTypeName)) {
            count++;
        }
        adjacent = this._surroundings.backward;
        if (adjacent === undefined ||
            adjacent.isEmpty ||
            (!adjacent.isOpaque && blockShortTypeName !== adjacent.shortTypeName)) {
            count++;
        }
        return count;
    }
    get isOpaque() {
        if (this._bedrockType === undefined) {
            this._ensureTypes();
        }
        if (this._bedrockType !== undefined) {
            const baseType = this._bedrockType.baseType;
            return baseType.isOpaque;
        }
        return false;
    }
    _ensureTypes() {
        if (this._bedrockType !== undefined) {
            return;
        }
        if (this._typeId === undefined) {
            return;
        }
        this._type = Database_1.default.ensureBlockType(this._typeId);
        if (this._type.javaData !== null &&
            this._type.javaData.name !== null &&
            this._type.javaData.name !== this._typeId) {
            this._bedrockType = Database_1.default.ensureBlockType(this._type.javaData.name);
            const typeProp = this.getProperty("type");
            if (typeProp !== undefined) {
                if (this._bedrockType.shortTypeName === "piston" && typeProp.asString("") === "sticky") {
                    this._bedrockType = Database_1.default.ensureBlockType("sticky_piston");
                }
                else if (this._bedrockType.shortTypeName === "sticky_piston" && typeProp.asString("") === "normal") {
                    this._bedrockType = Database_1.default.ensureBlockType("piston");
                }
            }
        }
        else {
            this._bedrockType = this._type;
        }
    }
    _updateDataFromProperties() {
        this._ensureTypes();
        if (this._bedrockType === undefined) {
            return;
        }
        const baseType = this._bedrockType.baseType;
        let data = 0;
        if (baseType.data.properties !== undefined) {
            for (let i = 0; i < baseType.data.properties.length; i++) {
                const propData = baseType.data.properties[i];
                if (propData.values !== undefined) {
                    const prop = this.getProperty(propData.name);
                    if (prop !== null && prop !== undefined) {
                        for (let j = 0; j < propData.values.length; j++) {
                            if (prop.value === propData.values[j].id) {
                                const dataAdd = propData.values[j].data;
                                if (dataAdd !== undefined) {
                                    data += dataAdd;
                                }
                            }
                        }
                    }
                }
            }
        }
        this._data = data;
    }
    _notifyTypeChanged() {
        this._onTypeChanged.dispatch(this, this);
    }
    _notifyPropertyChanged(blockProperty) {
        this._updateDataFromProperties();
        this._onPropertyChanged.dispatch(this, blockProperty);
        if (this.line !== undefined && this.line.cube !== undefined) {
            this.line.cube._notifyBlockPropertyChanged(this);
        }
    }
    get bedrockType() {
        this._ensureTypes();
        return this._bedrockType;
    }
    get textureName() {
        this._ensureTypes();
        if (this._bedrockType === undefined) {
            return undefined;
        }
        if (this.shortTypeName === "water") {
            return undefined;
        }
        return this._bedrockType.typeId;
    }
    copyFrom(block) {
        this.typeName = block.typeName;
    }
    static fromLegacyId(byte) {
        if (byte === 0 || byte >= 256 || byte === undefined) {
            return new Block("minecraft:air");
        }
        const blockType = Database_1.default.getBlockTypeByLegacyId(byte);
        if (blockType) {
            return new Block(blockType.typeId);
        }
        // Log.fail("Could not find block identifier: " + byte);
        return new Block("minecraft:dirt");
    }
    get effectiveWaterLevel() {
        let prop = this.getProperty("level");
        if (prop !== undefined) {
            return prop.asNumber(0) * 2;
        }
        const shortTypeName = this.shortTypeName;
        if (shortTypeName === "water") {
            return 15;
        }
        prop = this.getProperty("liquid_depth");
        if (prop !== undefined) {
            return 15 - prop.asNumber(0);
        }
        if (this.extraLiquidDepth < 0) {
            return 0;
        }
        return 15 - this.extraLiquidDepth;
    }
    get renderType() {
        this._ensureTypes();
        if (this._bedrockType === undefined) {
            return BlockRenderType_1.BlockRenderType.BlockOneTexture;
        }
        if (this.shortTypeName === "water") {
            return BlockRenderType_1.BlockRenderType.Water;
        }
        return this._bedrockType.renderType;
    }
    getProperty(name) {
        return this.properties[name];
    }
    ensureProperty(name) {
        return this.addProperty(name);
    }
    getPropertyBoolean(name, defaultValue) {
        const prop = this.properties[name];
        if (prop === undefined || prop === null) {
            return defaultValue;
        }
        return prop.asBoolean(defaultValue);
    }
    getPropertyString(name, defaultValue) {
        const prop = this.properties[name];
        if (prop === undefined || prop === null) {
            return defaultValue;
        }
        return prop.asString(defaultValue);
    }
    getPropertyNumber(name, defaultValue) {
        const prop = this.properties[name];
        if (prop === undefined || prop === null) {
            return defaultValue;
        }
        return prop.asNumber(defaultValue);
    }
    addProperty(name) {
        let property = this.properties[name];
        if (property == null) {
            property = new BlockProperty_1.default(this);
            property.id = name;
            this.properties[name] = property;
        }
        return property;
    }
    get z() {
        return this._z;
    }
    set z(value) {
        this._z = value;
    }
    get x() {
        if (this.line === undefined) {
            return undefined;
        }
        return this.line.x;
    }
    get y() {
        if (this.line === undefined) {
            return undefined;
        }
        return this.line.y;
    }
    get coordinatesString() {
        if (this.line === undefined) {
            return "";
        }
        return this.x + "." + this.y + "." + this.z;
    }
    get typeName() {
        return this._typeId;
    }
    set typeName(val) {
        if (this._typeId !== val) {
            this._typeId = val;
            this._bedrockType = undefined;
            this._type = undefined;
            if (this.line !== undefined && this.line.cube !== undefined) {
                this.line.cube._notifyBlockTypeChanged(this);
            }
        }
    }
    getBlockData() {
        let typeId = this.typeName;
        if (typeId === null || typeId === undefined) {
            typeId = "";
        }
        const props = {};
        for (const id in this.properties) {
            const blockProp = this.properties[id];
            props[id] = blockProp.value;
        }
        const blockData = {
            typeId: typeId,
            state: props,
        };
        return blockData;
    }
    toString() {
        return JSON.stringify(this.getBlockData(), null, 2);
    }
    get isEmpty() {
        return this._typeId == null || this.shortTypeName === "air";
    }
    _ensureSurroundingsIfCube() {
        if (this.line === undefined || this._z === undefined || this._surroundings !== undefined) {
            return;
        }
        const cube = this.line.cube;
        const curX = this.line.x;
        const curY = this.line.y;
        const curZ = this._z;
        let down = undefined;
        let up = undefined;
        let left = undefined;
        let right = undefined;
        let forward = undefined;
        let backward = undefined;
        const plane = cube.x(curX);
        if (curY >= 1) {
            down = plane.y(curY - 1).z(curZ);
        }
        if (curY < cube.maxY - 1) {
            up = plane.y(curY + 1).z(curZ);
        }
        if (curX >= 1) {
            left = cube
                .x(curX - 1)
                .y(curY)
                .z(curZ);
        }
        if (curX < cube.maxX - 1) {
            right = cube
                .x(curX + 1)
                .y(curY)
                .z(curZ);
        }
        const line = cube.x(curX).y(curY);
        if (curZ >= 1) {
            backward = line.z(curZ - 1);
        }
        if (curZ < cube.maxZ - 1) {
            forward = line.z(curZ + 1);
        }
        this._surroundings = {
            down: down,
            up: up,
            left: left,
            right: right,
            backward: backward,
            forward: forward,
        };
    }
    get isCovered() {
        if (this._covered !== undefined) {
            return this._covered;
        }
        this._ensureSurroundingsIfCube();
        if (this._surroundings === undefined || this._z === undefined) {
            this._covered = false;
            return false;
        }
        const surround = this._surroundings;
        if (surround.down === undefined ||
            surround.down.isEmpty ||
            !surround.down.isOpaque ||
            !surround.down.isCovered ||
            surround.up === undefined ||
            surround.up.isEmpty ||
            !surround.up.isOpaque ||
            !surround.up.isCovered ||
            surround.left === undefined ||
            surround.left.isEmpty ||
            !surround.left.isOpaque ||
            !surround.left.isCovered ||
            surround.right === undefined ||
            surround.right.isEmpty ||
            !surround.right.isOpaque ||
            !surround.right.isCovered ||
            surround.forward === undefined ||
            surround.forward.isEmpty ||
            !surround.forward.isOpaque ||
            !surround.forward.isCovered ||
            surround.backward === undefined ||
            surround.backward.isEmpty ||
            !surround.backward.isOpaque ||
            !surround.backward.isCovered) {
            this._covered = false;
            return false;
        }
        this._covered = true;
        return true;
    }
    get isTouchingOtherBlock() {
        this._ensureSurroundingsIfCube();
        if (this._surroundings === undefined) {
            return false;
        }
        const surr = this._surroundings;
        if ((surr.down !== undefined && !surr.down.isEmpty) ||
            (surr.up !== undefined && !surr.up.isEmpty) ||
            (surr.left !== undefined && !surr.left.isEmpty) ||
            (surr.right !== undefined && !surr.right.isEmpty) ||
            (surr.forward !== undefined && !surr.forward.isEmpty) ||
            (surr.backward !== undefined && !surr.backward.isEmpty)) {
            return true;
        }
        return false;
    }
    get up() {
        this._ensureSurroundingsIfCube();
        if (this._surroundings === undefined) {
            return undefined;
        }
        return this._surroundings.up;
    }
    get down() {
        this._ensureSurroundingsIfCube();
        if (this._surroundings === undefined) {
            return undefined;
        }
        return this._surroundings.down;
    }
    get left() {
        this._ensureSurroundingsIfCube();
        if (this._surroundings === undefined) {
            return undefined;
        }
        return this._surroundings.left;
    }
    get right() {
        this._ensureSurroundingsIfCube();
        if (this._surroundings === undefined) {
            return undefined;
        }
        return this._surroundings.right;
    }
    get forward() {
        this._ensureSurroundingsIfCube();
        if (this._surroundings === undefined) {
            return undefined;
        }
        return this._surroundings.forward;
    }
    get backward() {
        this._ensureSurroundingsIfCube();
        if (this._surroundings === undefined) {
            return undefined;
        }
        return this._surroundings.backward;
    }
    get shortTypeName() {
        if (this._typeId !== undefined) {
            if (this._typeId.startsWith("minecraft:")) {
                return this._typeId.substring(10, this._typeId.length);
            }
            return this._typeId;
        }
        return undefined;
    }
    constructor(typeId) {
        super();
        this._data = 0;
        this.extraLiquidDepth = -1;
        this.persistenceVersion = -1;
        this.properties = {};
        this._onTypeChanged = new ste_events_1.EventDispatcher();
        this._onPropertyChanged = new ste_events_1.EventDispatcher();
        this._typeId = typeId;
    }
    applyFrom(template) {
        Log_1.default.assert(template !== null && template !== undefined, "Undefined block template");
        this._typeId = template.typeName;
        for (const propName in template.properties) {
            const property = template.getProperty(propName);
            const prop = this.ensureProperty(propName);
            prop.nbtType = property.nbtType;
            prop.value = property.value;
        }
    }
}
exports.default = Block;
Block.MAX_WATER_LEVEL = 16;

//# sourceMappingURL=../maps/minecraft/Block.js.map
