<?php
$repeat_extension_codes = array(':','.');
$repeat_codes=array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','X','Y','Z');
foreach(array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','x','y','z') as $letter)
	foreach($repeat_extension_codes as $letter2)
		$repeat_codes[] = $letter.$letter2;
//First one is never used
$n_codes = array('?','!','@','#','$','%','^','&','*','(',')','_');

function compressBuckets(array &$buckets){
	$repeat_codes=&$GLOBALS['repeat_codes'];
	$n_codes=&$GLOBALS['n_codes'];
	//print_r($repeat_codes);

	$input = implode('',$buckets);

	$output = array();
	for($i=0;$i<strlen($input);$i+=2){
		$n = (int)substr($input,$i,2);
		//echo $n;
		$output[] = (int)($i ==0 ? $n : $n - (int)substr($input,$i-2,2));
	}


	/*
		This changes the output to put in the repeat codes and avoid having
		numbers that take up two characters by replacing the first digit
		with a code. This allows for variable length decoding which is
		more space efficient (while not affecting the particular number if it's not a repeat).
	*/
	$series=0;
	foreach($output as $i=>$n){
		if($i>0 && $n==1)//isset($output[$i+1])
			$series++;
		else{
			$series=0;
			if($n >= 10){
				$output[$i] = ($n_codes[floor($n / 10)]) . ($n % 10);
			}
		}

		if($series>1 && (!isset($output[$i+1]) || $output[$i+1]!=1)){
			//echo "Series:".($series)."\n";
			$series_start_i=$i-$series+1;
			$repeat_code = $repeat_codes[$series];
			$output[$series_start_i] = $repeat_code;//'x'.$series;
			for($j=$series_start_i+1;$j<$series_start_i + $series;$j++)
				unset($output[$j]);
		}

		//echo "$i\t$n\n";
	}
	//echo "Here is the offset version with repeat compression:\n";
	//print_r($output);
	//echo "\n";
	$output= implode($output);
	return $output;
}

function decompressBuckets(string $input,$left_pad=false){
	$repeat_codes=&$GLOBALS['repeat_codes'];
	$n_codes=&$GLOBALS['n_codes'];
	$repeat_extension_codes = &$GLOBALS['repeat_extension_codes'];

	$offsets=array();
	$input = str_split($input);
	$temp = -1;
	foreach($input as $i=>$x){
		$is_n_code=false;
		//Number codes to  convert !3 -> 13, @4 -> 14
		foreach($n_codes as $n_code_i=>$n_code){
			if($x == $n_code){
				$temp = $n_code_i;
				$is_n_code = true;
				break;
			}
		}
		if($is_n_code==false){
			if($temp>0){
				$offsets[] = (int)($temp.$x);
				$temp = -1;
			}else{
				if($i==0 && $x == '0')
					$offsets[] = 0;

				if(isset($input[$i+1]) && in_array($input[$i+1],$repeat_extension_codes)){
					//This is a double code point
					$code = $x.$input[$i+1];
					$i++; //Jump ahead (skip the extension code)
				}elseif(!in_array($x,range(1,9))){ //Should it be 0 too?
					$code = $x;
				}
				if(isset($code)){
					foreach($repeat_codes as $repeat_code_i=>$repeat_code){
						if($code == $repeat_code){
							for($j=0;$j<$repeat_code_i;$j++)
								$offsets[] = 1;
							break;
						}
					}
					unset($code);
				}else
					$offsets[] = $x;
			}
		}
	}


	$decompressed = array();
	$n = array_shift($offsets); //First offset is actually the start number
	$decompressed[] = $n; //Could pad this
	foreach($offsets as $i=>$offset){

		/*
			The real version won't pad like this
		*/
		$n = $decompressed[$i] + $offset;
		$decompressed[] = $left_pad ? str_pad(''.$n,2,'0',STR_PAD_LEFT):$n;
	}

	return $decompressed;
}
?>
