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

// Find and initialize Composer
$files = array(
    __DIR__ . '/../../vendor/autoload.php',
    __DIR__ . '/../../../autoload.php',
    __DIR__ . '/../../../../autoload.php',
    __DIR__ . '/../vendor/autoload.php',
);

$found = false;
foreach ($files as $file) {
    if (file_exists($file)) {
        require_once $file;
        break;
    }
}

if (!class_exists('Composer\Autoload\ClassLoader', false)) {
    die(
        'You need to set up the project dependencies using the following commands:' . PHP_EOL .
            'curl -s http://getcomposer.org/installer | php' . PHP_EOL .
            'php composer.phar install' . PHP_EOL
    );
}

$QUEUE = getenv('QUEUE');
if(empty($QUEUE)) {
    die("Set QUEUE env var containing the list of queues to work.\n");
}

/**
 * REDIS_BACKEND can have simple 'host:port' format or use a DSN-style format like this:
 * - redis://user:pass@host:port
 *
 * Note: the 'user' part of the DSN URI is required but is not used.
 */
$REDIS_BACKEND = getenv('REDIS_BACKEND');

// A redis database number
$REDIS_BACKEND_DB = getenv('REDIS_BACKEND_DB');
if(!empty($REDIS_BACKEND)) {
    if (empty($REDIS_BACKEND_DB))
        Resque::setBackend($REDIS_BACKEND);
    else
        Resque::setBackend($REDIS_BACKEND, $REDIS_BACKEND_DB);
}

$logLevel = false;
$LOGGING = getenv('LOGGING');
$VERBOSE = getenv('VERBOSE');
$VVERBOSE = getenv('VVERBOSE');
if(!empty($LOGGING) || !empty($VERBOSE)) {
    $logLevel = true;
}
else if(!empty($VVERBOSE)) {
    $logLevel = true;
}

$APP_INCLUDE = getenv('APP_INCLUDE');
if($APP_INCLUDE) {
    if(!file_exists($APP_INCLUDE)) {
        die('APP_INCLUDE ('.$APP_INCLUDE.") does not exist.\n");
    }

    require_once $APP_INCLUDE;
}

// See if the APP_INCLUDE containes a logger object,
// If none exists, fallback to internal logger
if (!isset($logger) || !is_object($logger)) {
    $logger = new Resque_Log($logLevel);
}

$BLOCKING = getenv('BLOCKING') !== FALSE;

$interval = 5;
$INTERVAL = getenv('INTERVAL');
if(!empty($INTERVAL)) {
    $interval = $INTERVAL;
}

$count = 1;
$COUNT = getenv('COUNT');
if(!empty($COUNT) && $COUNT > 1) {
    $count = $COUNT;
}

$PREFIX = getenv('PREFIX');
if(!empty($PREFIX)) {
    $logger->log(Psr\Log\LogLevel::INFO, 'Prefix set to {prefix}', array('prefix' => $PREFIX));
    Resque_Redis::prefix($PREFIX);
}

function cleanup_children($signal){
	$GLOBALS['send_signal'] = $signal;
}

if($count > 1) {
	$children = array();
	$GLOBALS['send_signal'] = FALSE;
	
	$die_signals = array(SIGTERM, SIGINT, SIGQUIT);
	$all_signals = array_merge($die_signals, array(SIGUSR1, SIGUSR2, SIGCONT, SIGPIPE));
	
	for($i = 0; $i < $count; ++$i) {
		$pid = Resque::fork();
		if($pid == -1) {
			die("Could not fork worker ".$i."\n");
		}
		// Child, start the worker
		elseif(!$pid) {
			$queues = explode(',', $QUEUE);
			$worker = new Resque_Worker($queues);
			$worker->logLevel = $logLevel;
			$worker->hasParent = TRUE;
			fwrite(STDOUT, '*** Starting worker '.$worker."\n");
			$worker->work($interval);
			break;
		}
		else {
			$children[$pid] = 1;
			while (count($children) == $count){
				if (!isset($registered)) {
					declare(ticks = 1);
					foreach ($all_signals as $signal) {
						pcntl_signal($signal,  "cleanup_children");
					}
					
					$PIDFILE = getenv('PIDFILE');
					if ($PIDFILE) {
						if(file_put_contents($PIDFILE, getmypid()) === false){
							$logger->log(Psr\Log\LogLevel::NOTICE, 'Could not write PID information to {pidfile}', array('pidfile' => $PIDFILE));
                                                        die(2);
                                                }
					}
					
					$registered = TRUE;
				}
				
				if(function_exists('setproctitle')) {
					setproctitle('resque-' . Resque::VERSION . ": Monitoring {$count} children: [".implode(',', array_keys($children))."]");
				}
				
				$childPID = pcntl_waitpid(-1, $childStatus, WNOHANG);
				if ($childPID != 0) {
					fwrite(STDOUT, "*** A child worker died: {$childPID}\n");
					unset($children[$childPID]);
					$i--;					
				}
				usleep(250000);
				if ($GLOBALS['send_signal'] !== FALSE){
					foreach ($children as $k => $v){
						posix_kill($k, $GLOBALS['send_signal']);
						if (in_array($GLOBALS['send_signal'], $die_signals)) {
							pcntl_waitpid($k, $childStatus);
						}
					}
					if (in_array($GLOBALS['send_signal'], $die_signals)) {
						exit;
					}
					$GLOBALS['send_signal'] = FALSE;
				}
			}
		}
	}
}
// Start a single worker
else {
	$queues = explode(',', $QUEUE);
	$worker = new Resque_Worker($queues);
	$worker->logLevel = $logLevel;
	$worker->hasParent = FALSE;

	$PIDFILE = getenv('PIDFILE');
	if ($PIDFILE) {
		if(file_put_contents($PIDFILE, getmypid()) === false) {
			$logger->log(Psr\Log\LogLevel::NOTICE, 'Could not write PID information to {pidfile}', array('pidfile' => $PIDFILE));
                        die(2);
                }
	}

    $logger->log(Psr\Log\LogLevel::NOTICE, 'Starting worker {worker}', array('worker' => $worker));
    $worker->work($interval, $BLOCKING);
}
?>
