text: "use strict";
  
  var util = require ("util");
  var packets = require ("../packets");
  var opcodes = require ("../opcodes");
  var errors = require ("../errors");
  var Request = require ("../request");
  var knownExtensions = require ("../known-extensions");
  
  var IncomingRequest = module.exports = function (args){
  	Request.call (this, args.helper._rinfo.address, args.helper._rinfo.port,
  			args.globalOptions.retries, args.globalOptions.extensions.timeout, args.globalOptions.interceptor);
  
  	this._isRRQ = !args.reader;
  	this._globalOptions = args.globalOptions;
  	this._maxDataLength = 4;
  	this._file = args.message.file;
  	this._size = args.size || null;
  	this._requestUserExtensions = args.message.userExtensions;
  	this._responseUserExtensions = null;
  	this._oackSent = false;
  	this._firstPacket = true;
  	this._requestExtensions = args.message.extensions;
  	this._responseExtensions = null;
  
  	var me = this;
  	this._initSocket (args.helper._socket, function (message){
  		if (me._firstPacket){
  			me._firstPacket = false;
  			me._requestTimer.reset ();
  		}
  		me._onMessage (message);
  	});
  
  	//The socket is still not bound to an address and port because no packet has
  	//been still sent, so the stats cannot be emitted yet (the call to address()
  	//fails)
  	//The socket must be manually bound
  	this._socket.bind (0, null, function (){
  		if (me._requestExtensions === null){
  			//The client doesn't send extensions, it's probably that it doesn't
  			//rollover automatically (old client), so we can abort the transfer
  			//prematurely
  			//Check the size (65535x512)
  			if (me._isRRQ && me._size > 33553920){
  				return me._sendErrorAndClose (errors.EFBIG);
  			}
  			me._onReady (me._createStats (512, 1), 0);
  			if (!me._isRRQ){
  				//The ACK of the block 0 is retransmitted from the reader
  				me._sendAck (0);
  			}
  		}else{
  			//Send OACK
  			me._sendOackMessage (me._requestExtensions);
  		}
  	});
  };
  
  util.inherits (IncomingRequest, Request);
  
  IncomingRequest.prototype.continueRequest = function (size){
  	this._setSize (size);
  
  	if (this._requestExtensions === null){
  		this.onContinue ();
  	}else{
          if( this._responseExtensions.tsize !== undefined){
              this._responseExtensions.tsize = size;
          }
  
  		//Set the user extensions
  		for (var p in this._responseUserExtensions){
  			//Ignore invalid extensions
  			if (knownExtensions[p]) continue;
  			if (this._requestUserExtensions[p] === undefined) continue;
  			this._responseExtensions[p] = this._responseUserExtensions[p];
  		}
  
  		this._sendAndRetransmit (packets.oack.serialize (this._responseExtensions));
  	}
  };
  
  IncomingRequest.prototype._createStats = function (blockSize, windowSize){
  	//Save max data length
  	this._maxDataLength += blockSize;
  
  	var address = this._socket.address ();
  
  	return {
  		blockSize: blockSize,
  		windowSize: windowSize,
  		size: this._size,
  		userExtensions: this._requestUserExtensions,
  		retries: this._globalOptions.retries,
  		timeout: this._timeout,
  		localAddress: address.address,
  		localPort: address.port,
  		remoteAddress: this._address,
  		remotePort: this._port,
  	};
  };
  
  IncomingRequest.prototype._onMessage = function (buffer){
  	var op = buffer.readUInt16BE (0);
  
  	if (op === opcodes.DATA){
  		if (!this._isRRQ){
  			if (buffer.length < 4 || buffer.length > this._maxDataLength){
  				return this._sendErrorAndClose (errors.EBADMSG);
  			}
  			try{
  				this._onData (packets.data.deserialize (buffer));
  			}catch (error){
  				this._sendErrorAndClose (error);
  			}
  		}else{
  			this._sendErrorAndClose (errors.EBADOP);
  		}
  	}else if (op === opcodes.ACK){
  		if (this._isRRQ){
  			if (buffer.length !== 4){
  				return this._sendErrorAndClose (errors.EBADMSG);
  			}
  			if (this._oackSent){
  				this._oackSent = false;
  				if (buffer.readUInt16BE (2) !== 0){
  					this._sendErrorAndClose (errors.EBADMSG);
  				}else{
  					this.onContinue ();
  				}
  			}else{
  				try{
  					this._onAck (packets.ack.deserialize (buffer));
  				}catch (error){
  					this._sendErrorAndClose (error);
  				}
  			}
  		}else{
  			this._sendErrorAndClose (errors.EBADOP);
  		}
  	}else if (op === opcodes.ERROR){
  		if (buffer.length < 4) return this._closeWithError (errors.EBADMSG);
  		try{
  			this._close (new Error (packets.error.deserialize (buffer).message));
  		}catch (error){
  			return this._closeWithError (error);
  		}
  	}else{
  		this._sendErrorAndClose (errors.EBADOP);
  	}
  };
  
  IncomingRequest.prototype._sendOackMessage = function (extensions){
  	var ext = {};
  	if (extensions.blksize !== undefined){
  		var blksize = this._globalOptions.extensions.blksize;
  		ext.blksize = extensions.blksize > blksize ? blksize : extensions.blksize;
  	}
  	if (extensions.windowsize !== undefined){
  		var windowsize = this._globalOptions.extensions.windowsize;
  		ext.windowsize = extensions.windowsize > windowsize
  				? windowsize
  				: extensions.windowsize;
  	}
  	if (extensions.tsize !== undefined){
  		if (!this._isRRQ) this._size = extensions.tsize;
  		ext.tsize = extensions.tsize;
  		//ext.tsize is set later, when the request continues (RRQ)
  	}
  	if (extensions.rollover !== undefined){
  		ext.rollover = 0;
  	}
  
  	this._oackSent = true;
  	var me = this;
  	var ready = function (){
  		me._onReady (me._createStats (ext.blksize || 512, ext.windowsize || 1),
  			0, true);
  	};
  
  	if (this._isRRQ){
  		//Save the extensions
  		this._responseExtensions = ext;
  		ready ();
  	}else{
  		ready ();
  		this._sendAndRetransmit (packets.oack.serialize (ext));
  	}
  };