declare module EightBittr {
    /**
     * A basic representation of an in-game Thing. Size, velocity, and position
     * are stored, as well as a reference to the parent IEightBittr.
     */
    export interface IThing {
        EightBitter: IEightBittr;
        top: number;
        right: number;
        bottom: number;
        left: number;
        width: number;
        height: number;
        xvel: number;
        yvel: number;
    }

    /**
     * Settings to initialize a new instance of the IEightBittr interface.
     */
    export interface IEightBittrSettings {
        /**
         * How much to expand each pixel from raw sizing measurements to in-game.
         */
        unitsize?: number;

        /**
         * A list of member attributes to copy from the source to the IEightBittr.
         */
        constants?: string[];

        /**
         * Where the constants should be copied from, if not the IEightBittr itself.
         */
        constantsSource?: any;
    }

    /**
     * A summary of times for reset Functions and the overall operation.
     */
    export interface IResetTime {
        /**
         * The name of the reset Function called.
         */
        name: string;

        /**
         * The performance.now timestamp of when the reset started.
         */
        timeStart: number;

        /**
         * The performance.now timestamp of when the reset finished.
         */
        timeEnd: number;

        /**
         * Exactly how long it took between timeStart and timeEnd.
         */
        timeTaken: number;
    }

    /**
     * A summary of times for reset Functions and the overall operation.
     */
    export interface IResetTimes {
        /**
         * What order the reset Functions were called.
         */
        order: string[];

        /**
         * The total start, end, and taken times for the reset operation.
         */
        total: IResetTime;

        /**
         * Start, end, and taken times for individual reset Functions, in order.
         */
        times: IResetTime[];
    }

    /**
     * An interface used exclusively as the parent of IGameStartr. IEightBittr
     * contains useful functions for manipulating IThings that are independent of
     * the required GameStartr modules.
     */
    export interface IEightBittr {
        /**
         * How much to expand each pixel from raw sizing measurements to in-game.
         */
        unitsize: number;

        /**
         * Timed result summaries of resetTimed, if it was called.
         */
        resetTimes: EightBittr.IResetTimes;

        /**
         * Resets the EightBittr by calling all of the named reset member Functions
         * on itself.
         * 
         * @param EightBitter
         * @param resets   The ordered Array of reset Functions to be called.
         * @param customs   Additional arguments to pass to all reset Functions.
         */
        reset(EightBitter: IEightBittr, resets: string[], customs?: any): void;

        /**
         * Resets the EightBittr in a timed manner by calling all the named reset
         * member Functions on itself and adding the time (in milliseconds) along 
         * along with the total process time to an Array, which is then returned.
         * 
         * @param EightBitter
         * @param resets   The ordered Array of reset Functions to be called.
         * @param customs   Additional arguments to pass to all reset Functions.
         */
        resetTimed(EightBitter: IEightBittr, resets: string[], customs?: any): void;

        /**
         * Creates and returns a new HTML <canvas> element, with an optional scaling
         * multiplier. Image smoothing is disabled.
         * 
         * @param width   How wide the canvas should be.
         * @param height   How tall the canvas should be.
         * @param scaling   How much to scale the style of the canvas (by default, 1
         *                  for not at all).
         * @returns A canvas of the given width, height, and scaling.
         * @remarks TypeScript does not recognize imageSmoothingEnabled unless
         *          prefixed by "ms", so context is cast to any.
         */
        createCanvas(width: number, height: number, scaling?: number): HTMLCanvasElement;

        /**
         * Shifts a Thing vertically by changing its top and bottom attributes.
         * 
         * @param thing   The Thing to shift vertically.
         * @param dy   How far to shift the Thing.
         */
        shiftVert(thing: IThing, dy: number): void;

        /**
         * Shifts a Thing horizontally by changing its top and bottom attributes.
         * 
         * @param thing   The Thing to shift horizontally.
         * @param dy   How far to shift the Thing.
         */
        shiftHoriz(thing: IThing, dx: number): void;

        /**
         * Sets the top of a Thing to a set number, changing the bottom based on its
         * height and the EightBittr's unisize.
         * 
         * @param thing   The Thing to shift vertically.
         * @param top   Where the Thing's top should be.
         */
        setTop(thing: IThing, top: number): void;

        /**
         * Sets the right of a Thing to a set number, changing the left based on its
         * width and the EightBittr's unisize.
         * 
         * @param thing   The Thing to shift horizontally.
         * @param top   Where the Thing's right should be.
         */
        setRight(thing: IThing, right: number): void;

        /**
         * Sets the bottom of a Thing to a set number, changing the top based on its
         * height and the EightBittr's unisize.
         * 
         * @param thing   The Thing to shift vertically.
         * @param top   Where the Thing's bottom should be.
         */
        setBottom(thing: IThing, bottom: number): void;

        /**
         * Sets the left of a Thing to a set number, changing the right based on its
         * width and the EightBittr's unisize.
         * 
         * @param thing   The Thing to shift horizontally.
         * @param top   Where the Thing's left should be.
         */
        setLeft(thing: IThing, left: number): void;

        /**
         * Shifts a Thing so that it is horizontally centered on the given x.
         * 
         * @param thing   The Thing to shift horizontally.
         * @param x   Where the Thing's horizontal midpoint should be.
         */
        setMidX(thing: IThing, x: number): void;

        /**
         * Shifts a Thing so that it is vertically centered on the given y.
         * 
         * @param thing   The Thing to shift vertically.
         * @param y   Where the Thing's vertical midpoint should be.
         */
        setMidY(thing: IThing, y: number): void;

        /**
         * Shifts a Thing so that it is centered on the given x and y.
         * 
         * @param thing   The Thing to shift vertically and horizontally.
         * @param x   Where the Thing's horizontal midpoint should be.
         * @param y   Where the Thing's vertical midpoint should be.
         */
        setMid(thing: IThing, x: number, y: number): void;

        /**
         * @param thing
         * @returns The horizontal midpoint of the Thing.
         */
        getMidX(thing: IThing): number;

        /**
         * @param thing
         * @returns The vertical midpoint of the Thing.
         */
        getMidY(thing: IThing): number;

        /**
         * Shifts a Thing so that its midpoint is centered on the midpoint of the
         * other Thing.
         * 
         * @param thing   The Thing to be shifted.
         * @param other   The Thing whose midpoint is referenced.
         */
        setMidObj(thing: IThing, other: IThing): void;

        /**
         * Shifts a Thing so that its horizontal midpoint is centered on the 
         * midpoint of the other Thing.
         * 
         * @param thing   The Thing to be shifted horizontally.
         * @param other   The Thing whose horizontal midpoint is referenced.
         */
        setMidXObj(thing: IThing, other: IThing): void;

        /**
         * Shifts a Thing so that its vertical midpoint is centered on the 
         * midpoint of the other Thing.
         * 
         * @param thing   The Thing to be shifted vertically.
         * @param other   The Thing whose vertical midpoint is referenced.
         */
        setMidYObj(thing: IThing, other: IThing): void;

        /**
         * @param thing
         * @param other
         * @returns Whether the first Thing's midpoint is to the left of the other's.
         */
        objectToLeft(thing: IThing, other: IThing): boolean;

        /**
         * Shifts a Thing's top up, then sets the bottom (similar to a shiftVert and
         * a setTop combined).
         * 
         * @param thing   The Thing to be shifted vertically.
         * @param dy   How far to shift the Thing vertically.
         */
        updateTop(thing: IThing, dy: number): void;

        /**
         * Shifts a Thing's right, then sets the left (similar to a shiftHoriz and a
         * setRight combined).
         * 
         * @param thing   The Thing to be shifted horizontally.
         * @param dx   How far to shift the Thing horizontally.
         */
        updateRight(thing: IThing, dx: number): void;

        /**
         * Shifts a Thing's bottom down, then sets the bottom (similar to a 
         * shiftVert and a setBottom combined).
         * 
         * @param thing   The Thing to be shifted vertically.
         * @param dy   How far to shift the Thing vertically.
         */
        updateBottom(thing: IThing, dy: number): void;

        /**
         * Shifts a Thing's left, then sets the right (similar to a shiftHoriz and a
         * setLeft combined).
         * 
         * @param thing   The Thing to be shifted horizontally.
         * @param dx   How far to shift the Thing horizontally.
         */
        updateLeft(thing: IThing, dx: number): void;

        /**
         * Shifts a Thing toward a target x, but limits the total distance allowed.
         * Distance is computed as from the Thing's horizontal midpoint.
         * 
         * @param thing   The Thing to be shifted horizontally.
         * @param x   How far to shift the Thing horizontally.
         * @param maxDistance   The maximum distance the Thing can be shifted.
         */
        slideToX(thing: IThing, x: number, maxDistance: number): void;

        /**
         * Shifts a Thing toward a target y, but limits the total distance allowed.
         * Distance is computed as from the Thing's vertical midpoint.
         * 
         * @param thing   The Thing to be shifted vertically.
         * @param x   How far to shift the Thing vertically.
         * @param maxDistance   The maximum distance the Thing can be shifted.
         */
        slideToY(thing: IThing, y: number, maxDistance: number): void;

        /**
         * Ensures the current object is an EightBittr by throwing an error if it 
         * is not. This should be used for functions in any EightBittr descendants
         * that have to call 'this' to ensure their caller is what the programmer
         * expected it to be.
         * 
         * @param current   The scope that should be an EightBittr.
         */
        ensureCorrectCaller(current: any): IEightBittr;

        /**
         * "Proliferates" all properties of a donor onto a recipient by copying each
         * of them and recursing onto child Objects. This is a deep copy.
         * 
         * @param recipient   An object to receive properties from the donor.
         * @param donor   An object do donoate properties to the recipient.
         * @param noOverride   Whether pre-existing properties of the recipient should 
         *                     be skipped (defaults to false).
         * @returns recipient
         */
        proliferate(recipient: any, donor: any, noOverride?: boolean): any;

        /**
         * Identical to proliferate, but instead of checking whether the recipient
         * hasOwnProperty on properties, it just checks if they're truthy.
         * 
         * @param recipient   An object to receive properties from the donor.
         * @param donor   An object do donoate properties to the recipient.
         * @param noOverride   Whether pre-existing properties of the recipient should 
         *                     be skipped (defaults to false).
         * @returns recipient
         */
        proliferateHard(recipient: any, donor: any, noOverride?: boolean): any;

        /**
         * Identical to proliferate, but tailored for HTML elements because many
         * element attributes don't play nicely with JavaScript Array standards. 
         * Looking at you, HTMLCollection!
         * 
         * @param recipient   An HTMLElement to receive properties from the donor.
         * @param donor   An object do donoate properties to the recipient.
         * @param noOverride   Whether pre-existing properties of the recipient should 
         *                     be skipped (defaults to false).
         * @returns recipient
         */
        proliferateElement(recipient: HTMLElement, donor: any, noOverride?: boolean): HTMLElement;

        /**
         * Creates and returns an HTMLElement of the specified type. Any additional
         * settings Objects may be given to be proliferated onto the Element via
         * proliferateElement.
         * 
         * @param type   The tag of the Element to be created.
         * @param settings   Additional settings to proliferated onto the Element.
         * @returns {HTMLElement}
         */
        createElement(tag?: string, ...args: any[]): HTMLElement;

        /**
         * Follows a path inside an Object recursively, based on a given path.
         * 
         * @param object   A container to follow a path inside.
         * @param path   The ordered names of attributes to descend into.
         * @param num   The starting index in path (by default, 0).
         * @returns The discovered property within object, or undefined if the
         *          full path doesn't exist.
         */
        followPathHard(object: any, path: string[], index?: number): any;

        /**
         * Switches an object from one Array to another using splice and push.
         * 
         * @param object    The object to move between Arrays.
         * @param arrayOld   The Array to take the object out of.
         * @param arrayNew   The Array to move the object into.
         */
        arraySwitch(object: any, arrayOld: any[], arrayNew: any[]): void;

        /**
         * Sets a Thing's position within an Array to the front by splicing and then
         * unshifting it.
         * 
         * @param object   The object to move within the Array.
         * @param array   An Array currently containing the object.
         */
        arrayToBeginning(object: any, array: any[]): void;

        /**
         * Sets a Thing's position within an Array to the front by splicing and then
         * pushing it.
         * 
         * @param object   The object to move within the Array.
         * @param array   An Array currently containing the object.
         */
        arrayToEnd(object: any, array: any[]): void;

        /**
         * Sets a Thing's position within an Array to a specific index by splicing 
         * it out, then back in.
         * 
         * @param object   The object to move within the Array.
         * @param array   An Array currently containing the object.
         * @param index   Where the object should be moved to in the Array.
         */
        arrayToIndex(object: any, array: any[], index: number): void;
    }
}


module EightBittr {
    "use strict";

    /**
     * An abstract class used exclusively as the parent of GameStartr. EightBittr
     * contains useful functions for manipulating Things that are independent of
     * the required GameStartr modules.
     */
    export class EightBittr implements IEightBittr {
        /**
         * How much to expand each pixel from raw sizing measurements to in-game.
         */
        public unitsize: number;

        /**
         * Timed result summaries of resetTimed, if it was called.
         */
        public resetTimes: EightBittr.IResetTimes;

        /**
         * Any custom settings passed in during construction to be passed to
         * reset Functions.
         */
        protected customs: any;

        /**
         * A listing of the names of all member variables of this EightBittr
         * that should be pulled in from the setting's constantsSource.
         */
        protected constants: string[];

        /**
         * Initializes a new instance of the EightBittr class. Constants are copied
         * onto the EightBittr from the designated source.
         * 
         * @param settings   Any optional custom settings.
         */
        constructor(settings: IEightBittrSettings = {}) {
            var EightBitter: EightBittr = EightBittr.prototype.ensureCorrectCaller(this),
                constants: any = settings.constants,
                constantsSource: any = settings.constantsSource || EightBitter,
                i: number;

            EightBitter.unitsize = settings.unitsize || 1;
            EightBitter.constants = constants;

            if (constants) {
                for (i = 0; i < constants.length; i += 1) {
                    EightBitter[constants[i]] = constantsSource[constants[i]];
                }
            }
        }


        /* Resets
        */

        /**
         * Resets the EightBittr by calling all of the named reset member Functions
         * on itself.
         * 
         * @param EightBitter
         * @param resets   The ordered Array of reset Functions to be called.
         * @param customs   Additional arguments to pass to all reset Functions.
         */
        reset(EightBitter: EightBittr, resets: string[], customs?: any): void {
            var reset: string,
                i: number;

            EightBitter.customs = customs;

            for (i = 0; i < resets.length; i += 1) {
                reset = resets[i];

                if (!EightBitter[reset]) {
                    throw new Error(reset + " is missing on a resetting EightBittr.");
                }

                EightBitter[reset](EightBitter, customs);
            }
        }

        /**
         * Resets the EightBittr in a timed manner by calling all the named reset
         * member Functions on itself and adding the time (in milliseconds) along 
         * along with the total process time to an Array, which is then returned.
         * 
         * @param EightBitter
         * @param resets   The ordered Array of reset Functions to be called.
         * @param customs   Additional arguments to pass to all reset Functions.
         */
        resetTimed(EightBitter: EightBittr, resets: string[], customs?: any): void {
            var timeStartTotal: number = performance.now(),
                timeEndTotal: number,
                timeStart: number,
                timeEnd: number,
                i: number;

            this.resetTimes = <any>{
                order: resets,
                times: []
            };

            for (i = 0; i < resets.length; i += 1) {
                timeStart = performance.now();
                EightBitter[resets[i]](EightBitter, customs);
                timeEnd = performance.now();

                this.resetTimes.times.push({
                    "name": resets[i],
                    "timeStart": timeStart,
                    "timeEnd": timeEnd,
                    "timeTaken": timeEnd - timeStart
                });
            }

            timeEndTotal = performance.now();

            this.resetTimes.total = {
                "name": "resetTimed",
                "timeStart": timeStartTotal,
                "timeEnd": timeEndTotal,
                "timeTaken": timeEndTotal - timeStartTotal
            };
        }


        /* HTML Functions
        */

        /**
         * Creates and returns a new HTML <canvas> element, with an optional scaling
         * multiplier. Image smoothing is disabled.
         * 
         * @param width   How wide the canvas should be.
         * @param height   How tall the canvas should be.
         * @param scaling   How much to scale the style of the canvas (by default, 1
         *                  for not at all).
         * @returns A canvas of the given width, height, and scaling.
         * @remarks TypeScript does not recognize imageSmoothingEnabled unless
         *          prefixed by "ms", so context is cast to any.
         */
        createCanvas(width: number, height: number, scaling: number = 1): HTMLCanvasElement {
            var canvas: HTMLCanvasElement = document.createElement("canvas"),
                // context: CanvasRenderingContext2D = canvas.getContext("2d");
                context: any = canvas.getContext("2d");

            canvas.width = width;
            canvas.height = height;

            scaling = scaling || 1;

            // Scaling 1 by default, but may be different (e.g. unitsize)
            canvas.style.width = (width * scaling) + "px";
            canvas.style.height = (height * scaling) + "px";

            // For speed's sake, disable image smoothing in the first supported browsers
            if (typeof context.imageSmoothingEnabled !== "undefined") {
                context.imageSmoothingEnabled = false;
            } else if (typeof context.webkitImageSmoothingEnabled !== "undefined") {
                context.webkitImageSmoothingEnabled = false;
            } else if (typeof context.mozImageSmoothingEnabled !== "undefined") {
                context.mozImageSmoothingEnabled = false;
            } else if (typeof context.msImageSmoothingEnabled !== "undefined") {
                context.msImageSmoothingEnabled = false;
            } else if (typeof context.oImageSmoothingEnabled !== "undefined") {
                context.oImageSmoothingEnabled = false;
            }

            return canvas;
        }


        /* Physics functions 
        */

        /**
         * Shifts a Thing vertically by changing its top and bottom attributes.
         * 
         * @param thing   The Thing to shift vertically.
         * @param dy   How far to shift the Thing.
         */
        shiftVert(thing: IThing, dy: number): void {
            thing.top += dy;
            thing.bottom += dy;
        }

        /**
         * Shifts a Thing horizontally by changing its top and bottom attributes.
         * 
         * @param thing   The Thing to shift horizontally.
         * @param dy   How far to shift the Thing.
         */
        shiftHoriz(thing: IThing, dx: number): void {
            thing.left += dx;
            thing.right += dx;
        }

        /**
         * Sets the top of a Thing to a set number, changing the bottom based on its
         * height and the EightBittr's unisize.
         * 
         * @param thing   The Thing to shift vertically.
         * @param top   Where the Thing's top should be.
         */
        setTop(thing: IThing, top: number): void {
            thing.top = top;
            thing.bottom = thing.top + thing.height * thing.EightBitter.unitsize;
        }

        /**
         * Sets the right of a Thing to a set number, changing the left based on its
         * width and the EightBittr's unisize.
         * 
         * @param thing   The Thing to shift horizontally.
         * @param top   Where the Thing's right should be.
         */
        setRight(thing: IThing, right: number): void {
            thing.right = right;
            thing.left = thing.right - thing.width * thing.EightBitter.unitsize;
        }

        /**
         * Sets the bottom of a Thing to a set number, changing the top based on its
         * height and the EightBittr's unisize.
         * 
         * @param thing   The Thing to shift vertically.
         * @param top   Where the Thing's bottom should be.
         */
        setBottom(thing: IThing, bottom: number): void {
            thing.bottom = bottom;
            thing.top = thing.bottom - thing.height * thing.EightBitter.unitsize;
        }

        /**
         * Sets the left of a Thing to a set number, changing the right based on its
         * width and the EightBittr's unisize.
         * 
         * @param thing   The Thing to shift horizontally.
         * @param top   Where the Thing's left should be.
         */
        setLeft(thing: IThing, left: number): void {
            thing.left = left;
            thing.right = thing.left + thing.width * thing.EightBitter.unitsize;
        }

        /**
         * Shifts a Thing so that it is horizontally centered on the given x.
         * 
         * @param thing   The Thing to shift horizontally.
         * @param x   Where the Thing's horizontal midpoint should be.
         */
        setMidX(thing: IThing, x: number): void {
            thing.EightBitter.setLeft(
                thing,
                x - thing.width * thing.EightBitter.unitsize / 2);
        }

        /**
         * Shifts a Thing so that it is vertically centered on the given y.
         * 
         * @param thing   The Thing to shift vertically.
         * @param y   Where the Thing's vertical midpoint should be.
         */
        setMidY(thing: IThing, y: number): void {
            thing.EightBitter.setTop(
                thing,
                y - thing.height * thing.EightBitter.unitsize / 2);
        }

        /**
         * Shifts a Thing so that it is centered on the given x and y.
         * 
         * @param thing   The Thing to shift vertically and horizontally.
         * @param x   Where the Thing's horizontal midpoint should be.
         * @param y   Where the Thing's vertical midpoint should be.
         */
        setMid(thing: IThing, x: number, y: number): void {
            thing.EightBitter.setMidX(thing, x);
            thing.EightBitter.setMidY(thing, y);
        }

        /**
         * @param thing
         * @returns The horizontal midpoint of the Thing.
         */
        getMidX(thing: IThing): number {
            return thing.left + thing.width * thing.EightBitter.unitsize / 2;
        }

        /**
         * @param thing
         * @returns The vertical midpoint of the Thing.
         */
        getMidY(thing: IThing): number {
            return thing.top + thing.height * thing.EightBitter.unitsize / 2;
        }

        /**
         * Shifts a Thing so that its midpoint is centered on the midpoint of the
         * other Thing.
         * 
         * @param thing   The Thing to be shifted.
         * @param other   The Thing whose midpoint is referenced.
         */
        setMidObj(thing: IThing, other: IThing): void {
            thing.EightBitter.setMidXObj(thing, other);
            thing.EightBitter.setMidYObj(thing, other);
        }

        /**
         * Shifts a Thing so that its horizontal midpoint is centered on the 
         * midpoint of the other Thing.
         * 
         * @param thing   The Thing to be shifted horizontally.
         * @param other   The Thing whose horizontal midpoint is referenced.
         */
        setMidXObj(thing: IThing, other: IThing): void {
            thing.EightBitter.setLeft(
                thing,
                thing.EightBitter.getMidX(other)
                - (thing.width * thing.EightBitter.unitsize / 2)
            );
        }

        /**
         * Shifts a Thing so that its vertical midpoint is centered on the 
         * midpoint of the other Thing.
         * 
         * @param thing   The Thing to be shifted vertically.
         * @param other   The Thing whose vertical midpoint is referenced.
         */
        setMidYObj(thing: IThing, other: IThing): void {
            thing.EightBitter.setTop(
                thing,
                thing.EightBitter.getMidY(other)
                - (thing.height * thing.EightBitter.unitsize / 2)
            );
        }

        /**
         * @param thing
         * @param other
         * @returns Whether the first Thing's midpoint is to the left of the other's.
         */
        objectToLeft(thing: IThing, other: IThing): boolean {
            return (
                thing.EightBitter.getMidX(thing) < thing.EightBitter.getMidX(other)
            );
        }

        /**
         * Shifts a Thing's top up, then sets the bottom (similar to a shiftVert and
         * a setTop combined).
         * 
         * @param thing   The Thing to be shifted vertically.
         * @param dy   How far to shift the Thing vertically.
         */
        updateTop(thing: IThing, dy: number): void {
            // If a dy is provided, move the thing's top that much
            thing.top += dy || 0;

            // Make the thing's bottom dependent on the top
            thing.bottom = thing.top + thing.height * thing.EightBitter.unitsize;
        }

        /**
         * Shifts a Thing's right, then sets the left (similar to a shiftHoriz and a
         * setRight combined).
         * 
         * @param thing   The Thing to be shifted horizontally.
         * @param dx   How far to shift the Thing horizontally.
         */
        updateRight(thing: IThing, dx: number): void {
            // If a dx is provided, move the thing's right that much
            thing.right += dx || 0;

            // Make the thing's left dependent on the right
            thing.left = thing.right - thing.width * thing.EightBitter.unitsize;
        }

        /**
         * Shifts a Thing's bottom down, then sets the bottom (similar to a 
         * shiftVert and a setBottom combined).
         * 
         * @param thing   The Thing to be shifted vertically.
         * @param dy   How far to shift the Thing vertically.
         */
        updateBottom(thing: IThing, dy: number): void {
            // If a dy is provided, move the thing's bottom that much
            thing.bottom += dy || 0;

            // Make the thing's top dependent on the top
            thing.top = thing.bottom - thing.height * thing.EightBitter.unitsize;
        }

        /**
         * Shifts a Thing's left, then sets the right (similar to a shiftHoriz and a
         * setLeft combined).
         * 
         * @param thing   The Thing to be shifted horizontally.
         * @param dx   How far to shift the Thing horizontally.
         */
        updateLeft(thing: IThing, dx: number): void {
            // If a dx is provided, move the thing's left that much
            thing.left += dx || 0;

            // Make the thing's right dependent on the left
            thing.right = thing.left + thing.width * thing.EightBitter.unitsize;
        }

        /**
         * Shifts a Thing toward a target x, but limits the total distance allowed.
         * Distance is computed as from the Thing's horizontal midpoint.
         * 
         * @param thing   The Thing to be shifted horizontally.
         * @param x   How far to shift the Thing horizontally.
         * @param maxDistance   The maximum distance the Thing can be shifted.
         */
        slideToX(thing: IThing, x: number, maxDistance: number): void {
            var midx: number = thing.EightBitter.getMidX(thing);

            // If no maxSpeed is provided, assume Infinity (so it doesn't matter)
            maxDistance = maxDistance || Infinity;

            // Thing to the left? Slide to the right.
            if (midx < x) {
                thing.EightBitter.shiftHoriz(thing, Math.min(maxDistance, x - midx));
            } else {
                // Thing to the right? Slide to the left.
                thing.EightBitter.shiftHoriz(thing, Math.max(-maxDistance, x - midx));
            }
        }

        /**
         * Shifts a Thing toward a target y, but limits the total distance allowed.
         * Distance is computed as from the Thing's vertical midpoint.
         * 
         * @param thing   The Thing to be shifted vertically.
         * @param x   How far to shift the Thing vertically.
         * @param maxDistance   The maximum distance the Thing can be shifted.
         */
        slideToY(thing: IThing, y: number, maxDistance: number): void {
            var midy: number = thing.EightBitter.getMidY(thing);

            // If no maxSpeed is provided, assume Infinity (so it doesn't matter)
            maxDistance = maxDistance || Infinity;

            // Thing above? slide down.
            if (midy < y) {
                thing.EightBitter.shiftVert(thing, Math.min(maxDistance, y - midy));
            } else {
                // Thing below? Slide up.
                thing.EightBitter.shiftVert(thing, Math.max(-maxDistance, y - midy));
            }
        }


        /* EightBittr utilities
        */

        /**
         * Ensures the current object is an EightBittr by throwing an error if it 
         * is not. This should be used for functions in any EightBittr descendants
         * that have to call 'this' to ensure their caller is what the programmer
         * expected it to be.
         * 
         * @param current   The scope that should be an EightBittr.
         */
        ensureCorrectCaller(current: any): EightBittr {
            if (!(current instanceof EightBittr)) {
                throw new Error("A function requires the caller ('this') to be the "
                    + "manipulated EightBittr object. Unfortunately, 'this' is a "
                    + typeof (this) + ".");
            }
            return current;
        }


        /* General utilities
        */

        /**
         * "Proliferates" all properties of a donor onto a recipient by copying each
         * of them and recursing onto child Objects. This is a deep copy.
         * 
         * @param recipient   An object to receive properties from the donor.
         * @param donor   An object do donoate properties to the recipient.
         * @param noOverride   Whether pre-existing properties of the recipient should 
         *                     be skipped (defaults to false).
         * @returns recipient
         */
        proliferate(recipient: any, donor: any, noOverride: boolean = false): any {
            var setting: any,
                i: string;

            // For each attribute of the donor:
            for (i in donor) {
                if (donor.hasOwnProperty(i)) {
                    // If noOverride, don't override already existing properties
                    if (noOverride && recipient.hasOwnProperty(i)) {
                        continue;
                    }

                    // If it's an object, recurse on a new version of it
                    setting = donor[i];
                    if (typeof setting === "object") {
                        if (!recipient.hasOwnProperty(i)) {
                            recipient[i] = new setting.constructor();
                        }
                        this.proliferate(recipient[i], setting, noOverride);
                    } else {
                        // Regular primitives are easy to copy otherwise
                        recipient[i] = setting;
                    }
                }
            }

            return recipient;
        }

        /**
         * Identical to proliferate, but instead of checking whether the recipient
         * hasOwnProperty on properties, it just checks if they're truthy.
         * 
         * @param recipient   An object to receive properties from the donor.
         * @param donor   An object do donoate properties to the recipient.
         * @param noOverride   Whether pre-existing properties of the recipient should 
         *                     be skipped (defaults to false).
         * @returns recipient
         */
        proliferateHard(recipient: any, donor: any, noOverride?: boolean): any {
            var setting: any,
                i: string;

            // For each attribute of the donor:
            for (i in donor) {
                if (donor.hasOwnProperty(i)) {
                    // If noOverride, don't override already existing properties
                    if (noOverride && recipient[i]) {
                        continue;
                    }

                    // If it's an object, recurse on a new version of it
                    setting = donor[i];
                    if (typeof setting === "object") {
                        if (!recipient[i]) {
                            recipient[i] = new setting.constructor();
                        }
                        this.proliferate(recipient[i], setting, noOverride);
                    } else {
                        // Regular primitives are easy to copy otherwise
                        recipient[i] = setting;
                    }
                }
            }
            return recipient;
        }

        /**
         * Identical to proliferate, but tailored for HTML elements because many
         * element attributes don't play nicely with JavaScript Array standards. 
         * Looking at you, HTMLCollection!
         * 
         * @param recipient   An HTMLElement to receive properties from the donor.
         * @param donor   An object do donoate properties to the recipient.
         * @param noOverride   Whether pre-existing properties of the recipient should 
         *                     be skipped (defaults to false).
         * @returns recipient
         */
        proliferateElement(recipient: HTMLElement, donor: any, noOverride: boolean = false): HTMLElement {
            var setting: any,
                i: string,
                j: number;

            // For each attribute of the donor:
            for (i in donor) {
                if (donor.hasOwnProperty(i)) {
                    // If noOverride, don't override already existing properties
                    if (noOverride && recipient.hasOwnProperty(i)) {
                        continue;
                    }

                    setting = donor[i];

                    // Special cases for HTML elements
                    switch (i) {
                        // Children and options: just append all of them directly
                        case "children":
                        case "children":
                            if (typeof (setting) !== "undefined") {
                                for (j = 0; j < setting.length; j += 1) {
                                    recipient.appendChild(setting[j]);
                                }
                            }
                            break;

                        // Style: proliferate (instead of making a new Object)
                        case "style":
                            this.proliferate(recipient[i], setting);
                            break;

                        // By default, use the normal proliferate logic
                        default:
                            // If it's null, don't do anything (like .textContent)
                            if (setting === null) {
                                recipient[i] = null;
                            } else if (typeof setting === "object") {
                                // If it's an object, recurse on a new version of it
                                if (!recipient.hasOwnProperty(i)) {
                                    recipient[i] = new setting.constructor();
                                }
                                this.proliferate(recipient[i], setting, noOverride);
                            } else {
                                // Regular primitives are easy to copy otherwise
                                recipient[i] = setting;
                            }
                            break;
                    }
                }
            }

            return recipient;
        }

        /**
         * Creates and returns an HTMLElement of the specified type. Any additional
         * settings Objects may be given to be proliferated onto the Element via
         * proliferateElement.
         * 
         * @param type   The tag of the Element to be created.
         * @param settings   Additional settings to proliferated onto the Element.
         * @returns {HTMLElement}
         */
        createElement(tag?: string, ...args: any[]): HTMLElement {
            var EightBitter: EightBittr = EightBittr.prototype.ensureCorrectCaller(this),
                element: HTMLElement = document.createElement(tag || "div"),
                i: number;

            // For each provided object, add those settings to the element
            for (i = 0; i < args.length; i += 1) {
                EightBitter.proliferateElement(element, args[i]);
            }

            return element;
        }

        /**
         * Follows a path inside an Object recursively, based on a given path.
         * 
         * @param object   A container to follow a path inside.
         * @param path   The ordered names of attributes to descend into.
         * @param num   The starting index in path (by default, 0).
         * @returns The discovered property within object, or undefined if the
         *          full path doesn't exist.
         */
        followPathHard(object: any, path: string[], index: number = 0): any {
            for (var i: number = index; i < path.length; i += 1) {
                if (typeof object[path[i]] === "undefined") {
                    return undefined;
                } else {
                    object = object[path[i]];
                }
            }

            return object;
        }

        /**
         * Switches an object from one Array to another using splice and push.
         * 
         * @param object    The object to move between Arrays.
         * @param arrayOld   The Array to take the object out of.
         * @param arrayNew   The Array to move the object into.
         */
        arraySwitch(object: any, arrayOld: any[], arrayNew: any[]): void {
            arrayOld.splice(arrayOld.indexOf(object), 1);
            arrayNew.push(object);
        }

        /**
         * Sets a Thing's position within an Array to the front by splicing and then
         * unshifting it.
         * 
         * @param object   The object to move within the Array.
         * @param array   An Array currently containing the object.
         */
        arrayToBeginning(object: any, array: any[]): void {
            array.splice(array.indexOf(object), 1);
            array.unshift(object);
        }

        /**
         * Sets a Thing's position within an Array to the front by splicing and then
         * pushing it.
         * 
         * @param object   The object to move within the Array.
         * @param array   An Array currently containing the object.
         */
        arrayToEnd(object: IThing, array: any[]): void {
            array.splice(array.indexOf(object), 1);
            array.push(object);
        }

        /**
         * Sets a Thing's position within an Array to a specific index by splicing 
         * it out, then back in.
         * 
         * @param object   The object to move within the Array.
         * @param array   An Array currently containing the object.
         * @param index   Where the object should be moved to in the Array.
         */
        arrayToIndex(object: IThing, array: any[], index: number): void {
            array.splice(array.indexOf(object), 1);
            array.splice(index, 0, object);
        }
    };
}
