Source: develop/debug.js

/**
 * Logger.
 *
 * @module stb/develop/debug
 * @author Stanislav Kalashnik <sk@infomir.eu>
 * @license GNU GENERAL PUBLIC LICENSE Version 3
 */

'use strict';

/* eslint new-cap: 0 */

var host   = require('../app').data.host,
	config = require('../../../../config/logger'),
	util   = require('util'),
	buffer = [],
	/**
	 * Storage for timers (time, timeEnd).
	 */
	timeCounters = {},
	socket;


// enable colors in console
require('tty-colors');


(function connect () {
	if ( !config.active || !host ) {
		return;
	}

	socket = new WebSocket('ws://' + location.hostname + ':' + config.port);

	socket.onclose = function () {
		setTimeout(function () {
			connect();
		}, 5000);
	};
})();


/**
 * Wrapper to dump message locally and remotely.
 *
 * @param {string} message data to output and send
 */
function log ( message ) {
	gSTB.Debug(message);
	buffer.push(message);
	if ( socket && socket.readyState === socket.OPEN ) {
		socket.send(JSON.stringify(buffer));
		buffer = [];
	}
}


/**
 * Global object to output logs
 * @namespace
 * @global
 */
module.exports = window.debug = {

	/**
	 * Check condition and warn if not match.
	 *
	 * @param {boolean} condition should be true if okay
	 * @param {string} title description of the problem
	 */
	assert: function ( condition, title ) {
		if ( !condition ) {
			if ( host ) {
				log(('Assertion failed: ' + title).red);
			} else {
				console.assert(condition, title);
			}
		}
	},


	/**
	 * Print a plain colored string.
	 *
	 * @param {*} message data to output
	 * @param {string} [color='black'] colour to set
	 */
	log: function ( message, color ) {
		message = (message + '') || '(empty message)';
		if ( host ) {
			log(message[color || 'white']);
		} else {
			console.log('%c%s', 'color:' + (color || 'black'), message);
		}
	},


	/**
	 * Print the given var with caption.
	 *
	 * @param {*} data data to output
	 * @param {string} [title] optional caption
	 */
	info: function ( data, title ) {
		var type = Object.prototype.toString.call(data).match(/\s([a-zA-Z]+)/)[1].toLowerCase(),
			args;

		if ( host ) {
			// prepare
			if ( data instanceof Object || Array.isArray(data) ) {
				// complex object
				data = data.nodeName ? data.outerHTML : JSON.stringify(data, null, 4);
			}
			// combine all together and print result
			log((type === 'error' ? type.red : type.green) + '\t' + (title ? title.bold + ':\t'.green : '') + data);
		} else {
			args = ['color:' + (type === 'error' ? 'red' : 'green'), type];
			if ( title ) {
				args.unshift('%c%s\t%c%s\t');
				args.push('color:grey');
				args.push(title);
			} else {
				args.unshift('%c%s\t');
			}
			args.push(data);
			// output
			console.log.apply(console, args);
		}
	},


	/**
	 * Print the given complex var with level restriction.
	 *
	 * @param {*} data data to output
	 * @param {number} [depth=0] amount of sub-levels to print
	 */
	inspect: function ( data, depth ) {
		if ( host ) {
			log('inspect:\n' + util.inspect(data, {depth: depth || 0, colors: true}));
		} else {
			console.log(data);
		}
	},


	/**
	 * Print the given event object in some special way.
	 *
	 * @param {Event} data event object
	 */
	event: function ( data ) {
		var type  = data.type.toUpperCase(),
			color = type === 'ERROR' ? 'red' : 'green',
			text  = ('Event ' + type[color]).bold;

		if ( host ) {
			switch ( type ) {
				case 'KEYDOWN':
					text = text +
					'\tctrl' [data.ctrlKey  ? 'green' : 'grey'] +
					' alt'  [data.altKey   ? 'green' : 'grey'] +
					' shift'[data.shiftKey ? 'green' : 'grey'] +
					'\t' + data.keyCode + '\t' + data.code + '\t' + (data.keyIdentifier || '').green;
					break;
				case 'KEYPRESS':
					text = text +
					'\tctrl' [data.ctrlKey  ? 'green' : 'grey'] +
					' alt'  [data.altKey   ? 'green' : 'grey'] +
					' shift'[data.shiftKey ? 'green' : 'grey'] +
					'\t' + data.keyCode + '\t' + (data.keyIdentifier || '').green + '\t' + String.fromCharCode(data.keyCode);
					break;
				case 'MOUSEMOVE':
					text = text +
					'\tctrl' [data.ctrlKey  ? 'green' : 'grey'] +
					' alt'  [data.altKey   ? 'green' : 'grey'] +
					' shift'[data.shiftKey ? 'green' : 'grey'] +
					'\t' + data.x + ':' + data.y;
					break;
				case 'CLICK':
					text = text +
					'\tctrl' [data.ctrlKey  ? 'green' : 'grey'] +
					' alt'  [data.altKey   ? 'green' : 'grey'] +
					' shift'[data.shiftKey ? 'green' : 'grey'] +
					'\t' + data.x + ':' + data.y;
					break;
				case 'ERROR':
					text = text +
						'\t' + data.filename +
						' (' + data.lineno + ':' + data.colno + ')' +
						' ' + data.message;
					break;
			}
			log(text);
		} else {
			switch ( type ) {
				case 'KEYDOWN':
				case 'KEYPRESS':
					console.log('%o\t%c%s %c%s %c%s %c%s %c%s\t%s\t%c%s', data, 'color:' + color + ';font-weight:bold', type,
						'color:' + (data.ctrlKey  ? 'green' : 'lightgrey'), 'ctrl',
						'color:' + (data.altKey   ? 'green' : 'lightgrey'), 'alt',
						'color:' + (data.shiftKey ? 'green' : 'lightgrey'), 'shift',
						'color:black', data.keyCode, data.code || '', 'color:green', data.keyIdentifier
					);
					break;
				default:
					console.log('%o\t%c%s', data, 'color:' + color + ';font-weight:bold', type);
			}
		}
	},


	/**
	 * Use to do some development-specific actions which are removed in release mode.
	 *
	 * @param {function} cb callback to execute
	 *
	 * @example
	 * debug.stub(function () {
	 *     alert('This is visible only in debug mode!');
	 * });
	 * // it's also possible to use simple expression:
	 * // link the current scope var with global
	 * // useful for dev only
	 * debug.stub(window.app = this);
	 */
	stub: function ( cb ) {
		if ( typeof cb === 'function' ) {
			cb();
		}
	},


	/**
	 * Start specific timer.
	 * Use to calculate time of some actions.
	 *
	 * @param {string} name timer name
	 *
	 * @example
	 * debug.time('function1');
	 * // some processing...
	 * debug.timeEnd('function1');
	 * // print time execution, like 'function1: 934ms'
	 */
	time: function ( name ) {
		var time, key;

		if ( host ) {
			if ( !name ) {
				return;
			}

			time = new Date().getTime();

			key = 'KEY:' + name;

			timeCounters[key] = time;
		} else {
			console.time(name);
		}
	},


	/**
	 * End specific timer.
	 * Use to calculate time of some actions.
	 *
	 * @param {string} name timer name
	 *
	 * @example
	 * debug.time('function1');
	 * // some processing...
	 * debug.timeEnd('function1');
	 * // print time execution, like 'function1: 934ms'
	 */
	timeEnd: function ( name ) {
		var key, diff, timeCounter;

		if ( host ) {
			if ( !name ) {
				return;
			}

			key = 'KEY:' + name;
			timeCounter = timeCounters[key];

			if ( timeCounter ) {
				diff = +new Date() - timeCounter;
				timeCounters[key] = null;
				diff += 'ms';
				log(name + ':\t' + diff.bgBlue);
			} else {
				throw 'no started timer for "' + name + '"';
			}
		} else {
			console.timeEnd(name);
		}
	}

};