<?php

// Classes
// 0.7.12
//////////////////////////////////////////

class ProgressBar {

	protected static $time_start;
	protected static $time_remain;
	protected static $time_update;
	protected static $total;
	protected static $done;
	protected static $message;
	
	public static function display($message = null) {
		
		$progress = self::$done/self::$total;
		$string = "PROGRESS:".round($progress*100,2);
		
		if ($message === true) {
			$message = self::$message;
			}
		
		if ($message) {
			if (time()-self::$time_update) { // only update the remaining time every 1 seconds
				$seconds = time() - self::$time_start;
				self::$time_remain = floor($seconds/$progress)-$seconds;
				self::$time_update = time();
				}
			$message = gmdate("H:i:s",self::$time_remain)." ".$message;
			}
		
		if ($message) {
			return "\n".$string."\n".$message;
			} elseif (!strpos(__FILE__,".app")) {
			return "\r\033[K\r".$string;
			} else {
			return "\n".$string;
			}
		
		}
	
	public static function start($total, $message = null) {
		self::$done = 0;
		self::$total = $total;
		self::$time_start = time();
		self::$message = $message;
		return msg($message).self::display();
		}

	public static function next($message = null) {
		self::$done++;
		if (is_string($message)) { msg($message); }
		return self::display($message);
		}
    
    public static function finish() {
        global $wopt_currstep;
        $wopt_currstep++;
        self::$done = 0;
        return "\nREFRESH\n";
    	}
	
	}

// Functions
//////////////////////////////////////////

function alert($string, $title = "Warning") {
	echo "\nALERT:".$title."|".$string."\n";
	}

function askMulti($string, $buttons) {
	$buttonstring = "buttons {\\\"".implode("\\\", \\\"",$buttons)."\\\"} default button ".count($buttons);
	$result = exec("osascript -e \"display dialog \\\"".$string."\\\" ".$buttonstring."\" | cut -f2 -d':'");
	return array_search($result,$buttons);
	}

function msg($string) {
	global $messages_log_file;
	$logstring = "[".date('Y-m-d h:i:s')."] ".$string."\n";
	file_put_contents($messages_log_file, $logstring, FILE_APPEND);
	return $string."\n";
	}

function timeToSeconds($val) {
	if (!is_numeric($val) && strpos($val,":") === false) {
		$val = str_replace(" s","",$val);
		$val = str_replace(" h ",":",$val);
		$val = str_replace(" min",":00",$val);
		}
	if (!is_numeric($val)) {
		$sec = 0;
		foreach (array_reverse(explode(':', $val)) as $k => $v) $sec += pow(60, $k) * $v;
		$val = $sec;
		}
	return number_format($val,2,".","");
	}

function sanitize($val,$type) {
	switch($type) {
		case "t":
		return $val;
		break;
		case "i":
		return filter_var($val,FILTER_SANITIZE_NUMBER_FLOAT);
		break;
		case "s":
		return timeToSeconds($val);
		break;
		case "d":
		if ($formatted = @strtotime($val)) {
			return $formatted;
			} else {
			return $val;
			}
		break;
		}
	}

function is_serial($string) {
    return (@unserialize($string) !== false || $string == 'b:0;');
	}

function statToArray($stat) {
	foreach (explode(" ",$stat) as $part) {
		$value = explode("=",$part);
		$out[$value[0]] = $value[1];
		}
	return $out;
	}
	
function stepString() {
	global $wopt_steps;
	global $wopt_currstep;
	return "Step ".$wopt_currstep." of ".$wopt_steps;
	}


function shortlabel($pathname, $max = 99) {
	$basename = basename($pathname);
	$suffix = "(...).".pathinfo($basename,PATHINFO_EXTENSION);
	if (strlen($basename) > $max) {
		$return = substr($basename, 0, ($max-strlen($suffix))).$suffix;
		} else {
		$return = $basename;
		}
	return $return;
	}

function human_filesize($bytes, $decimals = 2) {
    $size = array('B','kB','MB','GB','TB','PB','EB','ZB','YB');
    $factor = floor((strlen($bytes) - 1) / 3);
    return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$size[$factor];
	}

function ncenter($string, $title = "Skim") {
	exec("osascript -e 'display notification \"".$string."\" with title \"".$title."\"'");
	}

function utf8_for_xml($string) {
    return preg_replace ('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $string);
    }

class plistParser extends XMLReader {
	public function parseString($string) { $this->XML($string); return $this->process(); }
    private function process() {
    	$this->read();
    	if($this->nodeType !== XMLReader::DOC_TYPE || $this->name !== "plist") { throw new Exception(sprintf("Error parsing plist. nodeType: %d -- Name: %s", $this->nodeType, $this->name), 2); }
		if(!$this->next("plist") || $this->nodeType !== XMLReader::ELEMENT || $this->name !== "plist") { throw new Exception(sprintf("Error parsing plist. nodeType: %d -- Name: %s", $this->nodeType, $this->name), 3); }
		$plist = array(); while($this->read()) { if($this->nodeType == XMLReader::ELEMENT) { $plist[] = $this->parse_node(); } }
		if(count($plist) == 1 && $plist[0]) { return $plist[0]; } else { return $plist; }
		}
	private function parse_node() {
		if($this->nodeType !== XMLReader::ELEMENT) return;
		switch($this->name) {
			case 'data': return base64_decode($this->getNodeText()); break;
			case 'real': return floatval($this->getNodeText()); break;
			case 'string': return $this->getNodeText(); break;
			case 'integer': return intval($this->getNodeText()); break;
			case 'date': return $this->getNodeText(); break;
			case 'true': return true; break;
			case 'false': return false; break;
			case 'array': return $this->parse_array(); break;
			case 'dict': return $this->parse_dict(); break;
			// why the can't this plist parser handle the plist generated from an hdiutil list with no dimgs attached?
			//default: throw new Exception(sprintf("Not a valid plist. %s is not a valid type", $this->name), 4);
			}
		}
	private function parse_dict() {
		$array = array(); $this->nextOfType(XMLReader::ELEMENT);
		do { if($this->nodeType !== XMLReader::ELEMENT || $this->name !== "key") { if(!$this->next("key")) { return $array; } } $key = $this->getNodeText(); $this->nextOfType(XMLReader::ELEMENT); $array[$key] = $this->parse_node(); $this->nextOfType(XMLReader::ELEMENT, XMLReader::END_ELEMENT); }
		while($this->nodeType && !$this->isNodeOfTypeName(XMLReader::END_ELEMENT, "dict")); return $array;
		}
	private function parse_array() {
		$array = array(); $this->nextOfType(XMLReader::ELEMENT);
		do { $array[] = $this->parse_node(); $this->nextOfType(XMLReader::ELEMENT, XMLReader::END_ELEMENT); }
		while($this->nodeType && !$this->isNodeOfTypeName(XMLReader::END_ELEMENT, "array")); return $array;
		}
	private function getNodeText() { $string = $this->readString(); $this->nextOfType(XMLReader::END_ELEMENT); return $string; }
	private function nextOfType() { $types = func_get_args(); $this->read(); while($this->nodeType && !(in_array($this->nodeType, $types))) { $this->read(); } }
	private function isNodeOfTypeName($type, $name) { return $this->nodeType === $type && $this->name === $name; }
	}

function parseMediaInfo ($xml) {
	$xml = simplexml_load_string($xml);
    $data = array();
    $data['version'] = (string) $xml['version'];
    foreach ($xml->File->track as $track) {
		$trackType = strtolower($track['type']);
		$trackId = isset($track['streamid']) ? $track['streamid'] : 1;
		$trackId = (string)$trackId;
		$trackData = [];
		foreach ($track as $rawKey => $rawVal) {
			$key = strtolower($rawKey);
			$val = (string)$rawVal;
			if ($key == 'stream_identifier') { continue; }
			if (!array_key_exists($key, $trackData)) {
				$trackData[$key] = array($val);
				} elseif (!in_array($val, $trackData[$key])) {
				$trackData[$key][] = $val;
				}
            }
		if ($trackType == 'general') {
			$data['file']['general'] = $trackData;
			} else {
			$data['file'][$trackType][$trackId] = $trackData;
			}
		}
	return $data;
	}

?>