<commit_before>// Node.js API.
var http = require('http')

// Control-flow utilities.
var cadence = require('cadence')
var delta = require('delta')

// Route Sencha Connect middleware based on request method and URL patterns.
var dispatch = require('dispatch')

// Exceptions that you can catch by type.
var interrupt = require('interrupt').createInterrupter('reactor')

// Contextualized callbacks and event handlers.
var Operation = require('operation/variadic')

// Evented work queue.
var Turnstile = require('turnstile')
Turnstile.Queue = require('turnstile/queue')

// Catch exceptions based on a regex match of an error message or property.
var rescue = require('rescue')

// Return the first not null-like value.
var coalesce = require('extant')

// Do nothing.
var nop = require('nop')

function Constructor (object, dispatch) {
    this._object = object
    this._dispatch = dispatch
    this._use = []
    this._defaultUse = true
}

Constructor.prototype.useDefault = function () {
    this.use(require('express-auth-parser'))
    this.use(require('body-parser').urlencoded({ extended: false, limit: '64mb' }))
    this.use(require('body-parser').json({ limit: '64mb' }))
}

Constructor.prototype.use = function () {
    var vargs = Array.prototype.slice.call(arguments)
    this._defaultUse = false
    while (vargs.length) {
        var varg = vargs.shift()
        if (Array.isArray(varg)) {
            vargs.unshift(varg)
        } else {
            this._use.push(varg)
        }
    }
}

Constructor.prototype.dispatch = function () {
    var vargs = Array.prototype.slice.call(arguments)
    this._dispatch[vargs.shift()] = Operation(vargs, { object: this._object })
}

function handler (queue, before, operation) {
    return function (request, response, next) {
        var vargs = Array.prototype.slice.call(arguments, 3)
        request.entry = {
            when: {
                push: Date.now(),
                start: null,
                headers: null,
                finish: null
            },
            health: {
                push: JSON.parse(JSON.stringify(queue.turnstile.health)),
                start: null,
                finish: null
            },
            duration: {
                start: null,
                headers: null,
                finish: null,
            },
            request: {
                method: request.method,
                header: request.headers,
                url: request.url,
                vargs: vargs
            }
        }
        before(request, response, function (error) {
            queue.push({
                error: coalesce(error),
                operation: operation,
                request: request,
                response: response,
                vargs: vargs
            })
        })
    }
}

function Reactor (object, configurator) {
    var constructor = new Constructor(object, this._dispatch = {})
    configurator(constructor)
    this.turnstile = new Turnstile({
        Date: coalesce(constructor.Date, Date),
        turnstiles: coalesce(constructor.turnstiles, 24),
        timeout: coalesce(constructor.timeout)
    })
    this._queue = new Turnstile.Queue(this, '_respond', this.turnstile)
    this._logger = coalesce(constructor.logger, nop)
    this._completed = coalesce(constructor.completed, nop)
    this._object = object
    if (constructor._defaultUse) {
        constructor.useDefault()
    }
    var before = require('connect')()
    constructor._use.forEach(function (middleware) {
        before.use(middleware)
    })
    var dispatcher = {}
    for (var pattern in this._dispatch) {
        dispatcher[pattern] = handler(this._queue, before, this._dispatch[pattern])
    }
    this.middleware = require('connect')().use(dispatch(dispatcher))
}

Reactor.prototype._timeout = cadence(function () { throw 503 })

function createProperties (properties) {
    return {
        statusCode: properties.statusCode,
        headers: coalesce(properties.headers, {}),
        description: coalesce(properties.description)
    }
}

function raise (statusCode, description, headers) {
    throw interrupt('http', createProperties({
        statusCode: statusCode,
        description: description,
        headers: headers
    }))
}

Reactor.prototype._respond = cadence(function (async, envelope) {
    var work = envelope.body
    var next = work.next

    var entry = work.request.entry

    entry.when.start = Date.now()
    entry.health.start = JSON.parse(JSON.stringify(this.turnstile.health))

    work.request.entry = entry
    work.request.raise = raise

    if (envelope.timedout) {
        work.operation = Operation([ this, '_timeout' ])
    }

    var finish

    async(function () {
        async(function () {
            async([function () {
                async(function () {
                    if (work.error) {
                        throw { cause: work.error, statusCode: coalesce(work.error.statusCode) }
                    }
                    work.operation.apply(null, [ work.request ].concat(work.vargs, async()))
                }, function () {
                    var vargs = Array.prototype.slice.call(arguments)

                    var result = vargs.shift()
                    var statusCode = (typeof vargs[0] == 'number') ? vargs.shift() : 200
                    var description = coalesce(http.STATUS_CODES[statusCode])
                    if (typeof vargs[0] == 'string') {
                        description = vargs.shift()
                    }
                    if (vargs[0] == null) {
                        vargs.shift()
                    }
                    var headers = coalesce(vargs.shift(), {})

                    interrupt.assert(description != null, 'unknown.http.status', { statusCode: statusCode })

                    return [ result, statusCode, description, headers ]
                })
            }, function (caught) {
                for (;;) {
                    try {
                        return rescue(/^reactor#http$/m, function (error) {
                            var statusCode = error.statusCode
                            var description = coalesce(error.description, http.STATUS_CODES[statusCode])
                            var headers = coalesce(error.headers, {})

                            entry.error = coalesce(error.cause)

                            interrupt.assert(description != null, 'unknown.http.status', { statusCode: statusCode })

                            headers['content-type'] = 'application/json'

                            return [ description, statusCode, description, headers ]
                        })(caught)
                    } catch (error) {
                        if (
                            typeof error == 'number' &&
                            !isNaN(error) &&
                            (error | 0) === error &&
                            Math.floor(error / 100) <= 5 &&
                            Math.floor(error / 100) >= 3
                        ) {
                            error = { statusCode: error }
                        } else if (typeof error == 'string') {
                            error = { statusCode: 307, location: error }
                        }
                        if (
                            ! (error instanceof Error) &&
                            typeof error == 'object' &&
                            typeof error.statusCode == 'number' &&
                            !isNaN(error.statusCode) &&
                            (error.statusCode | 0) === error.statusCode &&
                            Math.floor(error.statusCode / 100) <= 5 &&
                            Math.floor(error.statusCode / 100) >= 3
                        ) {
                            var properties = createProperties(error)
                            if (error.location) {
                                properties.headers.location = error.location
                            }
                            error = interrupt('http', properties, { cause: coalesce(error.cause) })
                        } else {
                            entry.error = error
                            error = { statusCode: 500 }
                        }
                        caught = error
                    }
                }
            }])
        }, function (result, statusCode, description, headers) {
            var body, f
            if (typeof result == 'function') {
                f = result
            } else {
                if (typeof result == 'string') {
                    if (!('content-type' in headers)) {
                        headers['content-type'] = 'text/plain'
                        result = new Buffer(result)
                    } else if (headers['content-type'] == 'application/json') {
                        result = new Buffer(JSON.stringify(result) + '\n')
                    }
                } else if (!('content-type' in headers)) {
                    headers['content-type'] = 'application/json'
                    result = new Buffer(JSON.stringify(result) + '\n')
                }
                f = function (response) {
                    response.end(result)
                }
            }

            work.response.writeHead(statusCode, description, headers)

            entry.when.headers = Date.now()

            entry.statusCode = statusCode
            entry.description = description
            entry.headers = headers

            var finish = delta(async()).ee(work.response).on('finish')

            async([function () {
                async(function () {
                    if (f.length == 2) {
                        f.call(work.operation.object, work.response, async())
                    } else {
                        return [ f.call(work.operation.object, work.response) ]
                    }
                }, function () {
                    return []
                })
            }, function (error) {
                entry.error = error
                work.response.end()
                finish.cancel()
            }])
        })
    }, function () {
        entry.health.done = JSON.parse(JSON.stringify(this.turnstile.health))
        entry.when.finish = Date.now()
        entry.duration = {
            start: entry.when.start - entry.when.push,
            headers: entry.when.headers - entry.when.push,
            finish: entry.when.finish - entry.when.push
        }
        this._logger.call(null, 'info', 'request', entry)
        this._completed.call(null, entry)
    })
})

Reactor.resend = function (statusCode, headers, body) {
    return Reactor.send({ statusCode: statusCode, headers: headers }, body)
}

Reactor.send = function (properties, buffer) {
    var headers = JSON.parse(JSON.stringify(properties.headers))
    delete headers['content-length']
    delete headers['transfer-encoding']
    return [ buffer, properties.statusCode, properties.statusMessage, headers ]
}

Reactor.string = function (statusCode, contentType, text) {
    return [ new Buffer(text), statusCode, { 'content-type': contentType } ]
}

Reactor.stream = function (properties, stream) {
    var headers = JSON.parse(JSON.stringify(properties.headers))
    delete headers['content-length']
    headers['transfer-encoding'] = 'chunked'
    return [ function (response) {
        stream.pipe(response)
    }, properties.statusCode, properties.statusMessage, headers ]
}

module.exports = Reactor
<commit_msg>Logger passes just the entry object.<commit_after>// Node.js API.
var http = require('http')

// Control-flow utilities.
var cadence = require('cadence')
var delta = require('delta')

// Route Sencha Connect middleware based on request method and URL patterns.
var dispatch = require('dispatch')

// Exceptions that you can catch by type.
var interrupt = require('interrupt').createInterrupter('reactor')

// Contextualized callbacks and event handlers.
var Operation = require('operation/variadic')

// Evented work queue.
var Turnstile = require('turnstile')
Turnstile.Queue = require('turnstile/queue')

// Catch exceptions based on a regex match of an error message or property.
var rescue = require('rescue')

// Return the first not null-like value.
var coalesce = require('extant')

// Do nothing.
var nop = require('nop')

function Constructor (object, dispatch) {
    this._object = object
    this._dispatch = dispatch
    this._use = []
    this._defaultUse = true
}

Constructor.prototype.useDefault = function () {
    this.use(require('express-auth-parser'))
    this.use(require('body-parser').urlencoded({ extended: false, limit: '64mb' }))
    this.use(require('body-parser').json({ limit: '64mb' }))
}

Constructor.prototype.use = function () {
    var vargs = Array.prototype.slice.call(arguments)
    this._defaultUse = false
    while (vargs.length) {
        var varg = vargs.shift()
        if (Array.isArray(varg)) {
            vargs.unshift(varg)
        } else {
            this._use.push(varg)
        }
    }
}

Constructor.prototype.dispatch = function () {
    var vargs = Array.prototype.slice.call(arguments)
    this._dispatch[vargs.shift()] = Operation(vargs, { object: this._object })
}

function handler (queue, before, operation) {
    return function (request, response, next) {
        var vargs = Array.prototype.slice.call(arguments, 3)
        request.entry = {
            when: {
                push: Date.now(),
                start: null,
                headers: null,
                finish: null
            },
            health: {
                push: JSON.parse(JSON.stringify(queue.turnstile.health)),
                start: null,
                finish: null
            },
            duration: {
                start: null,
                headers: null,
                finish: null,
            },
            request: {
                method: request.method,
                header: request.headers,
                url: request.url,
                vargs: vargs
            }
        }
        before(request, response, function (error) {
            queue.push({
                error: coalesce(error),
                operation: operation,
                request: request,
                response: response,
                vargs: vargs
            })
        })
    }
}

function Reactor (object, configurator) {
    var constructor = new Constructor(object, this._dispatch = {})
    configurator(constructor)
    this.turnstile = new Turnstile({
        Date: coalesce(constructor.Date, Date),
        turnstiles: coalesce(constructor.turnstiles, 24),
        timeout: coalesce(constructor.timeout)
    })
    this._queue = new Turnstile.Queue(this, '_respond', this.turnstile)
    this._logger = coalesce(constructor.logger, nop)
    this._completed = coalesce(constructor.completed, nop)
    this._object = object
    if (constructor._defaultUse) {
        constructor.useDefault()
    }
    var before = require('connect')()
    constructor._use.forEach(function (middleware) {
        before.use(middleware)
    })
    var dispatcher = {}
    for (var pattern in this._dispatch) {
        dispatcher[pattern] = handler(this._queue, before, this._dispatch[pattern])
    }
    this.middleware = require('connect')().use(dispatch(dispatcher))
}

Reactor.prototype._timeout = cadence(function () { throw 503 })

function createProperties (properties) {
    return {
        statusCode: properties.statusCode,
        headers: coalesce(properties.headers, {}),
        description: coalesce(properties.description)
    }
}

function raise (statusCode, description, headers) {
    throw interrupt('http', createProperties({
        statusCode: statusCode,
        description: description,
        headers: headers
    }))
}

Reactor.prototype._respond = cadence(function (async, envelope) {
    var work = envelope.body
    var next = work.next

    var entry = work.request.entry

    entry.when.start = Date.now()
    entry.health.start = JSON.parse(JSON.stringify(this.turnstile.health))

    work.request.entry = entry
    work.request.raise = raise

    if (envelope.timedout) {
        work.operation = Operation([ this, '_timeout' ])
    }

    var finish

    async(function () {
        async(function () {
            async([function () {
                async(function () {
                    if (work.error) {
                        throw { cause: work.error, statusCode: coalesce(work.error.statusCode) }
                    }
                    work.operation.apply(null, [ work.request ].concat(work.vargs, async()))
                }, function () {
                    var vargs = Array.prototype.slice.call(arguments)

                    var result = vargs.shift()
                    var statusCode = (typeof vargs[0] == 'number') ? vargs.shift() : 200
                    var description = coalesce(http.STATUS_CODES[statusCode])
                    if (typeof vargs[0] == 'string') {
                        description = vargs.shift()
                    }
                    if (vargs[0] == null) {
                        vargs.shift()
                    }
                    var headers = coalesce(vargs.shift(), {})

                    interrupt.assert(description != null, 'unknown.http.status', { statusCode: statusCode })

                    return [ result, statusCode, description, headers ]
                })
            }, function (caught) {
                for (;;) {
                    try {
                        return rescue(/^reactor#http$/m, function (error) {
                            var statusCode = error.statusCode
                            var description = coalesce(error.description, http.STATUS_CODES[statusCode])
                            var headers = coalesce(error.headers, {})

                            entry.error = coalesce(error.cause)

                            interrupt.assert(description != null, 'unknown.http.status', { statusCode: statusCode })

                            headers['content-type'] = 'application/json'

                            return [ description, statusCode, description, headers ]
                        })(caught)
                    } catch (error) {
                        if (
                            typeof error == 'number' &&
                            !isNaN(error) &&
                            (error | 0) === error &&
                            Math.floor(error / 100) <= 5 &&
                            Math.floor(error / 100) >= 3
                        ) {
                            error = { statusCode: error }
                        } else if (typeof error == 'string') {
                            error = { statusCode: 307, location: error }
                        }
                        if (
                            ! (error instanceof Error) &&
                            typeof error == 'object' &&
                            typeof error.statusCode == 'number' &&
                            !isNaN(error.statusCode) &&
                            (error.statusCode | 0) === error.statusCode &&
                            Math.floor(error.statusCode / 100) <= 5 &&
                            Math.floor(error.statusCode / 100) >= 3
                        ) {
                            var properties = createProperties(error)
                            if (error.location) {
                                properties.headers.location = error.location
                            }
                            error = interrupt('http', properties, { cause: coalesce(error.cause) })
                        } else {
                            entry.error = error
                            error = { statusCode: 500 }
                        }
                        caught = error
                    }
                }
            }])
        }, function (result, statusCode, description, headers) {
            var body, f
            if (typeof result == 'function') {
                f = result
            } else {
                if (typeof result == 'string') {
                    if (!('content-type' in headers)) {
                        headers['content-type'] = 'text/plain'
                        result = new Buffer(result)
                    } else if (headers['content-type'] == 'application/json') {
                        result = new Buffer(JSON.stringify(result) + '\n')
                    }
                } else if (!('content-type' in headers)) {
                    headers['content-type'] = 'application/json'
                    result = new Buffer(JSON.stringify(result) + '\n')
                }
                f = function (response) {
                    response.end(result)
                }
            }

            work.response.writeHead(statusCode, description, headers)

            entry.when.headers = Date.now()

            entry.statusCode = statusCode
            entry.description = description
            entry.headers = headers

            var finish = delta(async()).ee(work.response).on('finish')

            async([function () {
                async(function () {
                    if (f.length == 2) {
                        f.call(work.operation.object, work.response, async())
                    } else {
                        return [ f.call(work.operation.object, work.response) ]
                    }
                }, function () {
                    return []
                })
            }, function (error) {
                entry.error = error
                work.response.end()
                finish.cancel()
            }])
        })
    }, function () {
        entry.health.done = JSON.parse(JSON.stringify(this.turnstile.health))
        entry.when.finish = Date.now()
        entry.duration = {
            start: entry.when.start - entry.when.push,
            headers: entry.when.headers - entry.when.push,
            finish: entry.when.finish - entry.when.push
        }
        this._logger.call(null, entry)
        this._completed.call(null, entry)
    })
})

Reactor.resend = function (statusCode, headers, body) {
    return Reactor.send({ statusCode: statusCode, headers: headers }, body)
}

Reactor.send = function (properties, buffer) {
    var headers = JSON.parse(JSON.stringify(properties.headers))
    delete headers['content-length']
    delete headers['transfer-encoding']
    return [ buffer, properties.statusCode, properties.statusMessage, headers ]
}

Reactor.string = function (statusCode, contentType, text) {
    return [ new Buffer(text), statusCode, { 'content-type': contentType } ]
}

Reactor.stream = function (properties, stream) {
    var headers = JSON.parse(JSON.stringify(properties.headers))
    delete headers['content-length']
    headers['transfer-encoding'] = 'chunked'
    return [ function (response) {
        stream.pipe(response)
    }, properties.statusCode, properties.statusMessage, headers ]
}

module.exports = Reactor
<|endoftext|>


<commit_before>/*global define, preprocess*/

define( [

    'virtjs',

    './gpu/StateMachine'

], function ( Virtjs, StateMachine ) {

    var colors = { 0 : 255, 1 : 192, 2 : 96, 3 : 0 };

    return Virtjs.ClassUtil.extend( {

        initialize : function ( engine ) {

            this._engine = engine;

            // The GPU states are managed by a separate class - I find it much more readable

            this._states = new StateMachine( engine );

            // Creates a temporary scanline buffer (which does not hold a significant state, and is only used internally)

            this._scanline = new Uint16Array( 160 );

            // Creates all the mappers now, avoiding garbage collection

            this._settingsMapper       = [ this._settingsAccess.bind( this ),   null ];
            this._lcdStatusMapper      = [ this._lcdStatusAccess.bind( this ),  null ];
            this._scrollXMapper        = [ this._scrollAccess.bind( this, 0 ),  null ];
            this._scrollYMapper        = [ this._scrollAccess.bind( this, 1 ),  null ];
            this._lineMapper           = [ this._lineAccess.bind( this ),       null ];
            this._lycMapper            = [ this._lycAccess.bind( this ),        null ];
            this._oamDmaMapper         = [ this._oamDmaAccess.bind( this ),     null ];
            this._bgPaletteMapper      = [ this._paletteAccess.bind( this, 0 ), null ];
            this._sprite1PaletteMapper = [ this._paletteAccess.bind( this, 1 ), null ];
            this._sprite2PaletteMapper = [ this._paletteAccess.bind( this, 2 ), null ];

            this._oamMapper  = [ this._oamAccess.bind( this ),  null ];
            this._vramMapper = [ this._vramAccess.bind( this ), null ];

        },

        setup : function ( ) {

            // GPU sprites (40)
            // These sprites are only the internal representation of the oam (4 bytes per sprite)

            this._sprites = [ ];
            for ( var t = 0; t < 40; ++ t )
                this._sprites[ t ] = { };

            for ( var t = 0; t < 160 ; ++ t )
                this._updateSprite( t );

            this._states.setup( );

        },

        step : function ( time ) {

            // We forward the cycle management to the GPU state machine

            this._states.step( time );

        },

        settingsMapping : function ( address ) {

            if ( address === 0x00 )
                return this._settingsMapper;

            if ( address === 0x01 )
                return this._lcdStatusMapper;

            if ( address === 0x02 )
                return this._scrollYMapper;

            if ( address === 0x03 )
                return this._scrollXMapper;

            if ( address === 0x04 )
                return this._lineMapper;

            if ( address === 0x05 )
                return this._lycMapper;

            if ( address === 0x06 )
                return this._oamDmaMapper;

            if ( address === 0x07 )
                return this._bgPaletteMapper;

            if ( address === 0x08 )
                return this._sprite1PaletteMapper;

            if ( address === 0x09 )
                return this._sprite2PaletteMapper;

            return [ [ 0 ], 0 ];

            return [ Virtjs.MemoryUtil.unaddressable( 16 ), address ];

        },

        oamMapping : function ( address ) {

            this._oamMapper[ 1 ] = address;

            return this._oamMapper;

        },

        vramMapping : function ( address ) {

            this._vramMapper[ 1 ] = address;

            return this._vramMapper;

        },

        _settingsAccess : function ( address, value ) {

            if ( typeof value === 'undefined' )
                return this._packSettings( );

            this._unpackSettings( value );

        },

        _scrollAccess : function ( index, address, value ) {

            if ( typeof value === 'undefined' )
                return this._engine.environment.gpuScrolls[ index ];

            this._engine.environment.gpuScrolls[ index ] = value;

        },

        _lcdStatusAccess : function ( address, value ) {

            if ( typeof value === 'undefined' )
                return this._packLcdStatus( );

            this._engine.environment.gpuInterrupts = value & 0x78;

        },

        _lineAccess : function ( address, value, user ) {

            if ( typeof value === 'undefined' )
                return this._engine.environment.gpuLine;

            throw new Error( 'Invalid write at ' + Virtjs.FormatUtil.address( user, 16 ) );

        },

        _lycAccess : function ( address, value ) {

            if ( typeof value === 'undefined' )
                return this._engine.environment.gpuLyCompare;

            this._engine.environment.gpuLyCompare = value;

        },

        _oamDmaAccess : function ( address, value, user ) {

            if ( typeof value === 'undefined' )
                throw new Error( 'Invalid read at ' + Virtjs.FormatUtil.address( user, 16 ) );

            var start = value << 8;

            for ( var offset = 0; offset < 160; ++ offset ) {
                this._engine.environment.oam[ offset ] = this._engine.mmu.readUint8( start + offset );
                this._updateSprite( offset );
            }

        },

        _paletteAccess : function ( index, address, value ) {

            if ( typeof value === 'undefined' )
                return this._packPalette( index );

            this._unpackPalette( index, value );

        },

        _oamAccess : function ( address, value, user ) {

            if ( typeof value === 'undefined' )
                return this._engine.environment.oam[ address ];

            if ( ! this._engine.environment.gpuLCDFeature || this._engine.environment.gpuMode === 0x00 || this._engine.environment.gpuMode === 0x01 ) {
                this._engine.environment.oam[ address ] = value;
                this._updateSprite( address );
            }

        },

        _vramAccess : function ( address, value ) {

            if ( typeof value === 'undefined' )
                return this._engine.environment.vram[ address ];

            if ( ! this._engine.environment.gpuLCDFeature || this._engine.environment.gpuMode !== 0x03 ) {
                this._engine.environment.vram[ address ] = value;
                this._updateTile( address );
            }

        },

        _packSettings : function ( ) {

            return (

                ( this._engine.environment.gpuBackgroundFeature ? 1 << 0 : 0 ) |
                ( this._engine.environment.gpuSpriteFeature     ? 1 << 1 : 0 ) |
                ( this._engine.environment.gpuSpriteSize        ? 1 << 2 : 0 ) |
                ( this._engine.environment.gpuBackgroundBase    ? 1 << 3 : 0 ) |
                ( this._engine.environment.gpuTilesetBase       ? 1 << 4 : 0 ) |
                ( this._engine.environment.gpuWindowFeature     ? 1 << 5 : 0 ) |
                ( this._engine.environment.gpuWindowTileMap     ? 1 << 6 : 0 ) |
                ( this._engine.environment.gpuLCDFeature        ? 1 << 7 : 0 )

            );

        },

        _unpackSettings : function ( value ) {

            this._engine.environment.gpuBackgroundFeature = ( value & ( 1 << 0 ) ) !== 0;
            this._engine.environment.gpuSpriteFeature     = ( value & ( 1 << 1 ) ) !== 0;
            this._engine.environment.gpuSpriteSize        = ( value & ( 1 << 2 ) ) !== 0;
            this._engine.environment.gpuBackgroundBase    = ( value & ( 1 << 3 ) ) !== 0;
            this._engine.environment.gpuTilesetBase       = ( value & ( 1 << 4 ) ) !== 0;
            this._engine.environment.gpuWindowFeature     = ( value & ( 1 << 5 ) ) !== 0;
            this._engine.environment.gpuWindowTileMap     = ( value & ( 1 << 6 ) ) !== 0;
            this._engine.environment.gpuLCDFeature        = ( value & ( 1 << 7 ) ) !== 0;

        },

        _packLcdStatus : function ( ) {

            return (
                ( this._engine.environment.gpuMode        << 0 ) |
                ( this._engine.environment.gpuCoincidence << 2 ) |
                ( this._engine.environment.gpuInterrupts  << 3 )
            );

        },

        _packPalette : function ( index, value ) {

            var palette = this._engine.environment.palettes[ index ];

            return (
                ( palette[ 0 ] << 0 ) |
                ( palette[ 1 ] << 2 ) |
                ( palette[ 2 ] << 4 ) |
                ( palette[ 3 ] << 6 )
            );

        },

        _unpackPalette : function ( index, value ) {

            var palette = this._engine.environment.palettes[ index ];

            palette[ 0 ] = ( value >> 0 ) & 0x3;
            palette[ 1 ] = ( value >> 2 ) & 0x3;
            palette[ 2 ] = ( value >> 4 ) & 0x3;
            palette[ 3 ] = ( value >> 6 ) & 0x3;

        },

        _updateTile : function ( address ) {

            // The row address

            var rowAddress = address & 0xFFFE;

            // Fetch the tile index inside the tile map ([0;384[)
            //  - rowAddress >> 4 : "divide by 16 then floor", since there is 16 bytes per tile

            var tileIndex = rowAddress >> 4;

            // Fetch the row index inside the tile ([0;8[)
            //  - rowAdress >> 1 : we remove the last bit, and get the row index inside the _whole map_
            //  - PREVIOUS & 0b111 (0x7) : "modulo 8" operation, since there is 8 rows per tile

            var y = ( rowAddress >> 1 ) & 0x7;

            for ( var x = 0; x < 8; ++ x ) {

                var mask = 1 << ( 7 - x );

                this._engine.environment.tilesets[ tileIndex ][ y ][ x ] =
                    ( this._engine.environment.vram[ rowAddress + 0 ] & mask ? 0x1 : 0 ) |
                    ( this._engine.environment.vram[ rowAddress + 1 ] & mask ? 0x2 : 0 )
                ;

            }

        },

        _updateSprite : function ( address ) {

            var sprite = this._sprites[ address >> 2 ];
            var value = this._engine.environment.oam[ address ];

            switch ( address & 0x3 ) {

                case 0 : sprite.y = value - 16; break ;
                case 1 : sprite.x = value - 8;  break ;
                case 2 : sprite.tile = value;   break ;

                case 3 : sprite.palette = value & 0x10 ? 1 : 0;
                /*and*/  sprite.xflip = value & 0x20 ? true : false;
                /*and*/  sprite.yflip = value & 0x40 ? true : false;
                /*and*/  sprite.priority = value & 0x80 ? 1 : 0;

            }

        },

        _hblank : function ( line ) {

            if ( this._engine.environment.gpuLCDFeature && this._engine.environment.gpuBackgroundFeature ) {
                this._backgroundScanline( this._scanline, line );
            } else for ( var x = 0, X = this._scanline.length; x < X; ++ x ) {
                this._scanline[ x ] = 0x00FF;
            }

            if ( this._engine.environment.gpuLCDFeature && this._engine.environment.gpuSpriteFeature ) {
                this._spritesScanline( this._scanline, line );
            }

            for ( var x = 0, y = line, X = this._scanline.length; x < X; ++ x ) {

                var trueColor = this._scanline[ x ] & 0xFF;

                this._engine._options.screen.setPixel( x, y, trueColor, trueColor, trueColor );

            }

        },

        _vblank : function ( ) {

            this._engine.environment.pendingInterrupts |= 0x01;

            this._engine._options.screen.flushScreen( );

            this._engine._continue = false;

        },

        _backgroundScanline : function ( scanline, line ) {

            // Fetch the background map base, which depends on a CPU flag

            var mapBase = this._engine.environment.gpuBackgroundBase ? 0x1C00 : 0x1800;

            // Fetch the offset of the first tile, which depends on a CPU flag

            var tilesOffset = this._engine.environment.gpuTilesetBase ? 0 : 256;

            // Compute the actual position of the pixel in the world (i.e. taking the scroll into count)

            var actualY = ( this._engine.environment.gpuScrolls[ 1 ] + line ) & 0xFF;

            // Fetch the top-left mapping coordinates
            // Note that these coordinates will be <= than the pixel
            //  - actualY >> 3 : "divide by 8 then floor", since there is 8 lines/columns per tile
            //  - PREVIOUS << 5 : "multiply per 32", since there is 32 mappings per line, and that a mapping is a single byte

            var mapOffsetY = ( actualY >> 3 ) << 5;

            // Fetch the pixel coordinates relative to the top-left tile
            //  - VALUE & 0b111 (0x7) : "modulo 8", since there is 8 lines/columns per tile

            var tileY = actualY & 0x7;

            // The first palette is the background palette

            var palette = this._engine.environment.palettes[ 0 ];

            for ( var x = 0; x < 160; ++ x ) {

                // Same computations than before, but for X coordinates

                var actualX = ( this._engine.environment.gpuScrolls[ 0 ] + x ) & 0xFF;
                var mapOffsetX = ( actualX >> 3 ) & 31;
                var tileX = actualX & 0x7;

                // Knowing the map offset, we can fetch the tile index

                var mapOffset = mapBase + mapOffsetY + mapOffsetX;
                var tileIndex = this._engine.environment.vram[ mapOffset ];

                // When using the second tileset, the index is actually a signed number so that whatever the tileset, the same index greater than 0x7F (such as 0xFF) will always point toward the same tile

                if ( ! this._engine.environment.gpuTilesetBase )
                    if ( tileIndex > 0x7f )
                        tileIndex -= 0x100;

                // We just have to get the palette index color, then the color from the palette

                var paletteIndex = this._engine.environment.tilesets[ tilesOffset + tileIndex ][ tileY ][ tileX ];
                var trueColor = colors[ palette[ paletteIndex ] ];

                scanline[ x ] = ( paletteIndex << 8 ) | trueColor;

            }

        },

        _spritesScanline: function ( scanline, line ) {

            var size = this._engine.environment.gpuSpriteSize ? 16 : 8;

            // Iterates on each sprite (40 of them)

            for ( var t = 0; t < 40; ++ t ) {

                var sprite = this._sprites[ t ];

                if ( sprite.y + size <= line || sprite.y > line )
                    continue ;

                var palette = this._engine.environment.palettes[ 1 + sprite.palette ];

                var tileIndex = sprite.tile;

                if ( this._engine.environment.gpuSpriteSize )
                    tileIndex = line - sprite.y >= 8 ? tileIndex | 0x01 : tileIndex & 0xFE;

                var tileY = ( line - sprite.y ) & 0xFF;

                var tileRow = sprite.yflip ?
                    this._engine.environment.tilesets[ tileIndex ][ 7 - tileY ] :
                    this._engine.environment.tilesets[ tileIndex ][ 0 + tileY ]
                ;

                for ( var tileX = 0; tileX < 8; ++ tileX ) {

                    var x = sprite.x + tileX;

                    if ( x < 0 || x >= 160 )
                        continue ;

                    var actualTileX = sprite.xflip ? 7 - tileX : tileX;
                    var paletteIndex = tileRow[ actualTileX ];
                    var trueColor = colors[ palette[ paletteIndex ] ];

                    if ( tileRow[ actualTileX ] === 0 )
                        continue ;

                    if ( scanline[ x ] & 0xFF00 && sprite.priority )
                        continue ;

                    scanline[ x ] = ( paletteIndex << 8 ) | trueColor;

                }

            }

        }

    } );

} );
<commit_msg>Fixes wrong N % 8 operation<commit_after>/*global define, preprocess*/

define( [

    'virtjs',

    './gpu/StateMachine'

], function ( Virtjs, StateMachine ) {

    var colors = { 0 : 255, 1 : 192, 2 : 96, 3 : 0 };

    return Virtjs.ClassUtil.extend( {

        initialize : function ( engine ) {

            this._engine = engine;

            // The GPU states are managed by a separate class - I find it much more readable

            this._states = new StateMachine( engine );

            // Creates a temporary scanline buffer (which does not hold a significant state, and is only used internally)

            this._scanline = new Uint16Array( 160 );

            // Creates all the mappers now, avoiding garbage collection

            this._settingsMapper       = [ this._settingsAccess.bind( this ),   null ];
            this._lcdStatusMapper      = [ this._lcdStatusAccess.bind( this ),  null ];
            this._scrollXMapper        = [ this._scrollAccess.bind( this, 0 ),  null ];
            this._scrollYMapper        = [ this._scrollAccess.bind( this, 1 ),  null ];
            this._lineMapper           = [ this._lineAccess.bind( this ),       null ];
            this._lycMapper            = [ this._lycAccess.bind( this ),        null ];
            this._oamDmaMapper         = [ this._oamDmaAccess.bind( this ),     null ];
            this._bgPaletteMapper      = [ this._paletteAccess.bind( this, 0 ), null ];
            this._sprite1PaletteMapper = [ this._paletteAccess.bind( this, 1 ), null ];
            this._sprite2PaletteMapper = [ this._paletteAccess.bind( this, 2 ), null ];

            this._oamMapper  = [ this._oamAccess.bind( this ),  null ];
            this._vramMapper = [ this._vramAccess.bind( this ), null ];

        },

        setup : function ( ) {

            // GPU sprites (40)
            // These sprites are only the internal representation of the oam (4 bytes per sprite)

            this._sprites = [ ];
            for ( var t = 0; t < 40; ++ t )
                this._sprites[ t ] = { };

            for ( var t = 0; t < 160 ; ++ t )
                this._updateSprite( t );

            this._states.setup( );

        },

        step : function ( time ) {

            // We forward the cycle management to the GPU state machine

            this._states.step( time );

        },

        settingsMapping : function ( address ) {

            if ( address === 0x00 )
                return this._settingsMapper;

            if ( address === 0x01 )
                return this._lcdStatusMapper;

            if ( address === 0x02 )
                return this._scrollYMapper;

            if ( address === 0x03 )
                return this._scrollXMapper;

            if ( address === 0x04 )
                return this._lineMapper;

            if ( address === 0x05 )
                return this._lycMapper;

            if ( address === 0x06 )
                return this._oamDmaMapper;

            if ( address === 0x07 )
                return this._bgPaletteMapper;

            if ( address === 0x08 )
                return this._sprite1PaletteMapper;

            if ( address === 0x09 )
                return this._sprite2PaletteMapper;

            return [ [ 0 ], 0 ];

            return [ Virtjs.MemoryUtil.unaddressable( 16 ), address ];

        },

        oamMapping : function ( address ) {

            this._oamMapper[ 1 ] = address;

            return this._oamMapper;

        },

        vramMapping : function ( address ) {

            this._vramMapper[ 1 ] = address;

            return this._vramMapper;

        },

        _settingsAccess : function ( address, value ) {

            if ( typeof value === 'undefined' )
                return this._packSettings( );

            this._unpackSettings( value );

        },

        _scrollAccess : function ( index, address, value ) {

            if ( typeof value === 'undefined' )
                return this._engine.environment.gpuScrolls[ index ];

            this._engine.environment.gpuScrolls[ index ] = value;

        },

        _lcdStatusAccess : function ( address, value ) {

            if ( typeof value === 'undefined' )
                return this._packLcdStatus( );

            this._engine.environment.gpuInterrupts = value & 0x78;

        },

        _lineAccess : function ( address, value, user ) {

            if ( typeof value === 'undefined' )
                return this._engine.environment.gpuLine;

            throw new Error( 'Invalid write at ' + Virtjs.FormatUtil.address( user, 16 ) );

        },

        _lycAccess : function ( address, value ) {

            if ( typeof value === 'undefined' )
                return this._engine.environment.gpuLyCompare;

            this._engine.environment.gpuLyCompare = value;

        },

        _oamDmaAccess : function ( address, value, user ) {

            if ( typeof value === 'undefined' )
                throw new Error( 'Invalid read at ' + Virtjs.FormatUtil.address( user, 16 ) );

            var start = value << 8;

            for ( var offset = 0; offset < 160; ++ offset ) {
                this._engine.environment.oam[ offset ] = this._engine.mmu.readUint8( start + offset );
                this._updateSprite( offset );
            }

        },

        _paletteAccess : function ( index, address, value ) {

            if ( typeof value === 'undefined' )
                return this._packPalette( index );

            this._unpackPalette( index, value );

        },

        _oamAccess : function ( address, value, user ) {

            if ( typeof value === 'undefined' )
                return this._engine.environment.oam[ address ];

            if ( ! this._engine.environment.gpuLCDFeature || this._engine.environment.gpuMode === 0x00 || this._engine.environment.gpuMode === 0x01 ) {
                this._engine.environment.oam[ address ] = value;
                this._updateSprite( address );
            }

        },

        _vramAccess : function ( address, value ) {

            if ( typeof value === 'undefined' )
                return this._engine.environment.vram[ address ];

            if ( ! this._engine.environment.gpuLCDFeature || this._engine.environment.gpuMode !== 0x03 ) {
                this._engine.environment.vram[ address ] = value;
                this._updateTile( address );
            }

        },

        _packSettings : function ( ) {

            return (

                ( this._engine.environment.gpuBackgroundFeature ? 1 << 0 : 0 ) |
                ( this._engine.environment.gpuSpriteFeature     ? 1 << 1 : 0 ) |
                ( this._engine.environment.gpuSpriteSize        ? 1 << 2 : 0 ) |
                ( this._engine.environment.gpuBackgroundBase    ? 1 << 3 : 0 ) |
                ( this._engine.environment.gpuTilesetBase       ? 1 << 4 : 0 ) |
                ( this._engine.environment.gpuWindowFeature     ? 1 << 5 : 0 ) |
                ( this._engine.environment.gpuWindowTileMap     ? 1 << 6 : 0 ) |
                ( this._engine.environment.gpuLCDFeature        ? 1 << 7 : 0 )

            );

        },

        _unpackSettings : function ( value ) {

            this._engine.environment.gpuBackgroundFeature = ( value & ( 1 << 0 ) ) !== 0;
            this._engine.environment.gpuSpriteFeature     = ( value & ( 1 << 1 ) ) !== 0;
            this._engine.environment.gpuSpriteSize        = ( value & ( 1 << 2 ) ) !== 0;
            this._engine.environment.gpuBackgroundBase    = ( value & ( 1 << 3 ) ) !== 0;
            this._engine.environment.gpuTilesetBase       = ( value & ( 1 << 4 ) ) !== 0;
            this._engine.environment.gpuWindowFeature     = ( value & ( 1 << 5 ) ) !== 0;
            this._engine.environment.gpuWindowTileMap     = ( value & ( 1 << 6 ) ) !== 0;
            this._engine.environment.gpuLCDFeature        = ( value & ( 1 << 7 ) ) !== 0;

        },

        _packLcdStatus : function ( ) {

            return (
                ( this._engine.environment.gpuMode        << 0 ) |
                ( this._engine.environment.gpuCoincidence << 2 ) |
                ( this._engine.environment.gpuInterrupts  << 3 )
            );

        },

        _packPalette : function ( index, value ) {

            var palette = this._engine.environment.palettes[ index ];

            return (
                ( palette[ 0 ] << 0 ) |
                ( palette[ 1 ] << 2 ) |
                ( palette[ 2 ] << 4 ) |
                ( palette[ 3 ] << 6 )
            );

        },

        _unpackPalette : function ( index, value ) {

            var palette = this._engine.environment.palettes[ index ];

            palette[ 0 ] = ( value >> 0 ) & 0x3;
            palette[ 1 ] = ( value >> 2 ) & 0x3;
            palette[ 2 ] = ( value >> 4 ) & 0x3;
            palette[ 3 ] = ( value >> 6 ) & 0x3;

        },

        _updateTile : function ( address ) {

            // The row address

            var rowAddress = address & 0xFFFE;

            // Fetch the tile index inside the tile map ([0;384[)
            //  - rowAddress >> 4 : "divide by 16 then floor", since there is 16 bytes per tile

            var tileIndex = rowAddress >> 4;

            // Fetch the row index inside the tile ([0;8[)
            //  - rowAdress >> 1 : we remove the last bit, and get the row index inside the _whole map_
            //  - PREVIOUS & 0b111 (0x7) : "modulo 8" operation, since there is 8 rows per tile

            var y = ( rowAddress >> 1 ) & 0x7;

            for ( var x = 0; x < 8; ++ x ) {

                var mask = 1 << ( 7 - x );

                this._engine.environment.tilesets[ tileIndex ][ y ][ x ] =
                    ( this._engine.environment.vram[ rowAddress + 0 ] & mask ? 0x1 : 0 ) |
                    ( this._engine.environment.vram[ rowAddress + 1 ] & mask ? 0x2 : 0 )
                ;

            }

        },

        _updateSprite : function ( address ) {

            var sprite = this._sprites[ address >> 2 ];
            var value = this._engine.environment.oam[ address ];

            switch ( address & 0x3 ) {

                case 0 : sprite.y = value - 16; break ;
                case 1 : sprite.x = value - 8;  break ;
                case 2 : sprite.tile = value;   break ;

                case 3 : sprite.palette = value & 0x10 ? 1 : 0;
                /*and*/  sprite.xflip = value & 0x20 ? true : false;
                /*and*/  sprite.yflip = value & 0x40 ? true : false;
                /*and*/  sprite.priority = value & 0x80 ? 1 : 0;

            }

        },

        _hblank : function ( line ) {

            if ( this._engine.environment.gpuLCDFeature && this._engine.environment.gpuBackgroundFeature ) {
                this._backgroundScanline( this._scanline, line );
            } else for ( var x = 0, X = this._scanline.length; x < X; ++ x ) {
                this._scanline[ x ] = 0x00FF;
            }

            if ( this._engine.environment.gpuLCDFeature && this._engine.environment.gpuSpriteFeature ) {
                this._spritesScanline( this._scanline, line );
            }

            for ( var x = 0, y = line, X = this._scanline.length; x < X; ++ x ) {

                var trueColor = this._scanline[ x ] & 0xFF;

                this._engine._options.screen.setPixel( x, y, trueColor, trueColor, trueColor );

            }

        },

        _vblank : function ( ) {

            this._engine.environment.pendingInterrupts |= 0x01;

            this._engine._options.screen.flushScreen( );

            this._engine._continue = false;

        },

        _backgroundScanline : function ( scanline, line ) {

            // Fetch the background map base, which depends on a CPU flag

            var mapBase = this._engine.environment.gpuBackgroundBase ? 0x1C00 : 0x1800;

            // Fetch the offset of the first tile, which depends on a CPU flag

            var tilesOffset = this._engine.environment.gpuTilesetBase ? 0 : 256;

            // Compute the actual position of the pixel in the world (i.e. taking the scroll into count)

            var actualY = ( this._engine.environment.gpuScrolls[ 1 ] + line ) & 0xFF;

            // Fetch the top-left mapping coordinates
            // Note that these coordinates will be <= than the pixel
            //  - actualY >> 3 : "divide by 8 then floor", since there is 8 lines/columns per tile
            //  - PREVIOUS << 5 : "multiply per 32", since there is 32 mappings per line, and that a mapping is a single byte

            var mapOffsetY = ( actualY >> 3 ) << 5;

            // Fetch the pixel coordinates relative to the top-left tile
            //  - VALUE & 0b111 (0x7) : "modulo 8", since there is 8 lines/columns per tile

            var tileY = actualY & 0x7;

            // The first palette is the background palette

            var palette = this._engine.environment.palettes[ 0 ];

            for ( var x = 0; x < 160; ++ x ) {

                // Same computations than before, but for X coordinates

                var actualX = ( this._engine.environment.gpuScrolls[ 0 ] + x ) & 0xFF;
                var mapOffsetX = ( actualX >> 3 ) & 31;
                var tileX = actualX & 0x7;

                // Knowing the map offset, we can fetch the tile index

                var mapOffset = mapBase + mapOffsetY + mapOffsetX;
                var tileIndex = this._engine.environment.vram[ mapOffset ];

                // When using the second tileset, the index is actually a signed number so that whatever the tileset, the same index greater than 0x7F (such as 0xFF) will always point toward the same tile

                if ( ! this._engine.environment.gpuTilesetBase )
                    if ( tileIndex > 0x7f )
                        tileIndex -= 0x100;

                // We just have to get the palette index color, then the color from the palette

                var paletteIndex = this._engine.environment.tilesets[ tilesOffset + tileIndex ][ tileY ][ tileX ];
                var trueColor = colors[ palette[ paletteIndex ] ];

                scanline[ x ] = ( paletteIndex << 8 ) | trueColor;

            }

        },

        _spritesScanline: function ( scanline, line ) {

            var size = this._engine.environment.gpuSpriteSize ? 16 : 8;

            // Iterates on each sprite (40 of them)

            for ( var t = 0; t < 40; ++ t ) {

                var sprite = this._sprites[ t ];

                if ( sprite.y + size <= line || sprite.y > line )
                    continue ;

                var palette = this._engine.environment.palettes[ 1 + sprite.palette ];

                var tileIndex = sprite.tile;

                if ( this._engine.environment.gpuSpriteSize )
                    tileIndex = line - sprite.y >= 8 ? tileIndex | 0x01 : tileIndex & 0xFE;

                var tileY = ( line - sprite.y ) & 0x07;

                var tileRow = sprite.yflip ?
                    this._engine.environment.tilesets[ tileIndex ][ 7 - tileY ] :
                    this._engine.environment.tilesets[ tileIndex ][ 0 + tileY ]
                ;

                for ( var tileX = 0; tileX < 8; ++ tileX ) {

                    var x = sprite.x + tileX;

                    if ( x < 0 || x >= 160 )
                        continue ;

                    var actualTileX = sprite.xflip ? 7 - tileX : tileX;
                    var paletteIndex = tileRow[ actualTileX ];
                    var trueColor = colors[ palette[ paletteIndex ] ];

                    if ( tileRow[ actualTileX ] === 0 )
                        continue ;

                    if ( scanline[ x ] & 0xFF00 && sprite.priority )
                        continue ;

                    scanline[ x ] = ( paletteIndex << 8 ) | trueColor;

                }

            }

        }

    } );

} );
<|endoftext|>


<commit_before>// Fix to make startsWith work in IE 11
if (!String.prototype.startsWith) {
    String.prototype.startsWith = function(searchString, position) {
        position = position || 0;
        return this.substr(position, searchString.length) === searchString;
    };
}

var loading = '';
var seaticon = '';
var sessionsloading = {};
var reserved_seats = [];

function loadingSession(s, isloading) {
    if (isloading) {
        $("#tooltip-"+s).html(loading);
        $(".plus[data-id="+s+"]").attr("disabled", "");
        $(".minus[data-id="+s+"]").attr("disabled", "");
    } else {
        $("#tooltip-"+s).html(seaticon);
        $(".plus[data-id="+s+"]").removeAttr("disabled");
        $(".minus[data-id="+s+"]").removeAttr("disabled");
    }
    setLoading(s, isloading);
}

function setLoading(id, isloading) {
    if (isloading) {
        sessionsloading[id] = true;
    } else {
        sessionsloading[id] = false;
    }

    for (i in sessionsloading) {
        if (sessionsloading[i]) {
            $("#finish").attr("disabled", "");
            return;
        }
    }

    $("#finish").removeAttr("disabled");
}

var old_session = -1;
var old_layout = -1;

delays = {};
selected_seats = {};

function check_warning(w, sessions) {
    if (w.type == 'req') {
        var firstFound = true;
        var secondFound = true;
        var ss = [];
        w.sessions1.forEach(function(s1) { ss.push(s1); });
        w.sessions2.forEach(function(s2) { ss.push(s2); });

        for (var i=0; i<w.sessions1.length; i++) {
            if (sessions.indexOf(w.sessions1[i]) < 0) {
                firstFound = false;
            }
        }
        for (var i=0; i<w.sessions2.length; i++) {
            if (sessions.indexOf(w.sessions2[i]) < 0) {
                secondFound = false;
            }
        }

        if (firstFound && !secondFound) {
            return true;
        }

        return false;
    }
}

function seat_droped(session, layout, seat) {
    var selector = '#' + session + '_' + layout + '_' + seat;
    $(selector).addClass("seat-L");
    $(selector).removeClass("seat-H");
    $(selector).unbind("click").click(function() {
        SeatMap.clickSeat($(this));
    });
}

function seat_holded(session, layout, seat) {
    var selector = '#' + session + '_' + layout + '_' + seat;

    if ($(selector).hasClass("seat-selected")) {
        return;
    }

    $(selector).addClass("seat-H");
    $(selector).removeClass("seat-L");
    $(selector).unbind("click");
}

function seat_reserved(session, layout, seat) {
    var selector = '#' + session + '_' + layout + '_' + seat;

    $(selector).addClass("seat-R");
    $(selector).removeClass("seat-L");
    $(selector).removeClass("seat-H");
    $(selector).unbind("click");

    // Update free seats from websockets
    if (reserved_seats.indexOf(selector) >= 0) {
        return;
    }
    reserved_seats.push(selector);
    try {
        free = $("td.layout-"+session+"-"+layout+" > div.layout-zone-free");
        free_num = free.html().trim().split(": ")[1];
        res = String(Number(free_num) - 1);
        free.html(free.html().replace(free_num, res));
    } catch(e) {
        console.error("Error updating free seats");
    }

}

function websocketCB(ev, data) {
    if (ev == 'hold') {
        var seat = data.row + '_' + data.col;
        seat_holded(data.session, data.layout, seat);
    } else if (ev == 'drop') {
        var seat = data.row + '_' + data.col;
        seat_droped(data.session, data.layout, seat);
    } else if (ev == 'confirm') {
        var seat = data.row + '_' + data.col;
        seat_reserved(data.session, data.layout, seat);
    } else if (ev == 'autoseat') {
        autoSelectSeatCB(data.session, data.seats, data.error);
    } else if (ev == 'holded') {
        var seat = data.row + '_' + data.col;
        var selector = '#' + data.session + '_' + data.layout + '_' + seat;
        $(selector).removeClass("seat-selected");
        seat_holded(data.session, data.layout, seat);
    }
}

function seatCB(ev, seat) {
    var row = seat.data("row");
    var col = seat.data("col");
    var session = seat.data("session");
    var layout = seat.data("layout");

    var current = [];
    var currentval = $("#seats-"+session).val();
    if (currentval) {
        current = currentval.split(",");
    }

    var str = layout + '_' + row + '_' + col;

    args = session;
    args += ' ' + layout;
    args += ' ' + row;
    args += ' ' + col;
    args += ' ' + client;

    if (ev == 'select') {
        current.push(str);
        ws.send('hold_seat ' + args);
    } else if (ev == 'unselect') {
        var idx = current.indexOf(str);
        if (idx >= 0) {
            current.splice(idx, 1);
        }
        ws.send('drop_seat ' + args);
    }

    $("#seats-"+session).val(current.join(","));
    $("#"+session).val(current.length);

    updateBadges(session, layout);

    $("#"+session).keydown();
}

function updateBadges(session, layout) {
    //updating the label with the number of selected seats
    var currentval = $("#seats-"+session).val();
    var current = currentval.split(",");
    var n = 0;
    current.forEach(function(element) {
        if (element.startsWith(layout + '_')) {
            n++;
        }
    });
    badge = $("#badge-"+session+"-"+layout);
    badge.text(n);
    if (n) {
        badge.addClass("label-success");
        badge.removeClass("label-default");
    } else {
        badge.removeClass("label-success");
        badge.addClass("label-default");
    }
    // Remove old badges. recursive function
    if (old_session != -1 && (old_session != session || old_layout != layout)) {
        updateBadges(old_session, old_layout);
    }
    old_session = session;
    old_layout = layout;
}

function recalcSums(obj) {
    var session = obj.attr("id");
    var val = parseInt(obj.val(), 10);

    if (isNaN(val)) {
        obj.val(0);
        val = 0;
    }

    var max = parseInt(obj.attr('max') || 500, 10);
    if (val > max) {
        val = max;
        obj.val(max);
    }

    var price = parseFloat(obj.data("price").replace(",", "."));
    $("#"+session+"-subtotal-price").html((val * price).toFixed(2));
}

function recalcTotal() {
    var sum = 0;
    $(".sessioninput").each(function() {
        var n = parseInt($(this).val(), 10);
        var price = parseFloat($(this).data("price").replace(",", "."));
        sum += price * n;
    });
    $("#total").html(sum.toFixed(2));
}

function fillSelectedSeats(obj) {
    // obj should be a .seats-input
    var session = obj.data('session');
    var v = obj.val();
    if (v) {
        var current = [];
        current = v.split(",");
        $("#"+session).val(current.length);
        $("#"+session).keydown();

        function recursiveSelection(arr, finish) {
            loadingSession(session, true);
            var c = arr.pop();
            var selector = '#' + session + '_' + c;
            var layout = c.split('_')[0];
            var l = $('.layout-'+session+'-'+layout);
            var obj = $('.display-'+session+'-'+layout);

            SeatMap.preloadLayout(l, obj, function() {
                updateBadges(session, layout);
                loadingSession(session, false);

                $(selector).removeClass("seat-H");
                $(selector).addClass("seat-selected");
                $(selector).unbind("click").click(function() {
                    SeatMap.clickSeat($(this));
                });

                if (arr.length) {
                    recursiveSelection(arr, finish);
                } else {
                    finish();
                }
            });
        }

        recursiveSelection(current.slice(0), function() {
            current.forEach(function(c) {
                var layout = c.split('_')[0];
                updateBadges(session, layout);
            });
        });
    } else {
        loadingSession(session, false);
    }
}

function autoSelectSeatCB(s, seats, error) {
    loadingSession(s, false);

    if (seats.length) {
        var value = [];
        seats.forEach(function(obj) {
            value.push(obj.layout+"_"+obj.row+"_"+obj.col);
        });
        $("#seats-"+s).val(value.join(","));
        fillSelectedSeats($("#seats-"+s));
    } else {
        if ($("#"+s).val() != 0) {
            $("#"+s).val(0);
            $("#"+s).select();
        }
        var layouts = $('#modal-'+s+' .layout');
        layouts.each(function() {
            var id = $(this).data('id');
            updateBadges(s, id);
        });
        alertify.alert(error);
        loadingSession(s, false);
    }
}

function autoSelectSeat(s, n) {
    if (n == 0) {
        return;
    }

    loadingSession(s, true);
    ws.send('autoseats ' + s + ' ' + n + ' ' + client);
}

function cleanSelectedSeat() {
    selected_seats = {};
}

function seatsChange(obj) {
    // obj should be a .sessioninput
    if (!obj) {
        obj = $(this);
    }
    // Only recalcTotal and autoseats if seats are changed
    if (selected_seats[obj.attr('id')] ==  obj.val()) {
        return;
    } else {
        selected_seats[obj.attr('id')] =  obj.val();
    }

    recalcSums(obj);
    recalcTotal();

    // if no name in the input, it's a numbered session
    // we do here the seat auto selection
    if (!obj.attr("name")) {
        var val = obj.val();
        var s = obj.data('session');
        var v = $("#seats-"+s).val();
        if (!v) {
            autoSelectSeat(s, val);
        } else {
            var current = [];
            current = v.split(",");
            if (current.length != val) {
                // unselecting all selected
                current.forEach(function(c) {
                    selector = '#' + s + '_' + c;
                    $(selector).removeClass('seat-selected');

                    a = c.split('_');
                    args = s;
                    args += ' ' + a[0];
                    args += ' ' + a[1];
                    args += ' ' + a[2];
                    args += ' ' + client;
                    ws.send('drop_seat ' + args);
                });
                $("#seats-"+s).val("");

                autoSelectSeat(s, val);
            }
        }
    }
}

function preSubmit() {
    var warnings = [];
    var sessions = [];

    $('.sessioninput').each(function() {
        val = parseInt($(this).val(), 10);
        id = $(this).attr("id");
        if (val) {
            sessions.push(id);
        }
    });

    $('.warning').each(function() {
        var warning = {};
        warning.name = $(this).data('name');
        warning.sessions1 = String($(this).data('sessions1')).split(',');
        warning.sessions2 = String($(this).data('sessions2')).split(',');
        warning.type = $(this).data('type');
        warning.message = $(this).data('message');
        warnings.push(warning);
    });

    confirms = ""
    for(var i=0; i<warnings.length; i++) {
        var w = warnings[i];
        if (check_warning(w, sessions)) {
            confirms += w.message + "\n\n";
        }
    }
    return confirms;
}

$(document).ready(function() {

    if (invalid_form.length) {
      window.location.hash = '#personal-info-form'
    }

    $("#btn-continue").click(function() {
        confirms = preSubmit();
        if (confirms) {
            alertify.confirm(confirms, function(e) {
                if (e) {
                    $("form").submit();
                } else {
                    return false;
                }
            });
        } else {
            $("form").submit();
        }
    });

    $('.withtooltip').tooltip();

    $(".seatmap").each(function() {
        var session = $(this).data('session');
        var obj = $("#modal-" + session);
        SeatMap.bindLayout(obj);
    });

    SeatMap.cbs.add(seatCB);
    ws.cbs.add(websocketCB);

    if (session_expired) {
        $(".sessioninput").val("0");
        $(".seats-input").val("");
    }

    $(".seats-input").each(function() {
        fillSelectedSeats($(this));
    });

    // calculating sums
    $('.sessioninput').keydown(function(e) {
        if (e.keyCode == 13) {
            return;
        }
        var obj = $(this);
        var id = obj.attr('id');
        if (e.keyCode == 9 || e.keyCode == 16) {
            seatsChange(obj);
            clearTimeout(delays[id]);
            setLoading("delay" + id, false);
        } else {
            setLoading("delay" + id, true);
            clearTimeout(delays[id]);
            delays[id] = setTimeout(function() {
                seatsChange(obj);
                setLoading("delay" + id, false);
            }, 500);
        }
    });
    recalcTotal();

    $('.sessioninput').each(function() {
        selected_seats[$(this).attr('id')] = $(this).val();
        recalcSums($(this));
        $(this).click(function() { $(this).select(); });
    });

    $(".plus").click(function() {
        var id = '#' + $(this).data("id");
        var max = parseInt($(id).attr('max') || 500, 10);
        var current = parseInt($(id).val(), 10);

        var next = current + 1;
        if (next > max) {
            next = max;
        }
        $(id).val(next);
        $(id).keydown();
        $(".plus").blur();
    });
    $(".minus").click(function() {
        var id = '#' + $(this).data("id");
        var min = parseInt($(id).attr('min') || 0, 10);
        var current = parseInt($(id).val(), 10);

        var next = current - 1;
        if (next < min) {
            next = min;
        }
        $(id).val(next);
        $(id).keydown();
        $(".minus").blur();
    });
});
<commit_msg>Fix typo error when check invalid form<commit_after>// Fix to make startsWith work in IE 11
if (!String.prototype.startsWith) {
    String.prototype.startsWith = function(searchString, position) {
        position = position || 0;
        return this.substr(position, searchString.length) === searchString;
    };
}

var loading = '';
var seaticon = '';
var sessionsloading = {};
var reserved_seats = [];

function loadingSession(s, isloading) {
    if (isloading) {
        $("#tooltip-"+s).html(loading);
        $(".plus[data-id="+s+"]").attr("disabled", "");
        $(".minus[data-id="+s+"]").attr("disabled", "");
    } else {
        $("#tooltip-"+s).html(seaticon);
        $(".plus[data-id="+s+"]").removeAttr("disabled");
        $(".minus[data-id="+s+"]").removeAttr("disabled");
    }
    setLoading(s, isloading);
}

function setLoading(id, isloading) {
    if (isloading) {
        sessionsloading[id] = true;
    } else {
        sessionsloading[id] = false;
    }

    for (i in sessionsloading) {
        if (sessionsloading[i]) {
            $("#finish").attr("disabled", "");
            return;
        }
    }

    $("#finish").removeAttr("disabled");
}

var old_session = -1;
var old_layout = -1;

delays = {};
selected_seats = {};

function check_warning(w, sessions) {
    if (w.type == 'req') {
        var firstFound = true;
        var secondFound = true;
        var ss = [];
        w.sessions1.forEach(function(s1) { ss.push(s1); });
        w.sessions2.forEach(function(s2) { ss.push(s2); });

        for (var i=0; i<w.sessions1.length; i++) {
            if (sessions.indexOf(w.sessions1[i]) < 0) {
                firstFound = false;
            }
        }
        for (var i=0; i<w.sessions2.length; i++) {
            if (sessions.indexOf(w.sessions2[i]) < 0) {
                secondFound = false;
            }
        }

        if (firstFound && !secondFound) {
            return true;
        }

        return false;
    }
}

function seat_droped(session, layout, seat) {
    var selector = '#' + session + '_' + layout + '_' + seat;
    $(selector).addClass("seat-L");
    $(selector).removeClass("seat-H");
    $(selector).unbind("click").click(function() {
        SeatMap.clickSeat($(this));
    });
}

function seat_holded(session, layout, seat) {
    var selector = '#' + session + '_' + layout + '_' + seat;

    if ($(selector).hasClass("seat-selected")) {
        return;
    }

    $(selector).addClass("seat-H");
    $(selector).removeClass("seat-L");
    $(selector).unbind("click");
}

function seat_reserved(session, layout, seat) {
    var selector = '#' + session + '_' + layout + '_' + seat;

    $(selector).addClass("seat-R");
    $(selector).removeClass("seat-L");
    $(selector).removeClass("seat-H");
    $(selector).unbind("click");

    // Update free seats from websockets
    if (reserved_seats.indexOf(selector) >= 0) {
        return;
    }
    reserved_seats.push(selector);
    try {
        free = $("td.layout-"+session+"-"+layout+" > div.layout-zone-free");
        free_num = free.html().trim().split(": ")[1];
        res = String(Number(free_num) - 1);
        free.html(free.html().replace(free_num, res));
    } catch(e) {
        console.error("Error updating free seats");
    }

}

function websocketCB(ev, data) {
    if (ev == 'hold') {
        var seat = data.row + '_' + data.col;
        seat_holded(data.session, data.layout, seat);
    } else if (ev == 'drop') {
        var seat = data.row + '_' + data.col;
        seat_droped(data.session, data.layout, seat);
    } else if (ev == 'confirm') {
        var seat = data.row + '_' + data.col;
        seat_reserved(data.session, data.layout, seat);
    } else if (ev == 'autoseat') {
        autoSelectSeatCB(data.session, data.seats, data.error);
    } else if (ev == 'holded') {
        var seat = data.row + '_' + data.col;
        var selector = '#' + data.session + '_' + data.layout + '_' + seat;
        $(selector).removeClass("seat-selected");
        seat_holded(data.session, data.layout, seat);
    }
}

function seatCB(ev, seat) {
    var row = seat.data("row");
    var col = seat.data("col");
    var session = seat.data("session");
    var layout = seat.data("layout");

    var current = [];
    var currentval = $("#seats-"+session).val();
    if (currentval) {
        current = currentval.split(",");
    }

    var str = layout + '_' + row + '_' + col;

    args = session;
    args += ' ' + layout;
    args += ' ' + row;
    args += ' ' + col;
    args += ' ' + client;

    if (ev == 'select') {
        current.push(str);
        ws.send('hold_seat ' + args);
    } else if (ev == 'unselect') {
        var idx = current.indexOf(str);
        if (idx >= 0) {
            current.splice(idx, 1);
        }
        ws.send('drop_seat ' + args);
    }

    $("#seats-"+session).val(current.join(","));
    $("#"+session).val(current.length);

    updateBadges(session, layout);

    $("#"+session).keydown();
}

function updateBadges(session, layout) {
    //updating the label with the number of selected seats
    var currentval = $("#seats-"+session).val();
    var current = currentval.split(",");
    var n = 0;
    current.forEach(function(element) {
        if (element.startsWith(layout + '_')) {
            n++;
        }
    });
    badge = $("#badge-"+session+"-"+layout);
    badge.text(n);
    if (n) {
        badge.addClass("label-success");
        badge.removeClass("label-default");
    } else {
        badge.removeClass("label-success");
        badge.addClass("label-default");
    }
    // Remove old badges. recursive function
    if (old_session != -1 && (old_session != session || old_layout != layout)) {
        updateBadges(old_session, old_layout);
    }
    old_session = session;
    old_layout = layout;
}

function recalcSums(obj) {
    var session = obj.attr("id");
    var val = parseInt(obj.val(), 10);

    if (isNaN(val)) {
        obj.val(0);
        val = 0;
    }

    var max = parseInt(obj.attr('max') || 500, 10);
    if (val > max) {
        val = max;
        obj.val(max);
    }

    var price = parseFloat(obj.data("price").replace(",", "."));
    $("#"+session+"-subtotal-price").html((val * price).toFixed(2));
}

function recalcTotal() {
    var sum = 0;
    $(".sessioninput").each(function() {
        var n = parseInt($(this).val(), 10);
        var price = parseFloat($(this).data("price").replace(",", "."));
        sum += price * n;
    });
    $("#total").html(sum.toFixed(2));
}

function fillSelectedSeats(obj) {
    // obj should be a .seats-input
    var session = obj.data('session');
    var v = obj.val();
    if (v) {
        var current = [];
        current = v.split(",");
        $("#"+session).val(current.length);
        $("#"+session).keydown();

        function recursiveSelection(arr, finish) {
            loadingSession(session, true);
            var c = arr.pop();
            var selector = '#' + session + '_' + c;
            var layout = c.split('_')[0];
            var l = $('.layout-'+session+'-'+layout);
            var obj = $('.display-'+session+'-'+layout);

            SeatMap.preloadLayout(l, obj, function() {
                updateBadges(session, layout);
                loadingSession(session, false);

                $(selector).removeClass("seat-H");
                $(selector).addClass("seat-selected");
                $(selector).unbind("click").click(function() {
                    SeatMap.clickSeat($(this));
                });

                if (arr.length) {
                    recursiveSelection(arr, finish);
                } else {
                    finish();
                }
            });
        }

        recursiveSelection(current.slice(0), function() {
            current.forEach(function(c) {
                var layout = c.split('_')[0];
                updateBadges(session, layout);
            });
        });
    } else {
        loadingSession(session, false);
    }
}

function autoSelectSeatCB(s, seats, error) {
    loadingSession(s, false);

    if (seats.length) {
        var value = [];
        seats.forEach(function(obj) {
            value.push(obj.layout+"_"+obj.row+"_"+obj.col);
        });
        $("#seats-"+s).val(value.join(","));
        fillSelectedSeats($("#seats-"+s));
    } else {
        if ($("#"+s).val() != 0) {
            $("#"+s).val(0);
            $("#"+s).select();
        }
        var layouts = $('#modal-'+s+' .layout');
        layouts.each(function() {
            var id = $(this).data('id');
            updateBadges(s, id);
        });
        alertify.alert(error);
        loadingSession(s, false);
    }
}

function autoSelectSeat(s, n) {
    if (n == 0) {
        return;
    }

    loadingSession(s, true);
    ws.send('autoseats ' + s + ' ' + n + ' ' + client);
}

function cleanSelectedSeat() {
    selected_seats = {};
}

function seatsChange(obj) {
    // obj should be a .sessioninput
    if (!obj) {
        obj = $(this);
    }
    // Only recalcTotal and autoseats if seats are changed
    if (selected_seats[obj.attr('id')] ==  obj.val()) {
        return;
    } else {
        selected_seats[obj.attr('id')] =  obj.val();
    }

    recalcSums(obj);
    recalcTotal();

    // if no name in the input, it's a numbered session
    // we do here the seat auto selection
    if (!obj.attr("name")) {
        var val = obj.val();
        var s = obj.data('session');
        var v = $("#seats-"+s).val();
        if (!v) {
            autoSelectSeat(s, val);
        } else {
            var current = [];
            current = v.split(",");
            if (current.length != val) {
                // unselecting all selected
                current.forEach(function(c) {
                    selector = '#' + s + '_' + c;
                    $(selector).removeClass('seat-selected');

                    a = c.split('_');
                    args = s;
                    args += ' ' + a[0];
                    args += ' ' + a[1];
                    args += ' ' + a[2];
                    args += ' ' + client;
                    ws.send('drop_seat ' + args);
                });
                $("#seats-"+s).val("");

                autoSelectSeat(s, val);
            }
        }
    }
}

function preSubmit() {
    var warnings = [];
    var sessions = [];

    $('.sessioninput').each(function() {
        val = parseInt($(this).val(), 10);
        id = $(this).attr("id");
        if (val) {
            sessions.push(id);
        }
    });

    $('.warning').each(function() {
        var warning = {};
        warning.name = $(this).data('name');
        warning.sessions1 = String($(this).data('sessions1')).split(',');
        warning.sessions2 = String($(this).data('sessions2')).split(',');
        warning.type = $(this).data('type');
        warning.message = $(this).data('message');
        warnings.push(warning);
    });

    confirms = ""
    for(var i=0; i<warnings.length; i++) {
        var w = warnings[i];
        if (check_warning(w, sessions)) {
            confirms += w.message + "\n\n";
        }
    }
    return confirms;
}

$(document).ready(function() {

    if (invalid_form) {
      window.location.hash = '#personal-info-form'
    }

    $("#btn-continue").click(function() {
        confirms = preSubmit();
        if (confirms) {
            alertify.confirm(confirms, function(e) {
                if (e) {
                    $("form").submit();
                } else {
                    return false;
                }
            });
        } else {
            $("form").submit();
        }
    });

    $('.withtooltip').tooltip();

    $(".seatmap").each(function() {
        var session = $(this).data('session');
        var obj = $("#modal-" + session);
        SeatMap.bindLayout(obj);
    });

    SeatMap.cbs.add(seatCB);
    ws.cbs.add(websocketCB);

    if (session_expired) {
        $(".sessioninput").val("0");
        $(".seats-input").val("");
    }

    $(".seats-input").each(function() {
        fillSelectedSeats($(this));
    });

    // calculating sums
    $('.sessioninput').keydown(function(e) {
        if (e.keyCode == 13) {
            return;
        }
        var obj = $(this);
        var id = obj.attr('id');
        if (e.keyCode == 9 || e.keyCode == 16) {
            seatsChange(obj);
            clearTimeout(delays[id]);
            setLoading("delay" + id, false);
        } else {
            setLoading("delay" + id, true);
            clearTimeout(delays[id]);
            delays[id] = setTimeout(function() {
                seatsChange(obj);
                setLoading("delay" + id, false);
            }, 500);
        }
    });
    recalcTotal();

    $('.sessioninput').each(function() {
        selected_seats[$(this).attr('id')] = $(this).val();
        recalcSums($(this));
        $(this).click(function() { $(this).select(); });
    });

    $(".plus").click(function() {
        var id = '#' + $(this).data("id");
        var max = parseInt($(id).attr('max') || 500, 10);
        var current = parseInt($(id).val(), 10);

        var next = current + 1;
        if (next > max) {
            next = max;
        }
        $(id).val(next);
        $(id).keydown();
        $(".plus").blur();
    });
    $(".minus").click(function() {
        var id = '#' + $(this).data("id");
        var min = parseInt($(id).attr('min') || 0, 10);
        var current = parseInt($(id).val(), 10);

        var next = current - 1;
        if (next < min) {
            next = min;
        }
        $(id).val(next);
        $(id).keydown();
        $(".minus").blur();
    });
});
<|endoftext|>


<commit_before>// Pulls the JSON data from csv-to-json.js and api-to-json.js and outputs them for ED3D

//Define Categories
window.systemsData = {
	"categories": {
		"Points of Interest": {
			"100": {
				"name": "System",
				"color": "F7F7F7"
			},
			"101": {
				"name": "MegaShips",
				"color": "f4f142"
			}
		},
		"Barnacles": {
			"200": {
				"name": "Barnacle",
				"color": "44f441"
			}
			// Disabled until output shows status
			/*			"200": {
			"name": "Ripe",
			"color": "F7F7F7"
			},
			"201": {
			"name": "Dead",
			"color": "F7F7F7"
			} */
		},
		"Brain Trees": {
			"300": {
				"name": "Brain Tree",
				"color": "41e5f4"
			}
		},
		"Guardian Ruins": {
			"400": {
				"name": "Alpha",
				"color": "f44141"
			},
			"401": {
				"name": "Beta",
				"color": "f4b241"
			},
			"402": {
				"name": "Gamma",
				"color": "f441d0"
			}
		},
		"Thargoid Structures": {
			"500": {
				"name": "Active",
				"color": "4152f4"
			},
			"501": {
				"name": "Inactive",
				"color": "9d41f4"
			}
		}
	},
	"systems": [{
			"name": "Sol",
			"coords": {
				"x": "0",
				"y": "0",
				"z": "0"
			},
			"cat": [
				"100"
			]
		}, {
			"name": "Merope",
			"coords": {
				"x": "-78.59375",
				"y": "-149.625",
				"z": "-340.53125"
			},
			"cat": [
				"100"
			]
		}, {
			"name": "HIP 22460",
			"coords": {
				"x": "-41.3125",
				"y": "-58.96875",
				"z": "-354.78125"
			},
			"cat": [
				"100"
			]
		}, {
			"name": "Col 173 Sector LJ-F C12-0 (The Cete)",
			"coords": {
				"x": "1202.125",
				"y": "-213.40625",
				"z": "-165.5625"
			},
			"cat": [
				"101"
			]
		},
	]
};

// Lets get data from CSV Files
function formatBN(data) {
	//Here you format BN JSON to ED3D acceptable object

	// this is assuming data is an array []
	for (var i = 0; i < data.length; i++) {
		var bnSite = {};
		bnSite["name"] = data[i].system;

		//Ripe or Dead Status not enabled yet, pending CSV fixes
		bnSite["cat"] = [200];
		bnSite["coords"] = {
			"x": parseFloat(data[i].galacticX),
			"y": parseFloat(data[i].galacticY),
			"z": parseFloat(data[i].galacticZ)
		};

		// We can then push the site to the object that stores all systems
		window.systemsData.systems.push(bnSite);

	}

}

function formatBT(data) {
	//Here you format BT JSON to ED3D acceptable object

	// this is assuming data is an array []
	for (var i = 0; i < data.length; i++) {
		var btSite = {};
		btSite["name"] = data[i].system;
		btSite["cat"] = [300];
		btSite["coords"] = {
			"x": parseFloat(data[i].galacticX),
			"y": parseFloat(data[i].galacticY),
			"z": parseFloat(data[i].galacticZ)
		};

		// We can then push the site to the object that stores all systems
		window.systemsData.systems.push(btSite);

	}

}

function formatTS(data) {
	//Here you format TS JSON to ED3D acceptable object

	// this is assuming data is an array []
	for (var i = 0; i < data.length; i++) {
		var tsSite = {};
		tsSite["name"] = data[i].system;

		//Check if Site is Active or Inactive, set Category to match
		if (data[i].active.toString().toLowerCase() == "y") {
			tsSite["cat"] = [500];
		} else {
			tsSite["cat"] = [501];
		}
		tsSite["coords"] = {
			"x": parseFloat(data[i].galacticX),
			"y": parseFloat(data[i].galacticY),
			"z": parseFloat(data[i].galacticZ)
		};

		// We can then push the site to the object that stores all systems
		window.systemsData.systems.push(tsSite);

	}

}

/* AdmlAdam's Code
// GR data from Canonn API and format
var stellarInfo = 'https://api.canonn.technology/api/v1/stellar/systems';
var systemList = 'https://api.canonn.technology/api/v1/maps/systemoverview';

var stellarCoords = {}

$.get(stellarInfo).done(function (stellarList) {
	//Get the stellar coords and cache them
	$.each(stellarList, function (index, info) {
		stellarCoords[info.id] = {
			'x': info.edsmCoordX,
			'y': info.edsmCoordY,
			'z': info.edsmCoordZ
		}
	});

	$.get(systemList).done(function (systemList) {
		$.each(systemList, function (index, system) {
			//Create the system info
			var sysId = system.systemId;
			var sysName = system.systemName;

			if (sysName.substr(0, 2) != 'z.') {
				var newSystem = {
					"name": sysName,
					"coords": {
						"x": stellarCoords[sysId].x,
						"y": stellarCoords[sysId].y,
						"z": stellarCoords[sysId].z
					},
					"cat": [
						"100"
					]
				}

				//Add system
				systemsData["systems"].push(newSystem);
			}
		});
	})
	.fail(function (d, textStatus, error) {
		alert("Error fetching Guardian Systems: " + error);
	})
})
*/

function parseData(url, callBack, resolvePromise) {
	Papa.parse(url, {
		download: true,
		header: true,
		complete: function (results) {

			console.log(results); // This is probably your data
			console.log(results.data); // This is probably undefined
			callBack(results.data);

			// after we called the callback
			// (which is synchronous, so we know it's safe here)
			// we can resolve the promise

			resolvePromise();
		}
	});
}

var p1 = new Promise(function (resolve, reject) {
		parseData("https://docs.google.com/spreadsheets/d/e/2PACX-1vTCGOwaRT8ESad9j0GAQ7tMMNj8ObxipFW8fop3eaZ-HoCVo_k9dQsHVvs1oFvARrY5SC6o4uDAWKQA/pub?gid=290263950&single=true&output=csv", formatBN, resolve);
	});

var p2 = new Promise(function (resolve, reject) {
		parseData("https://docs.google.com/spreadsheets/d/e/2PACX-1vRdEQQByWyU8MlzfJw9SzEsaM9c_zDV_RJ49Fiox842EEELrUHpMPexLYhjqNB8SOzB564jJ_oLdBx2/pub?gid=0&single=true&output=csv", formatBT, resolve);
	});

var p3 = new Promise(function (resolve, reject) {
		parseData("https://docs.google.com/spreadsheets/d/e/2PACX-1vR4-rhi1p4BU7AlOSj7_78Kvk5Ox6vb39vzzlWU3yI-dqlaLxk-CFLWvAFKc-J7WhomFiQ_u0P7Stxz/pub?gid=0&single=true&output=csv", formatTS, resolve);
	});

Promise.all([p1, p2, p3]).then(function () {
	Ed3d.init({
		container: 'edmap',
		json: window.systemsData,
		withHudPanel: true,
		hudMultipleSelect: true,
		effectScaleSystem: [50, 10000],
		startAnim: false,
		showGalaxyInfos: true,
		cameraPos: [25, 14100, -12900],
		systemColor: '#FF9D00'
	})
});
<commit_msg>Add GR CSV (No API :( )<commit_after>// Pulls the JSON data from csv-to-json.js and api-to-json.js and outputs them for ED3D

//Define Categories
window.systemsData = {
	"categories": {
		"Points of Interest - POI": {
			"100": {
				"name": "System",
				"color": "F7F7F7"
			},
			"101": {
				"name": "MegaShips",
				"color": "f4f142"
			}
		},
		"Barnacles - (BN)": {
			"200": {
				"name": "Barnacle",
				"color": "44f441"
			}
			// Disabled until output shows status
			/*			"200": {
			"name": "Ripe",
			"color": "F7F7F7"
			},
			"201": {
			"name": "Dead",
			"color": "F7F7F7"
			} */
		},
		"Brain Trees - (BT)": {
			"300": {
				"name": "Brain Tree",
				"color": "41e5f4"
			}
		},
		"Guardian Ruins - (GR)": {
			"400": {
				"name": "Alpha",
				"color": "f44141"
			},
			"401": {
				"name": "Beta",
				"color": "f4b241"
			},
			"402": {
				"name": "Gamma",
				"color": "f441d0"
			}
		},
		"Thargoid Structures - (TS)": {
			"500": {
				"name": "Active",
				"color": "4152f4"
			},
			"501": {
				"name": "Inactive",
				"color": "9d41f4"
			}
		},
		"Error Sites": {
			"600": {
				"name": "Invalid Data Information",
				"color": "150187"
			}
		}
	},
	"systems": [{
			"name": "Sol",
			"coords": {
				"x": "0",
				"y": "0",
				"z": "0"
			},
			"cat": [
				"100"
			]
		}, {
			"name": "Merope",
			"coords": {
				"x": "-78.59375",
				"y": "-149.625",
				"z": "-340.53125"
			},
			"cat": [
				"100"
			]
		}, {
			"name": "HIP 22460",
			"coords": {
				"x": "-41.3125",
				"y": "-58.96875",
				"z": "-354.78125"
			},
			"cat": [
				"100"
			]
		}, {
			"name": "Col 173 Sector LJ-F C12-0 (The Cete)",
			"coords": {
				"x": "1202.125",
				"y": "-213.40625",
				"z": "-165.5625"
			},
			"cat": [
				"101"
			]
		},
	]
};

// Lets get data from CSV Files
function formatBN(data) {
	//Here you format BN JSON to ED3D acceptable object

	// this is assuming data is an array []
	for (var i = 0; i < data.length; i++) {
		var bnSite = {};
		bnSite["name"] = data[i].system;

		//Ripe or Dead Status not enabled yet, pending CSV fixes
		bnSite["cat"] = [200];
		bnSite["coords"] = {
			"x": parseFloat(data[i].galacticX),
			"y": parseFloat(data[i].galacticY),
			"z": parseFloat(data[i].galacticZ)
		};

		// We can then push the site to the object that stores all systems
		window.systemsData.systems.push(bnSite);

	}

}

function formatBT(data) {
	//Here you format BT JSON to ED3D acceptable object

	// this is assuming data is an array []
	for (var i = 0; i < data.length; i++) {
		var btSite = {};
		btSite["name"] = data[i].system;
		btSite["cat"] = [300];
		btSite["coords"] = {
			"x": parseFloat(data[i].galacticX),
			"y": parseFloat(data[i].galacticY),
			"z": parseFloat(data[i].galacticZ)
		};

		// We can then push the site to the object that stores all systems
		window.systemsData.systems.push(btSite);

	}

}

function formatTS(data) {
	//Here you format TS JSON to ED3D acceptable object

	// this is assuming data is an array []
	for (var i = 0; i < data.length; i++) {
		var tsSite = {};
		tsSite["name"] = data[i].system;

		//Check if Site is Active or Inactive, set Category to match
		if (data[i].active.toString().toLowerCase() == "y") {
			tsSite["cat"] = [500];
		} else {
			tsSite["cat"] = [501];
		}
		tsSite["coords"] = {
			"x": parseFloat(data[i].galacticX),
			"y": parseFloat(data[i].galacticY),
			"z": parseFloat(data[i].galacticZ)
		};

		// We can then push the site to the object that stores all systems
		window.systemsData.systems.push(tsSite);

	}

}

function formatGR(data) {
	//Here you format GR JSON to ED3D acceptable object

	// this is assuming data is an array []
	for (var i = 0; i < data.length; i++) {
		var grSite = {};
		grSite["name"] = data[i].system;

		//Check Site Type and match categories
		if (data[i].type.toString() == "Alpha") {
			grSite["cat"] = [400];
		} else if (data[i].type.toString() == "Beta") {
			grSite["cat"] = [401];
		} else if (data[i].type.toString() == "Gamma") {
			grSite["cat"] = [402];
		} else {
			grSite["cat"] = [600];
		}
		grSite["coords"] = {
			"x": parseFloat(data[i].galacticX),
			"y": parseFloat(data[i].galacticY),
			"z": parseFloat(data[i].galacticZ)
		};

		// We can then push the site to the object that stores all systems
		window.systemsData.systems.push(grSite);

	}

}

function parseData(url, callBack, resolvePromise) {
	Papa.parse(url, {
		download: true,
		header: true,
		complete: function (results) {

			console.log(results); // This is probably your data
			console.log(results.data); // This is probably undefined
			callBack(results.data);

			// after we called the callback
			// (which is synchronous, so we know it's safe here)
			// we can resolve the promise

			resolvePromise();
		}
	});
}

var p1 = new Promise(function (resolve, reject) {
		parseData("https://docs.google.com/spreadsheets/d/e/2PACX-1vTCGOwaRT8ESad9j0GAQ7tMMNj8ObxipFW8fop3eaZ-HoCVo_k9dQsHVvs1oFvARrY5SC6o4uDAWKQA/pub?gid=290263950&single=true&output=csv", formatBN, resolve);
	});

var p2 = new Promise(function (resolve, reject) {
		parseData("https://docs.google.com/spreadsheets/d/e/2PACX-1vRdEQQByWyU8MlzfJw9SzEsaM9c_zDV_RJ49Fiox842EEELrUHpMPexLYhjqNB8SOzB564jJ_oLdBx2/pub?gid=0&single=true&output=csv", formatBT, resolve);
	});

var p3 = new Promise(function (resolve, reject) {
		parseData("https://docs.google.com/spreadsheets/d/e/2PACX-1vR4-rhi1p4BU7AlOSj7_78Kvk5Ox6vb39vzzlWU3yI-dqlaLxk-CFLWvAFKc-J7WhomFiQ_u0P7Stxz/pub?gid=0&single=true&output=csv", formatTS, resolve);
	});

var p4 = new Promise(function (resolve, reject) {
		parseData("https://docs.google.com/spreadsheets/d/e/2PACX-1vTSvkdtHr0SbM4dYOCsDalp1hRilWt2I5Hz1l2OIgbfR8Hs-lOCat_ZUyhyBnuv9R9rXz9vnhaYif2-/pub?gid=0&single=true&output=csv", formatGR, resolve);
	});

Promise.all([p1, p2, p3, p4]).then(function () {
	Ed3d.init({
		container: 'edmap',
		json: window.systemsData,
		withHudPanel: true,
		hudMultipleSelect: true,
		effectScaleSystem: [50, 10000],
		startAnim: false,
		showGalaxyInfos: true,
		cameraPos: [25, 14100, -12900],
		systemColor: '#FF9D00'
	})
});
<|endoftext|>