#!/usr/bin/env node

var program = require('commander');
var Bunzip = require('../');
var fs = require('fs');

program
    .version(Bunzip.version)
    .usage('-d|-z [infile] [outfile]')
    .option('-d, --decompress',
	    'Decompress stdin to stdout')
    //.option('-z, --compress',
    //      'Compress stdin to stdout')
    .option('-b, --block <n>',
	    'Extract a single block, starting at <n> bits.', undefined)
    .option('-m, --multistream',
	    'Read a multistream bzip2 file');
program.on('--help', function() {
    console.log('  If <infile> is omitted, reads from stdin.');
    console.log('  If <outfile> is omitted, writes to stdout.');
});
program.parse(process.argv);

if (!program.compress) { program.decompress = true; }

if (program.compress && program.block !== undefined) {
    console.error('--block can only be used with decompression');
    return 1;
}

if (program.decompress && program.compress) {
    console.error('Must specify either -d or -z.');
    return 1;
}

var makeInStream = function(in_fd) {
    var stat = fs.fstatSync(in_fd);
    var stream = {
	buffer: new Buffer(4096),
	filePos: null,
	pos: 0,
	end: 0,
	_fillBuffer: function() {
	    this.end = fs.readSync(in_fd, this.buffer, 0, this.buffer.length,
				  this.filePos);
	    this.pos = 0;
	    if (this.filePos !== null && this.end > 0) {
		this.filePos += this.end;
	    }
	},
	readByte: function() {
	    if (this.pos >= this.end) { this._fillBuffer(); }
	    if (this.pos < this.end) {
		return this.buffer[this.pos++];
	    }
	    return -1;
	},
	read: function(buffer, bufOffset, length) {
	    if (this.pos >= this.end) { this._fillBuffer(); }
	    var bytesRead = 0;
	    while (bytesRead < length && this.pos < this.end) {
		buffer[bufOffset++] = this.buffer[this.pos++];
		bytesRead++;
	    }
	    return bytesRead;
	},
	seek: function(seek_pos) {
	    this.filePos = seek_pos;
	    this.pos = this.end = 0;
	},
	eof: function() {
	  if (this.pos >= this.end) { this._fillBuffer(); }
	  return !(this.pos < this.end);
	}
    };
    if (stat.size) {
	stream.size = stat.size;
    }
    return stream;
};
var makeOutStream = function(out_fd) {
    return {
	buffer: new Buffer(4096),
	pos: 0,
	flush: function() {
	    fs.writeSync(out_fd, this.buffer, 0, this.pos);
	    this.pos = 0;
	},
	writeByte: function(byte) {
	    if (this.pos >= this.buffer.length) { this.flush(); }
	    this.buffer[this.pos++] = byte;
	}
    };
};

var in_fd = 0, close_in = function(){};
var out_fd = 1, close_out = function(){};
if (program.args.length > 0) {
    in_fd = fs.openSync(program.args.shift(), 'r');
    close_in = function() { fs.closeSync(in_fd); };
}
if (program.args.length > 0) {
    out_fd = fs.openSync(program.args.shift(), 'w');
    close_out = function() { fs.closeSync(out_fd); };
}

var inStream = makeInStream(in_fd);
var outStream= makeOutStream(out_fd);

if (program.decompress) {
    try {
        if (program.block !== undefined) {
	    Bunzip.decodeBlock(inStream, +program.block, outStream);
        } else {
	    Bunzip.decode(inStream, outStream, program.multistream);
        }
        outStream.flush();
    } catch (e) {
        if (e.code !== 'EPIPE') throw e;
    }
    close_in();
    close_out();
    return 0;
}
if (program.compress) {
    console.error('Compression not yet implemented.');
    return 1;
}
return 1;
