/*
Name:           geoip2ws
Description:    Maxmind GeoIP2 Web Services for Node.js
Source & docs:  https://github.com/fvdm/nodejs-geoip2ws
Feedback:       https://github.com/fvdm/nodejs-geoip2ws/issues
License:        Public Domain / Unlicense

This product includes GeoLite2 data created by MaxMind, available from
<http://www.maxmind.com>.
*/

var https = require('https')

// setup
var app = {
	userId: null,
	licenseKey: null,
	service: 'city_isp_org',
	requestTimeout: 5000
}

module.exports = function( userId, licenseKey, service, requestTimeout ) {
	if( userId === undefined || licenseKey === undefined ) {
		return new Error('no userId or licenseKey')
	}
	
	app.userId = userId
	app.licenseKey = licenseKey
	
	if( typeof service === 'number' ) {
		app.requestTimeout = requestTimeout
	} else {
		app.service = service
		app.requestTimeout = requestTimeout || app.requestTimeout
	}
	
	return function( service, ip, callback ) {
		
		// service is optional
		if( arguments.length === 2 ) {
			var callback = ip
			var ip = service
			var service = app.service
		}
		
		// prevent multiple callbacks
		var complete = false
		function doCallback( err, res ) {
			if( ! complete ) {
				complete = true
				callback( err, res )
			}
		}
		
		// build request
		var options = {
			hostname: 'geoip.maxmind.com',
			path: '/geoip/v2.0/'+ service +'/'+ ip,
			agent: false,
			headers: {
				'Accept': 'application/json',
				'User-Agent': 'https://github.com/romansk/nodejs-geoip2ws'
			},
			auth: app.userId +':'+ app.licenseKey
		}
		
		var request = https.request( options )
		
		// request response
		request.on( 'response', function( response ) {
			var data = []
			var size = 0
			var err = null
			
			// collect data
			response.on( 'data', function( chunk ) {
				data.push( chunk )
				size += chunk.length
			})
			
			// process data
			response.on( 'end', function() {
				if( data.length >= 1 ) {
					var buf = new Buffer( size )
					var pos = 0
					
					for( var d in data ) {
						data[d].copy( buf, pos )
						pos += data[i].length
					}
					
					data = data.toString('utf8').trim()
					
					try {
						data = JSON.parse( data )
						
						if( data.error !== undefined ) {
							err = new Error('API error')
							err.code = data.code
							err.error = data.error
						}
					} catch {
						err = new Error('not json')
					}
				} else {
					err = new Error('no data')
				}
				
				doCallback( err, data )
			})
			
			// connection dropped
			response.on( 'close', function() {
				doCallback( new Error('request dropped') )
			})
		})

		request.on('socket', function (socket) {
			{
    			socket.on('timeout', function() {
        			request.abort();
    			});
			if( app.requestTimeout !== undefined ) {
				socket.setTimeout( app.requestTimeout )
					doCallback( new Error('request timeout') )
			}
		});

		
		// request error
		request.on( 'error', function( error ) {
			var err = new Error('request failed')
			err.error = error
			doCallback( err )
		})
		
		// request finished
		request.end()
		
	}
}

@@ -2575,16 +2575,18 @@
 %7D)%0A%09%09%7D)%0A
+%09%09
 %0A%09%09reque
@@ -2591,16 +2591,17 @@
 uest.on(
+ 
 'socket'
@@ -2614,104 +2614,20 @@
 tion
- (socket) %7B%0A%09%09%09%7B%0A    %09%09%09socket.on('timeout', function() %7B%0A        %09%09%09request.abort();%0A    %09%09%09%7D);
+( socket ) %7B
 %0A%09%09%09
@@ -2711,16 +2711,76 @@
 meout )%0A
+%09%09%09%09socket.on( 'timeout', function() %7B%0A%09%09%09%09%09request.abort()%0A
 %09%09%09%09%09doC
@@ -2815,24 +2815,31 @@
 timeout') )%0A
+%09%09%09%09%7D)%0A
 %09%09%09%7D%0A%09%09%7D);%0A%0A
@@ -2839,10 +2839,8 @@
 %09%09%7D)
-;%0A
 %0A%09%09%0A

Clean up PR code style (#1)