text: /*
  *Parser for MRC files
  *
  */
  
  // provides
  goog.provide('X.parserMRC');
  
  // requires
  goog.require('X.event');
  goog.require('X.object');
  goog.require('X.parser');
  goog.require('X.triplets');
  goog.require('goog.vec.Mat3');
  goog.require('goog.vec.Mat4');
  goog.require('Zlib.Gunzip');
  
  /**
   * Create a parser for .mrc files.
   *
   * @constructor
   * @extends X.parser
   */
  X.parserMRC = function() {
  
  	//
  	// call the standard constructor of X.parser
  	goog.base(this);
  
  	//
  	// class attributes
  
  	/*
  	 * @inheritDoc
  	 * @const
  	*/
  	this._classname = 'parserMRC';
  };
  // inhert from X.parser
  goog.inherits(X.parserMRC, X.parser);
  
  /**
   * @inheritDoc
   */
  X.parserMRC.prototype.parse = function(container, object, data, flag) {
  	
  	X.TIMER(this._classname + '.parse');
  
  	var _data = data;
  
  	// parse the byte stream
  	var MRI = this.parseStream(_data);
  
  	// min and max intensities
  	var min = MRI.min;
  	var max = MRI.max;
  
  	//get dimsensions
  	var _dimensions = [MRI.nx, MRI.ny, MRI.nz];
  	object._dimensions = _dimensions
  
  	//get pixel spacing = xlen/mx
  	var spacingX = MRI.xlen / MRI.mx;
  	var spacingY = MRI.ylen / MRI.my;
  	var spacingZ = MRI.zlen / MRI.mz;
  	object._spacing = [ spacingX, spacingY, spacingZ ];
  
  	// attach the scalar range to the volume
  	object._min = object._windowLow = min;
  	object._max = object._windowHigh = max;
  	
  	// set the default threshold
  	if (object._lowerThreshold == -Infinity) {
  		object._lowerThreshold = min;
  	}
  	if (object._upperThreshold == Infinity) {
  		object._upperThreshold = max;
  	}
  	
  	// Create IJKtoXYZ matris
  	var IJKToRAS = goog.vec.Mat4.createFloat32();
  	goog.vec.Mat4.setRowValues(IJKToRAS,
  		3,
  		0,
  		0,
  		0,
  		1);
  			
  	// fill in IJKToRas
  	
  	goog.vec.Mat4.setRowValues(IJKToRAS, 0, -1, 0, 0, MRI.nx);
  	goog.vec.Mat4.setRowValues(IJKToRAS, 1, 0, 0, -1, MRI.ny);
  	goog.vec.Mat4.setRowValues(IJKToRAS, 2, 0, -1, 0, MRI.nz);
  	
  	// IJK to RAS and invert
  	MRI.IJKToRAS = IJKToRAS;
  	MRI.RASToIJK = goog.vec.Mat4.createFloat32();
  	goog.vec.Mat4.invert(MRI.IJKToRAS, MRI.RASToIJK);
  	
  	// get bounding box
  	// Transform ijk (0, 0, 0) to RAS
  	var tar = goog.vec.Vec4.createFloat32FromValues(0, 0, 0, 1);
  	var res = goog.vec.Vec4.createFloat32();
  	goog.vec.Mat4.multVec4(IJKToRAS, tar, res);
  	// Transform ijk (spacingX, spacinY, spacingZ) to RAS
  	var tar2 = goog.vec.Vec4.createFloat32FromValues(1, 1, 1, 1);
  	var res2 = goog.vec.Vec4.createFloat32();
  	goog.vec.Mat4.multVec4(IJKToRAS, tar2, res2);
  	
  	// get location of 8 corners and update BBox
  	var _dims = [MRI.nx, MRI.ny, MRI.nz];
  	var _rasBB = X.parser.computeRASBBox(IJKToRAS, _dims);
  	
  	// grab the RAS dimensions
  	MRI.RASSpacing = [res2[0] - res[0], res2[1] - res[1], res2[2] - res[2]];
  	MRI.RASDimensions = [_rasBB[1] + _rasBB[0] + 1, _rasBB[3] - _rasBB[2] + 1, _rasBB[5] - _rasBB[4] + 1];
  	
  	// grab the RAS Origin
  	MRI.RASOrigin = [_rasBB[0], _rasBB[2], _rasBB[4]];
  	
  	//grab the IJK dimensions
  	object._dimensions = _dims;
  	
  	// create the object
  	object.create_(MRI);
  	
  	// re-slice the data according each direction.
  	object._image = this.reslice(object);
  
  	X.TIMERSTOP(this._classname + '.parse');
  
  	// the object should be set up here, so let's fire a modified event
  	var modifiedEvent = new X.event.ModifiedEvent();
  	modifiedEvent._object = object;
  	modifiedEvent._container = container;
  	this.dispatchEvent(modifiedEvent);
  
  };
  
  /**
   *Parse the data stream following the MRC file format
   *File format specifications can be found at http://bio3d.colorado.edu/imod/doc/mrc_format.txt
   *
   * @param {!ArrayBuffer} data The data stream
   * @return {Object} the MRI structure which holds all parsed information
   */
  X.parserMRC.prototype.parseStream = function(data) {
  
  	this._data = data;
  
  	var MRI = {
  		nx: 0, //Number of Columns
  		ny: 0, //Number of Rows
  		nz: 0, //Number of Sections
  		mode: 0, //Type of pixel in image. Values used by IMOD
  		nxstart: 0, //Startin poin to sub image (not used in IMOD)
  		nystart: 0,
  		nzstart: 0,
  		mx: 0, //Grid size in X, Y, Z
  		my: 0,
  		mz: 0,
  		xlen: 0, //Cell size; pixel spacing = xlen/mx...
  		ylen: 0,
  		zlen: 0,
  		alpha: 0, //cell angles - ignored by IMOD
  		beta: 0,
  		gamma: 0,
  		mapc: 0, //map column
  		mapr: 0, //map row
  		maps: 0, //map section
  		amin: 0, //Minimum pixel value
  		amax: 0, //Maximum pixel value
  		amean: 0, //mean pixel value
  		ispg: 0, //space group numbe (ignored by IMOD0
  		next: 0, //number of bytes in extended header
  		creatid: 0, //is 0 
  		extra: null, 
  		nint: 0, // number of intergers or bytes per section
  		nreal: 0, // Number of reals per section
  		extra: null,
  		imodStamp: 0, //1146047817 = file created by IMOD
  		imodFlags: 0, //Bit flags
  		idtype: 0,
  		lens: 0,
  		nd1: 0,
  		nd2: 0,
  		vd1: 0,
  		vd2: 0,
  		tiltangles: null,
  		xorg: 0, //Orgin of the image
  		yorg: 0,
  		zorg: 0,
  		cmap: 0, //Contains "MAP "
  		stamp: 0, //Frist two bytes = 17 17 for bin-endian or 68 and 65 for littl-edian
  		rms: 0, //RMS deviation of densitites from mean density
  		nlabl: 0, //number of lables with useful data
  		data: null, //10 lables of 80 characters
  		min: Infinity,
  		max: -Infinity,
  		mean: 0,
  		space: null,
  		spaceorientation: null,
  		rasspaceorientation: null,
  		orientation: null,
  		normcosine: null
  	};		
  	
  	this.jumpTo(parseInt(0, 10));
  	// Reading the data. Names are the names used in C code.
  	MRI.nx = this.scan('sint');
  	MRI.ny = this.scan('sint');
  	MRI.nz = this.scan('sint');
  	MRI.mode = this.scan('sint');
  
  	// size of the image
  	var volsize = MRI.nx * MRI.ny * MRI.nz ;
  
  	// Read for the type of pixels
  	this.jumpTo(parseInt(1024, 10));
  	switch (MRI.mode) {
  	case 0:
  		MRI.data = this.scan('schar', volsize);
  		break;
  	case 1:
  		MRI.data = this.scan('sshort', volsize);
  		break;
  	case 2:
  		MRI.data = this.scan('float', volsize);
  		break;
  	case 3:
  		MRI.data = this.scan('uint', volsize);
  		break;
  	case 4:
  		MRI.data = this.scan('double', volsize);
  		break;
  	case 6:
  		MRI.data = this.scan('ushort', volsize);
  		break;
  	case 16:
  		MRI.data = this.scan('uchar', volsize);
  		break;
  
  	default:
  		throw new Error('Unsupported MRC data type: ' +MRI.mode);
  	}
  
  	this.jumpTo(parseInt(28, 10));
  
  	MRI.mx = this.scan('sint');
  	MRI.my = this.scan('sint');
  	MRI.mz = this.scan('sint');
  	
  	// pixel spacing = xlem/mx
  	MRI.xlen = this.scan('float');
  	MRI.ylen = this.scan('float');
  	MRI.zlen = this.scan('float');
  	MRI.alpha = this.scan('float');
  	MRI.beta = this.scan('float');
  	MRI.gamma = this.scan('float');
  	MRI.mapc = this.scan('sint');
  	MRI.mapr = this.scan('sint');
  	MRI.maps = this.scan('sint');
  	MRI.amin = this.scan('float');
  	MRI.amax = this.scan('float');
  	MRI.amean = this.scan('float');
  	MRI.ispeg = this.scan('sint');
  	MRI.next = this.scan('sint');
  	MRI.creatid = this.scan('short');
  	//Not sure what to do with the extra data, says 30 for size
  	MRI.nint = this.scan('short');
  	MRI.nreal = this.scan('short');
  	//Need to figure out extra data, 20 for size
  	MRI.imodStamp = this.scan('sint');
  	MRI.imodFLags = this.scan('sint');
  	MRI.idtype = this.scan('short');
  	MRI.lens = this.scan('short');
  	MRI.nd1 = this.scan('short');
  	MRI.nd2 = this.scan('short');
  	MRI.vd1 = this.scan('short');
  	MRI.vd2 = this.scan('short');
  	
  	// loop this around (6 different ones)
  	MRI.tiltangles = this.scan('float',6);
  
  	this.jumpTo(parseInt(196, 10));
  
  	MRI.xorg = this.scan('float');
  	MRI.yorg = this.scan('float');
  	MRI.zorg = this.scan('float');
  	
  	this.jumpTo(parseInt(216, 10));
  
  	MRI.rms = this.scan('float');
  	
  	MRI.nlabl = this.scan('sint');
  
  	// 10 of 80 characters
  	MRI.lables = this.scan('schar', 10);
  
  	//Dealing with extended header
  	if (MRI.next != 0) {
  		this.jumpTo(parseInt(MRI.next+1024, 10))
  		switch (MRI.mode) {
  		case 0:
  			MRI.data = this.scan('schar', volsize);
  			break;
  		case 1:
  			MRI.data = this.scan('sshort', volsize);
  			break;
  		case 2:
  			MRI.data = this.scan('float', volsize);
  			break;
  		case 3:
  			MRI.data = this.scan('uint', volsize);
  			break;
  		case 4:
  			MRI.data = this.scan('double', volsize);
  			break;
  		case 6:
  			MRI.data = this.scan('ushort', volsize);
  			break;
  		case 16:
  			MRI.data = this.scan('uchar', volsize);
  			break;
  
  		default:
  			throw new Error('Unsupported MRC data type: ' +MRI.mode);
  		};
  	}
  		
  
  	// minimum, maximum, mean intensities
  	// centered on the mean for best viewing ability
  	if (MRI.amean - (MRI.amax - MRI.amean) < 0) {	
  		MRI.min = MRI.amin;
  		MRI.max = MRI.amean + (MRI.amean - MRI.amin);
  	}
  	else {
  		MRI.min = MRI.amean - (MRI.amax - MRI.amean);
  		MRI.max = MRI.amax
  	}
  
  	return MRI;
  
  };
  
  // export symbols (required fro advanced compilatoin)
  goog.exportSymbol('X.parserMRC', X.parserMRC);
  goog.exportSymbol('X.parserMRC.prototype.parse', X.parserMRC.prototype.parse);
  
  
  