/*______________
|       ______  |   U I Z E     J A V A S C R I P T     A P I
|     /      /  |   -----------------------------------------
|    /    O /   |    MODULE : Uize.serialize Static Method (version 1.0.0)
|   /    / /    |    AUTHOR : Chris van Rensburg (http://www.tomkidding.com)
|  /    / /  /| |    ONLINE : http://www.tomkidding.com/uize/uize-js-api
| /____/ /__/_| | COPYRIGHT : (c)2004-2006 Chris van Rensburg
|          /___ |   LICENSE : Distributed under the terms of the GNU General Public License
|_______________|             http://www.gnu.org/licenses/gpl.txt
*/

/*
	DESCRIPTION
		A method to allow objects to be turned into a programming language representation

	TO DO
		- optimizations
			- don't calculate maxKeyLength if padKeys is set to false
*/

/*ScruncherSettings Mappings="" LineCompacting="TRUE"*/

(function () {
	if (typeof Uize == 'undefined') Uize = {};

	/*** Variables for Scruncher Optimization ***/
		var _string = 'string';

	/*** Global Variables ***/
		var _keyPaddingElements = [];
		for (var _charNo = 0; _charNo < 255; _charNo++)
			_keyPaddingElements.push (' ')
		;
		var
			_keyPadding = _keyPaddingElements.join (''),
			_reservedWordsMap = {
				'break':1, 'case':1, 'catch':1, 'continue':1, 'const':1, 'debugger':1, 'default':1, 'delete':1, 'do':1, 'else':1, 'export':1, 'false':1, 'finally':1, 'for':1, 'function':1, 'if':1, 'import':1, 'in':1, 'instanceof':1, 'new':1, 'null':1, 'return':1, 'switch':1, 'this':1, 'throw':1, 'true':1, 'try':1, 'typeof':1, 'var':1, 'void':1, 'while':1, 'with':1
				/* NOTES:
					- future reserved words:
						- JavaScript 2.0
							as, class, extends, interface, is, namespace, package, private, public, super, use
						- future use unknown
							abstract, enum, final, goto, implements, native, protected, static, synchronized, throws, transient, volatile
					- no longer reserved
						boolean, byte, char, double, float, int, long, short
				*/
			}
		;

	Uize.serialize = function (_params) {
		var
			_indentChars = typeof _params.indentChars == _string ? _params.indentChars : '  ',
			_linebreakChars = typeof _params.linebreakChars == _string ? _params.linebreakChars : '\n',
			_sortProperties = _params.sortProperties === true,
			_padKeys = _params.padKeys === true,
			_keyDelimiter = typeof _params.keyDelimiter == _string ? _params.keyDelimiter : ':',
			_keyAlign = typeof _params.keyAlign == _string ? _params.keyAlign : 'left',
			_whenToQuoteKeys = typeof _params.whenToQuoteKeys == _string ? _params.whenToQuoteKeys : 'auto'
				/* auto | auto all | always */
		;
		function _getPadding (_paddingAmount) {return _keyPadding.substr (0,_paddingAmount)}
		function _getQuotedStr (_string,_quoteChar) {
			return (
				_quoteChar +
				_string.replace (
					/\\/g,'\\\\'
				).replace (
					/\n/g,'\\n'
				).replace (
					/\r/g,'\\r'
				).replace (
					new RegExp (_quoteChar,'g'),'\\' + _quoteChar
				) +
				_quoteChar
			);
		}
		function _getSerializedItemLines (_item) {
			var _serialized = [];
			if (_item == null) {
				_serialized [0] = 'null';
			} else if (typeof _item == _string) {
				_serialized [0] = _getQuotedStr (_item,"'");
			} else if (typeof _item == 'number' || typeof _item == 'boolean') {
				_serialized [0] = _item;
			} else if (typeof _item == 'object') {
				var
					_isArray = _item instanceof Array || (_item && typeof _item.splice == 'function'),
					_openerChar = _isArray ? '[' : '{',
					_closerChar = _isArray ? ']' : '}',
					_maxKeyLength = 0,
					_keys = [],
					_displayKeys = []
				;
				if (_isArray) {
					for (var _memberNo = 0; _memberNo < _item.length; _memberNo++)
						_keys [_memberNo] = _memberNo
					;
				} else {
					function _mustQuoteKey (_key) {
						return _key.search (/\W/) > -1 || _reservedWordsMap [_key];
					}
					for (var _memberName in _item)
						_keys.push (_memberName)
					;
					if (_sortProperties) _keys.sort ();
					var _quoteAllKeys = _whenToQuoteKeys == 'always';
					if (!_quoteAllKeys && _whenToQuoteKeys == 'auto all') {
						for (var _keyNo = 0; _keyNo < _keys.length && !_quoteAllKeys; _keyNo++)
							_quoteAllKeys = _quoteAllKeys || _mustQuoteKey (_keys [_keyNo])
						;
					}
					for (var _keyNo = 0; _keyNo < _keys.length; _keyNo++) {
						var _key = _keys [_keyNo];
						_maxKeyLength = Math.max (
							_maxKeyLength,
							(
								_displayKeys [_keyNo] = (_quoteAllKeys || _mustQuoteKey (_key))
									? _getQuotedStr (_key,"'")
									: _key
							).length
						);
					}
				}
				if (_keys.length) {
					_serialized.push  (_openerChar);
					var _keysLength = _keys.length;
					for (var _keyNo = 0; _keyNo < _keysLength; _keyNo++) {
						var
							_key = _keys [_keyNo],
							_startPrefix = '',
							_serializedMember = _getSerializedItemLines (_item [_key])
						;
						if (!_isArray) {
							var
								_displayKey = _displayKeys [_keyNo],
								_padding = _maxKeyLength - _displayKey.length,
								_leftPadding = Math.round ({left:0,center:0.5,right:1} [_keyAlign] * _padding),
								_rightPadding = _padding - _leftPadding
							;
							_startPrefix = _getPadding (_padKeys ? _leftPadding : 0) + _displayKey + _getPadding (_padKeys ? _rightPadding : 0) + _keyDelimiter;
						}
						var _serializedMemberLength = _serializedMember.length;
						for (var _lineNo = 0; _lineNo < _serializedMemberLength; _lineNo++)
							_serialized.push  (_indentChars + (_lineNo ? '' : _startPrefix) + _serializedMember [_lineNo])
						;
						if (_keyNo < _keysLength - 1) _serialized [_serialized.length - 1] += ',';
					}
					_serialized.push  (_closerChar);
				} else {
					_serialized.push  (_openerChar + _closerChar);
				}
			}
			return _serialized;
		}
		return _getSerializedItemLines (_params.item).join (_linebreakChars);
	};
}) ();


