API Docs for: 1.4.0
Show:

File: src\utils\Log.ts


/**
* 
* @module Kiwi
* @submodule Utils.
*
*/
module Kiwi.Utils {

	/**
	* A utilty class used to add management functionality to common console methods. 
	* You can use this class by either creating a new instance, or using the instance at the namespace 'Kiwi.Log'.
	* 
	* log/error/warn methods contained on this class function just like their 'console' equivalents except that:
	* - You can assign a tag to message by adding a '#' symbol to the front of a parameter. Example: this.log('Hi', '#welcome'); 
	* - Messages can have multiple tags. Example: this.log('Hi', '#welcome', '#greeting');
	* - Messages are recorded (by default) and you can then search through any messages saved.
	*
	* You can use the 'show' commands to search through recordings and find specific messages. 
	*
	* 
	* @class Log
	* @namespace Kiwi.Utils
	* @constructor
	* @param [params] {Object}
	*   @param [options.recording=true] {Boolean} If the logs should be recorded.
	*   @param [options.display=true] {Boolean} If the logs should be displayed or not.
	*   @param [options.enabled=true] {Boolean} If the Logger is enabled at all.
	*   @param [options.maxRecordings=Infinity] {Number} The maximum number of recordings to have at a single time.
	*/
	export class Log {

		constructor(params: any= {}) {
			this.setDefaultsFromParams(params);
		}

		/**
		* Sets the log properties based on a object passed. 
		* This method is used to set the properties on the Log based on 
		* gameoptions passed at game creation.
		* 
		* @method setDefaultsFromParams
		* @param [params] {Object}
		*   @param [options.recording=true] {Boolean} If the logs should be recorded.
		*   @param [options.display=true] {Boolean} If the logs should be displayed or not.
		*   @param [options.enabled=true] {Boolean} If the Logger is enabled at all.
		*   @param [options.maxRecordings=Infinity] {Number} The maximum number of recordings to have at a single time.
		* @public
		*/
		public setDefaultsFromParams(params: any= {}) {

			if (!Kiwi.Utils.Common.isUndefined(params.enabled)) {
				this.enabled = params.enabled;
			}

			if (!Kiwi.Utils.Common.isUndefined(params.recording)) {
				this.recording = params.recording;
			}

			if (!Kiwi.Utils.Common.isUndefined(params.display)) {
				this.display = params.display;
			}

			if (!Kiwi.Utils.Common.isUndefined(params.maxRecordings)) {
				this.maxRecordings = params.maxRecordings;
            }

            if (Kiwi.Utils.Common.isArray(params.tagFilters)) {
                this.tagFilters = params.tagFilters;
            }

		}

		/**
		* If the log, warn, or error messages should function at all.
		* When set to false messages won't display or be recorded.
		*
		* @property enabled
		* @type Boolean
		* @default true 
		* @public
		*/
		public enabled: boolean = true;
		
		/**
		* If messages should be recorded or not.
		*
		* @property record
		* @type Boolean
		* @default true 
		* @public
		*/
		public recording: boolean = true;
		
		/**
		* If the log, warn, and error methods should display when executed or not.
		* You may want to set this to 'false' when releasing a game.
		*
		* @property display
		* @type Boolean
		* @default true 
		* @public
		*/
        public display: boolean = true;

        /**
        * A list of tags which any message recorded needs to match in-order to be displayed.
        * This helps when debugging systems with lots of messages, without removing every log. 
        * 
        * @property tagFilters
        * @type Array
        * @since 1.3.0
        * @public
        */
        public tagFilters: string[] = [];
		
		/**
		* The maximum number of recordings to be kept at once.
		*
		* @property maxRecordings
		* @type Number
		* @default Infinity 
		* @public
		*/
		public maxRecordings: number = Infinity;
		
		/**
		* A list containing all messages recorded.
		*
		* @property recordings
		* @type Array
		* @private 
		*/
		private recordings: any[] = [];
		
		/**
		* The time (in milliseconds) of the last recording.
		*
		* @property lastMessageTime
		* @type Number
		* @readOnly
		* @public
		*/
		public get lastMessageTime():number {
			if (this.recordings.length > 0) {
				return this.recordings[this.recordings.length - 1].time;
			}
			return 0;
		}
		
		/**
		* The number of recordings that have been saved.
		* Same as the recordings length, and won't go above the 'maxRecordings'.
		*
		* @property numRecordings
		* @type Number
		* @readOnly
		* @public
		*/
		public get numRecordings():number {
			return this.recordings.length;
		}


		/**
		* Saves a message to the 'recordings' array.
		* That message can then be retrieved later using the 'show' methods.
		*
		* @method recordMessage
		* @param message {String}
		* @param [tags=[]] {String}
		* @param [logMethod=console.log] {String} 
		* @public
		*/
		public record(messages: string[], tags:string[]=[], logMethod:any=console.log) {

			if (this.recording) {

				var recording = {
					messages: messages,
					time: Date.now(),
					tags: tags,
					logMethod: logMethod
				};

				if (this.recordings.push(recording) > this.maxRecordings) {
					this.recordings.shift();
				} 

			}

		}
		
		/**
		* Removes recordings from the list. Goes from the oldest to newest. 
		* By not passing any parameters, the entire log will be cleared.
		*
		* @method clearRecordings
		* @param [start=0] {Number} 
		* @param [end] {Number} 
		* @public
		*/
		public clearRecordings(start: number=0, end: number=this.recordings.length) {

			this.recordings.splice(start, end);

		}
		
		/**
		* Executes a particular array of messages using a method passed.
		* Takes into account the 'display' property before executing. 
		* 
		* @method _execute
		* @param method {Any} The method that should be used to log the messages. Generally a console method.
		* @param context {Any} The context that the method should be executed in. Generally set to the console. 
		* @param messages {Array} 
		* @param [force=false] {Array}  
		* @private
		*/
		private _execute(method:any, context: any, messages:string[], force:boolean=false) {

			if (this.display || force) {
				method.apply(context, messages);
			}

		}

		/**
		* Accepts an array of strings and returns a new array consisting of all elements considered as a tag.
		* 
		* @method getTagsFromArray
		* @param strings {Array} 
		* @return {Array} Elements of the array considered as tags
		* @public
		*/
        public getTagsFromArray(array: string[]) {

            var i = 0,
                tags = [];

            while (i < array.length) {
                if (typeof array[i] === "string") {
                    if (array[i].charAt(0) === "#") {
                        tags.push(array[i]);
                    }
                }
                i++;
            }

            return tags;

        }

        /**
        * Returns true if the all of the tags passed also occur in the tag filters. 
        * This is used to filter out messages by their tags.
        *
        * @method _filterTags
        * @param tags {Array} A list of tags, which need to occur in the tag filters
        * @param [tagFilters=this.tagFilters] {Array} A list of tags. Tags need to 
        * @return {Boolean} Tags match the tag filters, and so if the message would be allowed to execute.
        * @since 1.3.0
        * @private
        */
        private _filterTags(tags: string[], tagFilters:string[] = this.tagFilters): boolean {

            //No filters, then allow
            if (tagFilters.length === 0) {
                return true;
            }

            if (tags.length == 0) {
                return false;
            }

            var i = 0;
            while (i < tags.length) {

                //If the tag does not appear in the filter list 
                if (tagFilters.indexOf(tags[i]) === -1) {
                    return false;
                }

                i++;
            }

            return true;
        }
		
		/**
		* Logs a message using the 'console.log' method.
		* Arguments starting with a '#' symbol are given that value as a tag.
		* 
		* @method log
		* @param [..args] {Any} The data you would like to log.
		* @public
		*/
		public log(...args:any[]) {

			if (!this.enabled) {
				return;
			}

            var tags = this.getTagsFromArray(args);
            this.record(args, tags, console.log);

            if (this._filterTags(tags)) {
                this._execute(console.log, console, args);
            }

		}
		

		/**
		* Logs a message using the 'console.warn' method.
		* Arguments starting with a '#' symbol are given that value as a tag.
		* 
		* @method warn
		* @param [..args] {Any} The data you would like to log.
		* @public
		*/
		public warn(...args: any[]) {

			if (!this.enabled) {
				return;
			}

            var tags = this.getTagsFromArray(args);
            this.record(args, tags, console.warn);

            if (this._filterTags(tags)) {
                this._execute(console.warn, console, args);
            }

		}
		
		/**
		* Logs a message using the 'console.error' method.
		* Arguments starting with a '#' symbol are given that value as a tag.
		*
		* @method error
		* @param [..args] {Any} The data you would like to log.
		* @public
		*/
		public error(...args: any[]) {

			if (!this.enabled) {
				return;
			}

            var tags = this.getTagsFromArray(args);
            this.record(args, tags, console.error);

            if (this._filterTags(tags)) {
                this._execute(console.error, console, args);
            }

		}


		/**
		* Method that displays a particular recording passed.
		*
		* @method _show
		* @param recording {Object}
		* @param tags {Array}
		* @return {Boolean} If the recording was displayed or not.
		* @private
		*/
		private _show( recording, tags:string[] ) {

			if (!recording.logMethod) {
				return false;
			}

			//Check that the tags match
			var n = tags.length;
			while( n-- ) {

				if ( recording.tags.indexOf( tags[ n ] ) == -1 ) {
					return false;
				}

			}

			this._execute(recording.logMethod, console, recording.messages, true );
			return true;

		}


		/**
		* Displays the last recording matching the tags passed.
        * Ignores the tag filters.
		* 
		* @method showLast
		* @param [...args] {Any} Any tags that the recordings must have.
		* @public
		*/
		public showLast(...args:any[]) {
			var i = this.recordings.length;
			
			while(i--) {
				if (this._show(this.recordings[i], args)) {
					return;
				}
			}
		}


		/**
		* Displays all recordings.
        * Ignores the tag filters.
		* 
		* @method showAll
		* @param [...args] {Any} Any tags that the recordings must have.
		* @public
		*/
		public showAll(...args: any[]) {
			for (var i = 0; i < this.recordings.length; i++) {
				this._show(this.recordings[i], args );
			}
		}


		/**
		* Displays all logs recorded.
        * Ignores the tag filters.
		* 
		* @method showLogs
		* @param [...args] {Any} Any tags that the recordings must have.
		* @public
		*/
		public showLogs(...args: any[]) {
			for (var i = 0; i < this.recordings.length; i++) {
				if (this.recordings[i].logMethod === console.log) {
					this._show(this.recordings[i], args);
				}
			}
		}


		/**
		* Displays all errors recorded.
        * Ignores the tag filters.
		* 
		* @method showErrors
		* @param [...args] {Any} Any tags that the recordings must have.
		* @public
		*/
		public showErrors(...args: any[]) {
			for (var i = 0; i < this.recordings.length; i++) {
				if (this.recordings[i].logMethod === console.error) {
					this._show(this.recordings[i], args);
				}
			}
		}


		/**
		* Displays all warnings recorded.
        * Ignores the tag filters.
		*
		* @method showWarnings
		* @param [...args] {Any} Any tags that the recordings must have.
		* @public
		*/
		public showWarnings(...args: any[]) {
			for (var i = 0; i < this.recordings.length; i++) {
				if (this.recordings[i].logMethod === console.warn) {
					this._show(this.recordings[i], args);
				}
			}
		}

		/**
		* Displays a series of recordings within a time period passed. 
		* Time recorded is in milliseconds.
        * Ignores the tag filters.
		* 
		* @method showTimePeriod
		* @param [start=0] {Number}
		* @param [end=Infinity] {Number}
		* @param [tags] {Array} An tags that the recordings must have.
		* @public
		*/
		public showTimePeriod(start: number=0, end: number=Infinity, tags:string[]=[]) {

			var recording;

			for (var i = 0; i < this.recordings.length; i++) {

				recording = this.recordings[i];
				if (start < recording.time && end > recording.time) {

					this._show(recording, tags);

				}
			}

        }

        /**
        * Adds a tag to the list of tag filters.
        * Any messages that do not have the tags in the tagFilters list will not be displayed.
        * 
        * @method addFilter
		* @param [...args] {Any} Tags to add to the filters list.
        * @since 1.3.0
        * @public
        */
        public addFilter(...args: any[]) {
            this.tagFilters = this.tagFilters.concat(args);
        }

        /**
        * Removes a tag to the list of tag filters.
        * Any messages that do not have the tags in the tagFilters list will not be displayed.
        * 
        * @method removeFilter
		* @param [...args] {Any} Tags to be remove from the filters list.
        * @since 1.3.0
        * @public
        */
        public removeFilter(...args: any[]) {

            var i = 0,
                index;

            while (i < args.length) {

                index = this.tagFilters.indexOf(args[i]);
                if (index !== -1) {
                    this.tagFilters.splice(index, 1);
                }
                
                i++;
            }

        }

	}

}