/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Class = require('../../utils/Class');
var Frame = require('../../textures/Frame');

/**
 * @classdesc
 * A Bob Game Object.
 *
 * A Bob belongs to a Blitter Game Object. The Blitter is responsible for managing and rendering this object.
 *
 * A Bob has a position, alpha value and a frame from a texture that it uses to render with. You can also toggle
 * the flipped and visible state of the Bob. The Frame the Bob uses to render can be changed dynamically, but it
 * must be a Frame within the Texture used by the parent Blitter.
 *
 * Bob positions are relative to the Blitter parent. So if you move the Blitter parent, all Bob children will
 * have their positions impacted by this change as well.
 *
 * You can manipulate Bob objects directly from your game code, but the creation and destruction of them should be
 * handled via the Blitter parent.
 *
 * @class Bob
 * @memberof Phaser.GameObjects
 * @constructor
 * @since 3.0.0
 *
 * @param {Phaser.GameObjects.Blitter} blitter - The parent Blitter object is responsible for updating this Bob.
 * @param {number} x - The horizontal position of this Game Object in the world, relative to the parent Blitter position.
 * @param {number} y - The vertical position of this Game Object in the world, relative to the parent Blitter position.
 * @param {(string|integer)} frame - The Frame this Bob will render with, as defined in the Texture the parent Blitter is using.
 * @param {boolean} visible - Should the Bob render visible or not to start with?
 */
var Bob = new Class({

    initialize:

    function Bob (blitter, x, y, frame, visible)
    {
        /**
         * The Blitter object that this Bob belongs to.
         *
         * @name Phaser.GameObjects.Bob#parent
         * @type {Phaser.GameObjects.Blitter}
         * @since 3.0.0
         */
        this.parent = blitter;

        /**
         * The x position of this Bob, relative to the x position of the Blitter.
         *
         * @name Phaser.GameObjects.Bob#x
         * @type {number}
         * @since 3.0.0
         */
        this.x = x;

        /**
         * The y position of this Bob, relative to the y position of the Blitter.
         *
         * @name Phaser.GameObjects.Bob#y
         * @type {number}
         * @since 3.0.0
         */
        this.y = y;

        /**
         * The frame that the Bob uses to render with.
         * To change the frame use the `Bob.setFrame` method.
         *
         * @name Phaser.GameObjects.Bob#frame
         * @type {Phaser.Textures.Frame}
         * @protected
         * @since 3.0.0
         */
        this.frame = frame;

        /**
         * A blank object which can be used to store data related to this Bob in.
         *
         * @name Phaser.GameObjects.Bob#data
         * @type {object}
         * @default {}
         * @since 3.0.0
         */
        this.data = {};

        /**
         * The tint value of this Bob.
         *
         * @name Phaser.GameObjects.Bob#tint
         * @type {number}
         * @default 0xffffff
         * @since 3.20.0
         */
        this.tint = 0xffffff;

        /**
         * The visible state of this Bob.
         *
         * @name Phaser.GameObjects.Bob#_visible
         * @type {boolean}
         * @private
         * @since 3.0.0
         */
        this._visible = visible;

        /**
         * The alpha value of this Bob.
         *
         * @name Phaser.GameObjects.Bob#_alpha
         * @type {number}
         * @private
         * @default 1
         * @since 3.0.0
         */
        this._alpha = 1;

        /**
         * The horizontally flipped state of the Bob.
         * A Bob that is flipped horizontally will render inversed on the horizontal axis.
         * Flipping always takes place from the middle of the texture.
         *
         * @name Phaser.GameObjects.Bob#flipX
         * @type {boolean}
         * @since 3.0.0
         */
        this.flipX = false;

        /**
         * The vertically flipped state of the Bob.
         * A Bob that is flipped vertically will render inversed on the vertical axis (i.e. upside down)
         * Flipping always takes place from the middle of the texture.
         *
         * @name Phaser.GameObjects.Bob#flipY
         * @type {boolean}
         * @since 3.0.0
         */
        this.flipY = false;
    },

    /**
     * Changes the Texture Frame being used by this Bob.
     * The frame must be part of the Texture the parent Blitter is using.
     * If no value is given it will use the default frame of the Blitter parent.
     *
     * @method Phaser.GameObjects.Bob#setFrame
     * @since 3.0.0
     *
     * @param {(string|integer|Phaser.Textures.Frame)} [frame] - The frame to be used during rendering.
     *
     * @return {Phaser.GameObjects.Bob} This Bob Game Object.
     */
    setFrame: function (frame)
    {
        if (frame === undefined)
        {
            this.frame = this.parent.frame;
        }
        else if (frame instanceof Frame && frame.texture === this.parent.texture)
        {
            this.frame = frame;
        }
        else
        {
            this.frame = this.parent.texture.get(frame);
        }

        return this;
    },

    /**
     * Resets the horizontal and vertical flipped state of this Bob back to their default un-flipped state.
     *
     * @method Phaser.GameObjects.Bob#resetFlip
     * @since 3.0.0
     *
     * @return {Phaser.GameObjects.Bob} This Bob Game Object.
     */
    resetFlip: function ()
    {
        this.flipX = false;
        this.flipY = false;

        return this;
    },

    /**
     * Resets this Bob.
     *
     * Changes the position to the values given, and optionally changes the frame.
     *
     * Also resets the flipX and flipY values, sets alpha back to 1 and visible to true.
     *
     * @method Phaser.GameObjects.Bob#reset
     * @since 3.0.0
     *
     * @param {number} x - The x position of the Bob. Bob coordinate are relative to the position of the Blitter object.
     * @param {number} y - The y position of the Bob. Bob coordinate are relative to the position of the Blitter object.
     * @param {(string|integer|Phaser.Textures.Frame)} [frame] - The Frame the Bob will use. It _must_ be part of the Texture the parent Blitter object is using.
     *
     * @return {Phaser.GameObjects.Bob} This Bob Game Object.
     */
    reset: function (x, y, frame)
    {
        this.x = x;
        this.y = y;

        this.flipX = false;
        this.flipY = false;

        this._alpha = 1;
        this._visible = true;

        this.parent.dirty = true;

        if (frame)
        {
            this.setFrame(frame);
        }

        return this;
    },

    /**
     * Changes the position of this Bob to the values given.
     *
     * @method Phaser.GameObjects.Bob#setPosition
     * @since 3.20.0
     *
     * @param {number} x - The x position of the Bob. Bob coordinate are relative to the position of the Blitter object.
     * @param {number} y - The y position of the Bob. Bob coordinate are relative to the position of the Blitter object.
     *
     * @return {Phaser.GameObjects.Bob} This Bob Game Object.
     */
    setPosition: function (x, y)
    {
        this.x = x;
        this.y = y;

        return this;
    },

    /**
     * Sets the horizontal flipped state of this Bob.
     *
     * @method Phaser.GameObjects.Bob#setFlipX
     * @since 3.0.0
     *
     * @param {boolean} value - The flipped state. `false` for no flip, or `true` to be flipped.
     *
     * @return {Phaser.GameObjects.Bob} This Bob Game Object.
     */
    setFlipX: function (value)
    {
        this.flipX = value;

        return this;
    },

    /**
     * Sets the vertical flipped state of this Bob.
     *
     * @method Phaser.GameObjects.Bob#setFlipY
     * @since 3.0.0
     *
     * @param {boolean} value - The flipped state. `false` for no flip, or `true` to be flipped.
     *
     * @return {Phaser.GameObjects.Bob} This Bob Game Object.
     */
    setFlipY: function (value)
    {
        this.flipY = value;

        return this;
    },

    /**
     * Sets the horizontal and vertical flipped state of this Bob.
     *
     * @method Phaser.GameObjects.Bob#setFlip
     * @since 3.0.0
     *
     * @param {boolean} x - The horizontal flipped state. `false` for no flip, or `true` to be flipped.
     * @param {boolean} y - The horizontal flipped state. `false` for no flip, or `true` to be flipped.
     *
     * @return {Phaser.GameObjects.Bob} This Bob Game Object.
     */
    setFlip: function (x, y)
    {
        this.flipX = x;
        this.flipY = y;

        return this;
    },

    /**
     * Sets the visibility of this Bob.
     * 
     * An invisible Bob will skip rendering.
     *
     * @method Phaser.GameObjects.Bob#setVisible
     * @since 3.0.0
     *
     * @param {boolean} value - The visible state of the Game Object.
     *
     * @return {Phaser.GameObjects.Bob} This Bob Game Object.
     */
    setVisible: function (value)
    {
        this.visible = value;

        return this;
    },

    /**
     * Set the Alpha level of this Bob. The alpha controls the opacity of the Game Object as it renders.
     * Alpha values are provided as a float between 0, fully transparent, and 1, fully opaque.
     * 
     * A Bob with alpha 0 will skip rendering.
     *
     * @method Phaser.GameObjects.Bob#setAlpha
     * @since 3.0.0
     *
     * @param {number} value - The alpha value used for this Bob. Between 0 and 1.
     *
     * @return {Phaser.GameObjects.Bob} This Bob Game Object.
     */
    setAlpha: function (value)
    {
        this.alpha = value;

        return this;
    },

    /**
     * Sets the tint of this Bob.
     *
     * @method Phaser.GameObjects.Bob#setTint
     * @since 3.20.0
     *
     * @param {number} value - The tint value used for this Bob. Between 0 and 0xffffff.
     *
     * @return {Phaser.GameObjects.Bob} This Bob Game Object.
     */
    setTint: function (value)
    {
        this.tint = value;

        return this;
    },

    /**
     * Destroys this Bob instance.
     * Removes itself from the Blitter and clears the parent, frame and data properties.
     *
     * @method Phaser.GameObjects.Bob#destroy
     * @since 3.0.0
     */
    destroy: function ()
    {
        this.parent.dirty = true;

        this.parent.children.remove(this);

        this.parent = undefined;
        this.frame = undefined;
        this.data = undefined;
    },

    /**
     * The visible state of the Bob.
     * 
     * An invisible Bob will skip rendering.
     *
     * @name Phaser.GameObjects.Bob#visible
     * @type {boolean}
     * @since 3.0.0
     */
    visible: {

        get: function ()
        {
            return this._visible;
        },

        set: function (value)
        {
            this.parent.dirty |= (this._visible !== value);
            this._visible = value;
        }

    },

    /**
     * The alpha value of the Bob, between 0 and 1.
     * 
     * A Bob with alpha 0 will skip rendering.
     *
     * @name Phaser.GameObjects.Bob#alpha
     * @type {number}
     * @since 3.0.0
     */
    alpha: {

        get: function ()
        {
            return this._alpha;
        },

        set: function (value)
        {
            this.parent.dirty |= ((this._alpha > 0) !== (value > 0));
            this._alpha = value;
        }

    }

});

module.exports = Bob;
