<?php
/**
* @version	$Id: json_helper.php 14628 2011-10-04 09:36:30Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

	defined('FULL_PATH') or die('restricted access!');

	class JSONHelper extends kHelper {

//		var $match = Array ('\\', "\n", "\t", "\r", "\b", "\f", '"');
//		var $replace = Array ('\\\\', '\\n', '\\t', '\\r', '\\b', '\\f', '\"');

//		\x{2028} is some strange char found in GTA responses... it breaks javascript
		var $match = Array ('/\\\\/u', '/\\"/u', '/\\t/u', '/\\n/u', '/\\r/u', '/\\x{2028}/u');
		var $replace = Array ('\\\\\\\\', '\\"', '\\t', '\\n', '\\r', '');

		/**
		 * Object constructor
		 *
		 * @return JSONHelper
		 */
		function JSONHelper() {

		}

		/**
		 * Parse structure to JSON
		 *
		 * @param mixed $data
		 * @return string
		 */
		function parse($data)
		{
			return '('.$this->encode($data).')';
		}

		/**
		 * Converts PHP variable to JSON string
		 * Can convert any PHP variable with any content to correct JSON structure
		 *
		 * @param mixed $data Data to convert
		 * @return string
		 */
		function encode($data)
		{
			$type = $this->getType($data);

			switch ( $type ) {
				case 'object':
					$data = '{' . $this->processData($data, $type) . '}';
					break;
				case 'array':
					$data = '[' . $this->processData($data, $type) . ']';
					break;
				default:
					if ( is_int($data) || is_float($data) ) {
						$data = (string)$data;
					}
					elseif ( is_string($data) ) {
						$data = '"' . $this->escape($data) . '"';
					}
					elseif ( is_bool($data) ) {
						$data = $data ? 'true' : 'false';
					}
					else {
						$data = 'null';
					}
			}
			
			return $data;
		}

		/**
		 * Enter description here...
		 *
		 * @param Array $data
		 * @param string $type
		 * @return string
		 */
		function processData($data, $type)
		{
			$output = Array ();
			// If data is an object - it should be converted as a key => value pair

			if ( $type == 'object' ) {
				foreach ($data as $key => $value) {
					$output[] = '"' . $key . '": ' . $this->encode($value);
				}
			}
			else {
				foreach ($data as $value) {
					$output[] = $this->encode($value);
				}
			}

			return implode(',', $output);
		}

		/**
		 * Function determines type of variable
		 *
		 * @param mixed $data
		 * @return string
		 */
		function getType(&$data)
		{
			if (is_object($data)) {
				$type = 'object';
			} elseif (is_array($data)) {
				// If array is assoc it should be processed as an object
				if($this->is_assoc($data)) {
					$type = 'object';
				} else {
					$type = 'array';
				}
			} elseif (is_numeric($data)) {
				$type = 'number';
			} elseif(is_string($data)) {
				$type = 'string';
			} elseif(is_bool($data)) {
				$type = 'boolean';
			} elseif(is_null($data)) {
				$type = 'null';
			} else {
				$type = 'string';
			}
			return $type;
		}

		/**
		 * Function determines if array is associative
		 *
		 * @param array $array
		 * @return bool
		 */
		function is_assoc($array)
		{
//			Arrays are defined as integer-indexed arrays starting at index 0, where
//	     	the last index is (count($array) -1); any deviation from that is
//	     	considered an associative array, and will be encoded as such (from Zend Framework).

			return !empty($array) && (array_keys($array) !== range(0, count($array) - 1));
		}

		/**
		 * Escapes special characters
		 * Function escapes ", \, /, \n and \r symbols so that not to cause JavaScript error or
		 * data loss
		 *
		 * @param string $string
		 * @return string
		 */
		function escape($string)
		{
			$string = preg_replace($this->match, $this->replace, $string);

			return $string;

			// Escape certain ASCII characters:
	        // 0x08 => \b
	        // 0x0c => \f
//			return str_replace(array(chr(0x08), chr(0x0C)), array('\b', '\f'), $string);
		}
	}