#!/usr/bin/env php
<?php

ini_set('display_errors','on');
ini_set('error_reporting', E_ALL|E_STRICT);

function eit_dump_error_and_exit2( $text, $backtrace, Exception $cause=null, $extraInfo='' ) {
	fwrite(STDERR, "{$text}\n");
	foreach( $backtrace as $item ) {
		if( isset($item['file']) || isset($item['line']) ) {
			$f = isset($item['file']) ? $item['file'] : '';
			$l = isset($item['line']) ? $item['line'] : '';
			$u = isset($item['function']) ? $item['function'] : '';
			fwrite(STDERR, "  " . $f . ($l ? ":{$l}" : '') . ($u ? " in {$u}" : '') . "\n");
		}
	}
	if( $cause != null ) {
		fwrite(STDERR, "Caused by...\n");
		eit_dump_exception_and_exit($cause);
	}
	if( $extraInfo ) {
		fwrite(STDERR, "\n".$extraInfo."\n");
	}
	exit(1);
}

function eit_dump_error_and_exit( $errno, $errstr, $errfile=null, $errline=null, $errcontext=null ) {
	if( (error_reporting() & $errno) == 0 ) return; // @fopen, etc.
	eit_dump_error_and_exit2( "Error code=$errno: $errstr", debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ) );
}

set_error_handler('eit_dump_error_and_exit', E_ALL|E_STRICT);



$forceUpgrade = false;
$verbosity = 0;
$upgradeTableExpression = null;
$scriptDirs = array();
$upgradeScriptBlobstoreDir = null;
$upgraderClass = 'EarthIT_ProjectUtil_DB_DatabaseUpgrader';
$bootstrapFile = null;
$showHelp = false;
$dryRun = false;
$moreOptions = array();

$usageText =
	"Usage: {$argv[0]} [options]\n".
	"Options:\n".
	"  -f    ; force upgrade, even if scripts will be run out of order\n".
	"  -upgrade-table [<schema>.]<table-name> ; indicate upgrade log table\n".
	"  -bootstrap <file.php>      ; indicate environment initialization script\n".
	"  -upgrade-script-dir <dir>  ; indicate directory containing upgrade scripts\n".
	"  -upgrade-script-blobstore-dir <dir> ; indicate directory into which to copy\n".
	"                             ; upgrade scripts as they're run\n".
	"  -upgrader-class <classname> ; override upgrader class\n".
	"  -dry-run ; dump upgrades to STDOUT instead of running them\n".
	"  -v    ; be chatty\n".
	"  -vv   ; be chattier\n".
	"  -? -h ; show help text and exit\n".
	"\n".
	"Use -dry-run to dump out the SQL for all outstanding upgrades.\n".
	"This will include inserts into the upgrade log table,\n".
	"and should be suitable for running independently.\n".
	"\n".
	"Output from -v and -vv looks similar, but is intended only for debugging\n".
	"and might not be suitable for running (for one thing, -dry-run makes a\n".
	"point to insert missing semicolons between statements.  -vv does not).\n";

for( $i=1; $i<count($argv); ++$i ) {
	if( '-f' == $argv[$i] ) {
		$forceUpgrade = true;
	} else if( '-upgrade-table' == $argv[$i] ) {
		$upgradeTableExpression = $argv[++$i];
	} else if( '-bootstrap' == $argv[$i] ) {
		$bootstrapFile = $argv[++$i];
	} else if( '-naming-convention' == $argv[$i] ) {
		$moreOptions['dbObjectNamingConvention'] = $argv[++$i];
	} else if( '-upgrade-script-dir' == $argv[$i] ) {
		$scriptDirs[] = $argv[++$i];
	} else if( '-upgrade-script-blobstore-dir' == $argv[$i] ) {
		$upgradeScriptBlobstoreDir = $argv[++$i];
	} else if( '-upgrader-class' == $argv[$i] ) {
		$upgraderClass = $argv[++$i];
	} else if( '-dry-run' == $argv[$i] ) {
		$dryRun = true;
	} else if( '-v' == $argv[$i] ) {
		$verbosity = 1;
	} else if( '-vv' == $argv[$i] ) {
		$verbosity = 2;
	} else if( '-?' == $argv[$i] or '-h' == $argv[$i] or '--help' == $argv[$i] ) {
		$showHelp = true;
	} else {
		fwrite(STDERR, "Error: Unrecognized argument: {$argv[$i]}\n");
		fwrite(STDERR, "Run {$argv[0]} -? for usage information\n");
		exit(1);
	}
}

if( $showHelp ) {
	fwrite(STDOUT, $usageText);
	exit(0);
}

function findBootstrapFile() {
	$bootstrapSearchDirs = array('.', __DIR__.'/..', __DIR__);
	foreach( $bootstrapSearchDirs as $d ) {
		if( file_exists($f = "{$d}/init-environment.php") ) {
			return $f;
		}
	}
	return null;
}

$bootstrapFile = $bootstrapFile ?: findBootstrapFile();
if( $bootstrapFile === null ) {
	fwrite(STDERR, "Error: no bootstrap file specified or found.\n");
	exit(1);
}

$reg = require $bootstrapFile;
if( isset($reg->sqlRunner) ) {
	// the most modernistical approach
	$sqlRunner = $reg->sqlRunner;
} else if( method_exists($reg, 'getSqlRunner') ) {
	$sqlRunner = $reg->getSqlRunner();
} else if( method_exists($reg, 'getDbAdapter') ) {
	$sqlRunner = new EarthIT_ProjectUtil_DB_DoctrineSQLRunner($reg->getDbAdapter());
} else {
	fwrite(STDERR, "Error: Registry doesn't define getSqlRunner or getDbAdapter.\n");
	exit(1);
}

if( count($scriptDirs) == 0 ) {
	$scriptDirs[] = 'build/db/upgrades';
}

$upgrader = new $upgraderClass($sqlRunner, $scriptDirs, $moreOptions);
$upgrader->actuallyDoUpgrades = !$dryRun;
$upgrader->dumpUpgradesToStdout = $dryRun;
$upgrader->upgradeScriptBlobstoreDir = $upgradeScriptBlobstoreDir;
$upgrader->allowOutOfOrderScripts = $forceUpgrade;
$upgrader->verbosity = $verbosity;
if( $upgradeTableExpression ) $upgrader->setUpgradeTable($upgradeTableExpression);
$upgrader->run();
