API Docs for: 2.0.0

src/node-filebuffer.js

// SAGE2 is available for use under the SAGE2 Software License
//
// University of Illinois at Chicago's Electronic Visualization Laboratory (EVL)
// and University of Hawai'i at Manoa's Laboratory for Advanced Visualization and
// Applications (LAVA)
//
// See full text, terms and conditions in the LICENSE.txt included file
//
// Copyright (c) 2014

/**
 * @module filebuffer
 */

"use strict";

var fs        = require('fs');
var path      = require('path');
var sageutils = require('../src/node-utils');    // provides utility functions

/* global  */
if (!String.prototype.splice) {

	/**
     * The splice() method changes the content of a string by removing a range of
     * characters and/or adding new characters.
     *
     * @this {String}
     * @param {number} start Index at which to start changing the string.
     * @param {number} delCount An integer indicating the number of old chars to remove.
     * @param {string} newSubStr The String that is spliced in.
     * @return {string} A new string with the spliced substring.
     */
	String.prototype.splice = function(start, delCount, newSubStr) {
		newSubStr = newSubStr || "";
		return this.slice(0, start) + newSubStr + this.slice(start + Math.abs(delCount));
	};
}





function MDManager() {
}

function getEntryValue(data, entryStr, delim) {
	var position = data.indexOf(entryStr);
	var entry = null;
	var tempStr;
	var tempPos = 0;
	if (position > -1) {
		position = position + entryStr.length;
		tempStr = data.slice(position);
		tempPos = tempStr.indexOf(delim);
		if (tempPos > -1) {
			entry = tempStr.slice(0, tempPos);
			tempPos = tempPos + delim.length;
		} else {
			entry = tempStr;
			tempPos = 0;
		}
		position = position + tempPos;
	} else {
		position = 0;
	}
	return {value: entry, end: position};
}

MDManager.prototype.parse = function(data) {
	var owner = getEntryValue(data, ' _Owner:_ ', '  \n').value;
	var color = getEntryValue(data, ' _Color:_ ', '  \n').value;
	var temp = getEntryValue(data, ' _Created On:_ ', '  \n');
	var createdOn = parseInt(temp.value, 10);
	var texIdx = temp.end;
	var text = data.slice(texIdx);
	return {text: text, owner: owner, createdOn: createdOn, color: color};
};

function FileBuffer() {
	this.buffers = {};
	this.files = {};
	this.mdManager = new MDManager();
}

function CustomBuffer(data) {
	this.changeCount = 0;
	this.appId = data.appId;
	this.owner = data.owner;
	this.createdOn = data.createdOn;
	this.color = data.color;
	this.str = "";
	this.cursorTable = {};
	this.insertMode = false;
}

CustomBuffer.prototype.insertStr = function(text, user_id) {
	if (user_id !== undefined && user_id !== null) {
		var caret = this.cursorTable[user_id] || 0;
	}
	var replace = this.insertMode ? text.length : 0;
	this.str = this.str.splice(caret, replace, text);
	caret = caret + text.length;
	this.changeCount = this.changeCount + text.length;
	var result = {index: caret - text.length, offset: text.length, deleteCount: replace, data: text, user_id: user_id};
	this.cursorTable[user_id] = caret;
	return result;
};

CustomBuffer.prototype.resetChange = function() {
	this.changeCount = 0;
};

CustomBuffer.prototype.getData = function() {
	var data = {
		owner: this.owner,
		createdOn: this.createdOn,
		text: this.str,
		color: this.color
	};
	return data;
};

CustomBuffer.prototype.insertChar = function(code, printable, user_id) {
	var caret = this.cursorTable[user_id];
	var result = {index: caret, offset: 0, deleteCount: 0, data: null, user_id: user_id};
	if (printable) {
		//Changing \r to \n
		//Need to make this flexible enough to handle \r, \n, or \r\n
		var char = (code === 13) ? '\n' : String.fromCharCode(code);
		var replace = this.insertMode ? 1 : 0;
		this.str = this.str.splice(caret, replace, char);
		caret = caret + 1;
		this.changeCount = this.changeCount + 1;
		result.offset = 1;
		result.data = char;
		result.deleteCount = replace;
	} else {
		switch (code) {
			case 35:// End
				if (caret < this.str.length) {
					var lineEnd = this.str.indexOf('\n', caret) + 1; // If found, +1 will point to next char
					if (lineEnd === 0) {
						lineEnd = this.str.length;
					}
					result.offset = lineEnd - caret;
					caret = lineEnd;
				}
				break;
			case 36:// Home

				if (caret > 0) {
					var lineBegin = this.str.slice(0, caret).lastIndexOf('\n') + 1;
					result.offset = lineBegin - caret;
					caret = lineBegin;
				}
				break;
			case 37:// left

				if (caret > 0) {
					caret = caret - 1;
					result.offset = -1;
				}
				break;
			case 39:// right

				if (caret < this.str.length) {
					caret = caret + 1;
					result.offset = 1;
				}
				break;
			case 8:// backspace

				if (caret > 0) {
					this.str = this.str.splice(caret - 1, 1);
					caret = caret - 1;
					this.changeCount = this.changeCount + 1;
					result.offset = -1;
					result.deleteCount = 1;
				}
				break;
			case 46:// delete

				if (caret < this.str.length) {
					this.str = this.str.splice(caret, 1);
					this.changeCount = this.changeCount + 1;
					result.deleteCount = 1;
				}
				break;
			case 45:
				this.insertMode = !this.insertMode;
				break;
		}
	}
	this.cursorTable[user_id] = caret;
	return result;
};


CustomBuffer.prototype.updateCursorPosition = function(data) {
	this.cursorTable[data.user_id] = data.cursorPosition;
};

FileBuffer.prototype.requestBuffer = function(data) {
	if ((data.appId.toString() in this.buffers) === false) {
		var buf = new CustomBuffer(data);
		if (data.content !== undefined && data.content !== null) {
			var text = data.content.split('\r\n').join('\n');
			text = this.parse(text).text;
			buf.insertStr(text);
		}
		this.buffers[data.appId] = buf;
	}
};

FileBuffer.prototype.editCredentialsForBuffer = function(data) {
	if ((data.appId.toString() in this.buffers) === true) {
		var buf = this.buffers[data.appId];
		buf.owner = data.owner;
		buf.createdOn = data.createdOn;
	}
};

FileBuffer.prototype.closeFileBuffer = function(appId) {
	if (this.buffers.hasOwnProperty(appId)) {
		var buf = this.buffers[appId];
		if (buf.changeCount > 0) {
			this.writeToFile(appId);
		}
		delete this.buffers[appId];
		delete this.files[appId];
	}
};

FileBuffer.prototype.hasFileBufferForApp = function(appId) {
	return (appId.toString() in this.buffers);
};

FileBuffer.prototype.associateFile = function(data) {
	var fileName = data.fileName;
	var fileDir = data.fileDir;
	// check and create the folder if needed
	if (!sageutils.folderExists(fileDir)) {
		sageutils.mkdirParent(fileDir);
	}

	// finally, build the full path
	var fullPath = path.join(fileDir, fileName);

	this.files[data.appId] = fullPath;
	sageutils.log("SAGE2", "File", fileName, "attached to buffer of", data.appName);
};

FileBuffer.prototype.writeToFile = function(appId) {
	if (this.buffers.hasOwnProperty(appId) && this.files.hasOwnProperty(appId)) {
		var buffer = this.buffers[appId];
		var fileName = this.files[appId];
		var bufData = buffer.getData();

		/*var prefix = " _Owner:_ " + bufData.owner + "  \n"
			+ " _Color:_ " + bufData.color + "  \n"
			+ " _Created On:_ " + bufData.createdOn + "  \n";
		*/

		var output = bufData.text.split('\n').join('\r\n');
		fs.writeFile(fileName, output, function(err) {
			if (err) {
				return console.log(err);
			}
			buffer.resetChange();
		});
	}
};

FileBuffer.prototype.insertChar = function(data) {
	if (this.buffers.hasOwnProperty(data.appId)) {
		var buffer = this.buffers[data.appId];
		var update = buffer.insertChar(data.code, data.printable, data.user_id);
		if (buffer.changeCount > 15) {
			this.writeToFile(data.appId);
		}
		return update;
	}
};

FileBuffer.prototype.insertStr = function(data) {
	if (this.buffers.hasOwnProperty(data.appId)) {
		var buffer = this.buffers[data.appId];
		var text = data.text.split('\r\n').join('\n');
		text = this.parse(text).text;
		var update = buffer.insertStr(text, data.user_id);
		if (buffer.changeCount > 15) {
			this.writeToFile(data.appId);
		}
		return update;
	}
};

FileBuffer.prototype.parse = function(data) {
	try {
		if (typeof data !== 'string') {
			data = data.toString('utf8');
		}
		var parsedFileData = this.mdManager.parse(data);
		return parsedFileData;
	} catch (e) {
		console.log("Error :->", e);
	}
};

FileBuffer.prototype.updateFileBufferCursorPosition = function(data) {
	if (this.buffers.hasOwnProperty(data.appId)) {
		var buffer = this.buffers[data.appId];
		buffer.updateCursorPosition(data);
	}
};



module.exports = FileBuffer;