<?php

/**
 * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * @package fusionLib
 * @copyright Copyright (c) 2008 - 2013 fusionLib. All rights reserved.
 * @link http://fusionlib.com
 */

/**
 * _flUtf8Base Class
 *
 * Class for common UTF8 functions.
 *
 * @package fusionLib
 */
abstract class _flUtf8Base {

	/**
	 * Check a string as being valid UTF-8.
	 *
	 * @param string $string The string to check for validity.
	 * @return bool true is returned if the string is valid UTF-8 else false.
	 */
	static function isValid($string) {

		// For all bytes
		$len = strlen($string);
		$bytes = 0;
		for($i=0;$i<$len;$i+=$bytes) {

			// Get the next source byte
			$in = ord($string[$i]);

			// If single byte
			if(($in & 0x80) == 0)
				$bytes = 1;
			// Else multi byte
			else {
				// if 2 byte
				if(($in & 0xe0) == 0xc0 && ($i + 1) < $len) {
					// Check 2nd byte and that unicode char is in shortest form
					$in2 = ord($string[$i + 1]);
					if(($in2 & 0xc0) == 0x80 && ($v = (($in & 0x1f) << 6 | ($in2 & 0x3f))) >= 0x0080 && ($v & 0xfffff800) != 0xd800)
						$bytes = 2;
					else
						break;
				}
				// If 3 byte
				else if(($in & 0xf0) == 0xe0 && ($i + 2) < $len) {
					// Check 2nd & 3rd bytes and that unicode char is in shortest form
					$in2 = ord($string[$i + 1]);
					$in3 = ord($string[$i + 2]);
					if(($in2 & 0xc0) == 0x80 && ($in3 & 0xc0) == 0x80 && ($v = (($in & 0x0f) << 12 | ($in2 & 0x3f) << 6 | ($in3 & 0x3f))) >= 0x0800 && ($v & 0xfffff800) != 0xd800)
						$bytes = 3;
					else
						break;
				}
				// If 4 byte
				else if(($in & 0xf8) == 0xf0 && ($i + 3) < $len) {
					// Check 2nd, 3rd and 4th bytes and that unicode char is in shortest form
					// Check if exceeds maximum allowed code point
					$in2 = ord($string[$i + 1]);
					$in3 = ord($string[$i + 2]);
					$in4 = ord($string[$i + 3]);
					if(($in2 & 0xc0) == 0x80 && ($in3 & 0xc0) == 0x80 && ($in4 & 0xc0) == 0x80 && ($v = (($in & 0x07) << 18 | ($in2 & 0x3f) << 12 | ($in3 & 0x3f) << 6 | ($in4 & 0x3f))) >= 0x10000 && $v < 0x10ffff && ($v & 0xfffff800) != 0xd800)
						$bytes = 4;
					else
						break;
				}
				// Else it is a bad byte sequence
				else
					break;
			}
		}

		// If not all bytes used then bad string else valid
		return $i == $len;
	}
}

// If mbstring functions are present then use this class
if(function_exists('mb_internal_encoding')) {

	// Set the internal encoding to UTF-8
	mb_internal_encoding('UTF-8');

	/**
	 * flUtf8 Class
	 *
	 * Class to supply PHP capability specific functions for UTF-8 support.
	 *
	 * @package fusionLib
	 */
	abstract class flUtf8 extends _flUtf8Base {

		/**
		 * Convert string to uppercase.
		 *
		 * @param string $str The string to convert.
		 * @return string The uppercased string.
		 */
		static function toUpper($str) {
			return mb_strtoupper($str);
		}

		/**
		 * Convert string to lowercase.
		 *
		 * @param string $str The string to convert.
		 * @return string The lowercased string.
		 */
		static function toLower($str) {
			return mb_strtolower($str);
		}

		/**
		 * Find the length of a UTF-8 encoded string.
		 *
		 * @param string $string The string to find the length of.
		 * @return int The length of the string in characters.
		 * @static
		 */
		static function strlen($string) {
			return mb_strlen($string);
		}

		/**
		 * Extract part of a UTF-8 string.
		 *
		 * @param string $string The string to extract characters from.
		 * @param int $start If non-negative the returned string will start at the start'th position in the
		 * string starting at zero. If negative the returned string will start at the start'th character from the end
		 * of the string.
		 * @param int $length If given and positive the string will contain at most length characters, if negative
		 * then that many characters will be omitted from the end of the string.
		 * @return string The extracted portion of the string.
		 * @static
		 */
		static function substr($string, $start, $length = null) {
			return is_null($length) ? mb_substr($string, $start) : mb_substr($string, $start, $length);
		}
	}
}
else
	require FLLIBPATH . 'Utf8/utf8-native.php';
