#!/usr/bin/php
<?php

include("PEAR/PackageFile.php");

function usage() {
	echo "Usage: ".$_SERVER["argv"][0]." [options] package|channel|summary|description|maintainers dir\n";
	echo "       ".$_SERVER["argv"][0]." [options] date|version|license|changelog|all|hasphpscript dir\n";
	echo "       ".$_SERVER["argv"][0]." [options] debian_deps dir\n";
	echo "       ".$_SERVER["argv"][0]." [options] debian_pkgname channel_url pear_name\n";
	echo "       ".$_SERVER["argv"][0]." [options] debian_version version\n";
	echo "\ncommands:\n";
	echo "  package         - Name of package\n";
	echo "  channel         - PEAR channel URL\n";
	echo "  summary         - Short summary of package\n";
	echo "  description     - Long description of package\n";
	echo "  maintainers     - Comma separated list of maintainers\n";
	echo "  date            - Date of release\n";
	echo "  version         - Version of package\n";
	echo "  license         - License of package\n";
	echo "  changelog       - Full changelog of package\n";
	echo "  all             - print_r() of complete package file\n";
	echo "  hasphpscript    - Check if package contains files of type 'script'\n";
	echo "  debian_deps     - Print dependencies as Debian control fields\n";
	echo "\n  debian_pkgname  - Translate a PEAR package name to a Debian package name\n";
	echo "\n  debian_version  - Translate a PEAR version to a Debian version\n";
	echo "\narguments:\n";
	echo "  dir             - Directory containing package.xml or package2.xml file\n";
	echo "\noptions:\n";
	echo "  -d              - print debug to STDERR\n";
}

function printLog($message) {
	global $debug;
	if ($debug) {
		if ($handle = fopen("php://stderr", "a")) {
			if (!is_object($message)) {
				$message = PEAR::raiseError($message);
			}
			fwrite($handle, $message->toString()."\n");
			//var_dump($message->getUserInfo());
			fclose($handle);
		}
	}
}

function checkForPhpScript($pf, $content = NULL) {
	if(get_class($pf) == "PEAR_PackageFile_v1") {
		$filelist = $pf->getFilelist();
		foreach($filelist as $item) {
			if($item['role'] == 'script') {
				return 1;
			}
		}
		return 0;
	} elseif(get_class($pf) == "PEAR_PackageFile_v2") {
		if ($content === NULL) {
			$content = $pf->getContents();
		}
		foreach($content as $name=>$item) {
			if($name == 'dir') {
				return checkForPhpScript($pf, $item);
			} elseif($name == 'file') {
				foreach($item as $file) {
					if($file['attribs']['role'] == 'script') {
						return 1;
					}
				}
			}
		}
		return 0;
	} else {
		printLog("Unknown PEAR_PackageFile version");
		exit(1);
	}

}

function pearPackageNameToDebianPackageName($channel_url, $package_name, $prefix = NULL, $shift_from_url = Array("pear", "pecl", "www")) {
	global $builtin_extensions;
	//put everything lowercase
	$package_name = strtolower($package_name);
	$channel_url = strtolower($channel_url);

	// split channel url by dots:
	$urlc = explode(".", $channel_url);
	// split package name by underscores:
	$packagec = explode("_", $package_name);
	// drop last part of url (TLD):
	array_pop($urlc);
	// drop first part of url if equal to pear or www
	if (isset($urlc[0]) && in_array($urlc[0], $shift_from_url)) {
		if (($urlc[0] == "pecl") && ($prefix === NULL)) {
			if (in_array($package_name, $builtin_extensions)) {
				return NULL;
			}
			$prefix = "php5-"; // Wild guess
		}
		array_shift($urlc);
	}
	// drop first part of url if equal to php
	if (isset($urlc[0]) && ($urlc[0] == "php")) {
		array_shift($urlc);
	}
	// drop first part of package if equal to last part of url (should be done several times?)
	if (end($urlc) == $packagec[0]) {
		array_shift($packagec);
	}
	//merge the result
	return (($prefix === NULL) ? "php-" : $prefix) .implode('-', array_merge($urlc, $packagec));
}
function pearExtensionNameToDebianPackageName($extension_name, $prefix = "php5-") {
	global $builtin_extensions;
	if (in_array($extension_name, $builtin_extensions)) {
		return NULL;
	}
	return $prefix.strtolower($extension_name);
}

function pearVersionToDebianVersion($version) {
	$debian_version = "";
	$tmp = explode(".",strtolower($version));
	foreach($tmp as $component) {
		if (preg_match('/^\d+$/', $component)) {
			$debian_version .= "$component.";
		} elseif (preg_match('/^(\d+)(alpha\d*|a\d*|beta\d*|b\d*|rc\d*)$/', $component, $matches)) {
			$debian_version .= "$matches[1]~$matches[2].";
		} else {
			$debian_version .= "?not supported($component)?."; # TODO
		}
	}
	return substr($debian_version, 0, -1);
}

function loadPackageFile($packagefilename) {
	$config = new PEAR_Config();
	if ($config instanceof PEAR_Error) {
		printLog($config);
		exit(1);
	}
	$pkg = new PEAR_PackageFile($config);
	if ($pkg instanceof PEAR_Error) {
		printLog($pkg);
		exit(1);
	}
	// Check first for package.xml or package2.xml in subdirs, to have correct relative dirs
	if (is_dir($packagefilename)) {
		$dir_name = realpath($packagefilename);
		$d = dir($dir_name);
		while (false !== ($entry = $d->read())) {
			if ($entry != "." && $entry != ".." && is_dir("$dir_name/$entry")) {
				if (is_file("$dir_name/$entry/package2.xml")) {
					$packagefilename = "$dir_name/$entry/package2.xml";
				} elseif (is_file("$dir_name/$entry/package.xml")) {
					$packagefilename = "$dir_name/$entry/package.xml";
				}
			}
		}
		$d->close();
	}
	$pf = $pkg->fromAnyFile($packagefilename, 0);
	if ($pf instanceof PEAR_Error) {
		printLog($pf);
		exit(1);
	}

	return $pf;
}

$debug = false;
$builtin_extensions = Array('bcmath', 'bz2', 'calendar', 'Core', 'ctype', 'date',
	'dba', 'dom', 'ereg', 'exif', 'fileinfo', 'filter', 'ftp', 'gettext', 'hash', 'iconv', 'json', 'libxml',
	'mbstring', 'mhash', 'openssl', 'pcre', 'Phar', 'posix', 'Reflection', 'session', 'shmop', 'SimpleXML',
	'soap', 'sockets', 'SPL', 'standard', 'sysvmsg', 'sysvsem', 'sysvshm', 'tokenizer', 'wddx', 'xml',
	'xmlreader', 'xmlwriter', 'zip', 'zlib');
$args = $_SERVER["argv"];
array_shift($args);

if (!empty($args[0]) && ($args[0] == "-d")) {
	$debug = true;
	array_shift($args);
}

if(count($args) < 2) {
	usage();
	exit;
}
$command = array_shift($args);

switch($command) {
	case "package":
		$pf = loadPackageFile($args[0]);
		echo $pf->getPackage();
		break;
	case "channel":
		$pf = loadPackageFile($args[0]);
		echo $pf->getChannel();
		break;
	case "summary":
		$pf = loadPackageFile($args[0]);
		echo $pf->getSummary();
		break;
	case "description":
		$pf = loadPackageFile($args[0]);
		echo $pf->getDescription();
		break;
	case "maintainers":
		$pf = loadPackageFile($args[0]);
		$tmp = Array();
		foreach($pf->getMaintainers() as $maintainer) {
			if (in_array($maintainer["role"], Array("lead", "developer"))) {
				$tmp[] = $maintainer["name"];
			}
		}
		print implode(", ", $tmp);
		break;
	case "date":
		$pf = loadPackageFile($args[0]);
		echo $pf->getDate();
		break;
	case "version":
		$pf = loadPackageFile($args[0]);
		echo $pf->getVersion();
		break;
	case "license":
		$pf = loadPackageFile($args[0]);
		echo $pf->getLicense();
		break;
	case "changelog":
		$pf = loadPackageFile($args[0]);
		echo "Version ".$pf->getVersion()." - ".$pf->getDate()." (".$pf->getState().")\n";
		echo "----------------------------------------\n";
		echo "Notes:\n";
		echo "  ".str_replace("\n", "\n  ", wordwrap(ereg_replace("[[:space:]]+", " ", $pf->getNotes())))."\n\n";
		if(get_class($pf) == "PEAR_PackageFile_v1") {
			foreach($pf->_packageInfo["changelog"] as $changelog) {
				echo "Version ".$changelog["version"]." - ".$changelog["release_date"]." (".$changelog["release_state"].")\n";
				echo "----------------------------------------\n";
				echo "Notes:\n";
				echo "  ".str_replace("\n", "\n  ", wordwrap(ereg_replace("[[:space:]]+", " ", $changelog["release_notes"])))."\n\n";
			}

		} elseif( get_class($pf) == "PEAR_PackageFile_v2") {
			$tmparr = $pf->_packageInfo["changelog"]["release"];
			if(array_key_exists("version", $tmparr)) {
				$tmparr = Array($tmparr);
			}
			$tmparr = array_reverse($tmparr);
			foreach($tmparr as $changelog) {
				echo "Version ".$changelog["version"]["release"]." - ".$changelog["date"]." (".$changelog["stability"]["release"].")\n";
				echo "----------------------------------------\n";
				echo "Notes:\n";
				echo "  ".str_replace("\n", "\n  ", wordwrap(ereg_replace("[[:space:]]+", " ", $changelog["notes"])))."\n\n";
			}
		} else {
			printLog("Unknown PEAR_PackageFile version");
			exit(1);
		}
		break;
	case "all":
		$pf = loadPackageFile($args[0]);
		print_r($pf->_packageInfo);
		break;
	case "hasphpscript":
		$pf = loadPackageFile($args[0]);
		echo checkForPhpScript($pf);
		break;
	case "debian_deps":
		$pf = loadPackageFile($args[0]);
		$deps = Array();
		if(get_class($pf) == "PEAR_PackageFile_v1") {
			if ($pf->hasDeps()) {
				printLog("debian_deps is not supported for package.xml version 1.0");
			}
		} elseif( get_class($pf) == "PEAR_PackageFile_v2") {
			$dependencies = &$pf->getDependencies();
			foreach($dependencies as $level => $dep) {
				foreach($dep as $type => $tmp) {
					if (($level == "required") or ($level == "optional")) {
						if (key($tmp) !== 0) {
							$tmp = Array($tmp);
						}
						foreach($tmp as $infos) {
							if (!array_key_exists("exclude", $infos)) {
								$infos["exclude"] = Array();
							} elseif (!is_array($infos["exclude"])) {
								$infos["exclude"] = Array($infos["exclude"]);
							}
							switch($type) {
								case "pearinstaller":
									$package = "php-pear";
									break;
								case "php":
									if (checkForPhpScript($pf)) {
										$package = "php5-cli";
									} else {
										$package = "php5";
									}
									break;
								case "package":
									$package = pearPackageNameToDebianPackageName($infos["channel"], $infos["name"]);
									break;
								case "extension":
									$package = pearExtensionNameToDebianPackageName($infos["name"]);
									break;
								case "subpackage":
								case "os":
								case "arch":
								default:
									printLog("Tag '$type' not supported in $level $type: ".print_r($infos, true));
									continue 2;
							}
							if ($package === NULL) {
								continue;
							}
							if (array_key_exists("min", $infos) || array_key_exists("max", $infos)) {
								$tmp2 = $package;
								if (array_key_exists("min", $infos)) {
									if (in_array($infos["min"], $infos["exclude"])) {
										$operator = ">>";
										$infos["exclude"] = array_diff($infos["exclude"], Array($infos["min"]));
									} else {
										$operator = ">=";
									}
									$package = "$tmp2 ($operator ".
										pearVersionToDebianVersion($infos["min"]).
										")";
								}
								if (array_key_exists("max", $infos)) {
									if (!empty($package)) {
										$package = "$package, ";
									}
									if (in_array($infos["max"], $infos["exclude"])) {
										$operator = "<<";
										$infos["exclude"] = array_diff($infos["exclude"], Array($infos["max"]));
									} else {
										$operator = "<=";
									}
									$package = "$package$tmp2 ($operator ".
										pearVersionToDebianVersion($infos["max"]).
										")";
								}
							}
							# TODO: recommended
							if (!empty($infos["recommended"])) {
								printLog("Tag 'recommended' not supported in $level $type $package: ".print_r($infos["recommended"], true));
							}
							# TODO: exclude
							if (!empty($infos["exclude"])) {
								printLog("Tag 'exclude' not supported in $level $type $package: ".print_r($infos["exclude"], true));
							}
							if (array_key_exists("conflicts", $infos)) {
								$deps["conflicts"][] = $package;
							} else {
								$deps[$level][] = $package;
							}
						}
					}
				}
			}
		} else {
			printLog("Unknown PEAR_PackageFile version");
			exit(1);
		}
		if (array_key_exists("required", $deps)) {
			print "Depends: ".implode(", ", $deps["required"])."\n";
		}
		if (array_key_exists("optional", $deps)) {
			print "Recommends: ".implode(", ", $deps["optional"])."\n";
		}
		if (array_key_exists("conflicts", $deps)) {
			print "Breaks: ".implode(", ", $deps["conflicts"])."\n";
		}
	break;
	case "debian_pkgname":
		if(count($args) != 2) {
			usage();
			exit;
		}
		echo pearPackageNameToDebianPackageName($args[0], $args[1]);
		exit;
		break;
	case "debian_version":
		if(count($args) != 1) {
			usage();
			exit;
		}
		echo pearVersionToDebianVersion($args[0]);
		exit;
		break;
	default:
		printLog("Unknown command $command");
		exit(1);

}

?>
