<?php
namespace Engine;

/**
 * Convert a number to/from the specified base
 * @author Lucian Sirbu
 */
class NumberConvertor
{
	/**
	 * Convert a number to the specified base
	 * Bases are specified as alphabets ('0123456789') instead of 'base10'
	 * @param Int $number
	 * @param string $alphabet
	 * @return String
	 */
	static public function baseEncode($number, $alphabet = 'alphabet:full')
	{
		if (is_float($number)) {
			// throw new \RuntimeException("Bases can only be converted for numbers");

			// keep only the modulo, ignore anything above PHP_INT_MAX. This should not normally be reached!!! It will convert 0xffffffffffffffff to 0x0 for hex numbers....
			$div = (int)floor($number/PHP_INT_MAX);
			$mod = (int)($number - ($div*PHP_INT_MAX));

			$number = $mod;
		}

		$alphabet = self::expandAlphabet($alphabet);
		$alphabetL = strlen($alphabet);
		$ret = "";
		if ($number==0) {
			return $alphabet[0];
		}

		while ($number) {
			$ret.= $alphabet[$number % $alphabetL];
			$number = floor($number / $alphabetL);
		}
		return strrev($ret);
	}

	/**
	 * Convert a number to the specified base
	 * Bases are specified as alphabets ('0123456789') instead of 'base10'
	 * @param String $str
	 * @param string $alphabet
	 * @return Int
	 */
	static public function baseDecode($str, $alphabet = 'alphabet:full')
	{
		$alphabet = self::expandAlphabet($alphabet);
		$alphabetL = strlen($alphabet);
		$alphabetRev = array_flip(str_split($alphabet, 1));

		$ret = 0;
		while (strlen($str[0])) {
			$ret = $ret * $alphabetL + $alphabetRev[$str[0]];
			$str = substr($str, 1);
		}

		return $ret;
	}

	/**
	 * Convert the alphabet from a shorthand notation to a full fledged char list
	 * @param String $alphabet
	 * @return string
	 */
	static protected function expandAlphabet($alphabet)
	{
		switch($alphabet) {
			case 'alphabet:hex':
				return '0123456789abcdef';
			break;
			case 'alphabet:lowercaseLetters':
				return '0123456789abcdefghijklmnopqrstuvwxyz';
			break;
			case 'alphabet:full':
				return '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
			break;
		}

		return $alphabet;
	}
}
