<?php
/**
 * core.framework
 *
 * @category  Core
 * @package   Core_Gearman
 * @copyright Copyright (c) 2011. Burza d.o.o. (http://web.burza.hr/en/)
 * @license   proprietary
 */

/**
 * @category  Core
 * @package   Core_Gearman
 * @copyright Copyright (c) 2011. Burza d.o.o. (http://web.burza.hr/en/)
 * @license   proprietary
 */
class Core_Gearman_Client
{
    const JOB_NORMAL      = 'run';
    const JOB_BACKGROUND  = 'runbackground';

    const TASK_NORMAL     = 'queue';
    const TASK_BACKGROUND = 'queuebackground';

    const PRIORITY_NORMAL = 'normal';
    const PRIORITY_HIGH   = 'high';
    const PRIORITY_LOW    = 'low';

    /** @var GearmanClient */
    protected $_client;

    /** @var string */
    protected $_prefix;

    /** @var array */
    protected $_methods = array(
        self::PRIORITY_NORMAL => array(
            self::JOB_NORMAL      => 'doNormal',
            self::JOB_BACKGROUND  => 'doBackground',
            self::TASK_NORMAL     => 'addTask',
            self::TASK_BACKGROUND => 'addTaskBackground',
        ),
        self::PRIORITY_HIGH   => array(
            self::JOB_NORMAL      => 'doHigh',
            self::JOB_BACKGROUND  => 'doHighBackground',
            self::TASK_NORMAL     => 'addTaskHigh',
            self::TASK_BACKGROUND => 'addTaskHighBackground',
        ),
        self::PRIORITY_LOW    => array(
            self::JOB_NORMAL      => 'doLow',
            self::JOB_BACKGROUND  => 'doLowBackground',
            self::TASK_NORMAL     => 'addTaskLow',
            self::TASK_BACKGROUND => 'addTaskLowBackground',
        ),
    );

    public function __construct(array $servers = null)
    {
        if (null !== $servers) {
            $this->addServers($servers);
        }
    }

    public function addServers(array $servers)
    {
        foreach($servers as $server) {
            $this->addServer($server);
        }
        return $this;
    }

    public function addServer($server)
    {
        $this->getClient()->addServer($server);
    }

    /**
     * @return string
     */
    public function getPrefix()
    {
        return $this->_prefix;
    }

    /**
     * @param string $prefix
     *
     * @return Core_Gearman_Client
     */
    public function setPrefix($prefix)
    {
        $this->_prefix = $prefix;
        return $this;
    }

    /**
     * @param GearmanClient $client
     *
     * @return \Core_Gearman_Client
     */
    public function setClient(GearmanClient $client)
    {
        $this->_client = $client;
        return $this;
    }

    /**
     * @return GearmanClient
     */
    public function getClient()
    {
        if (null === $this->_client) {
            $this->_client = new GearmanClient;
        }
        return $this->_client;
    }

    /**
     *
     * @param string $function
     * @param mixed  $data
     * @param string $unique_id
     * @param string $priority
     *
     * @return mixed
     */
    public function run($function, $data = null, $unique_id = '', $priority = self::PRIORITY_NORMAL)
    {
        return $this->_run($this->_findMethod(__FUNCTION__, $priority), $function, $data, $unique_id);
    }

    /**
     *
     * @param string $function
     * @param mixed  $data
     * @param string $unique_id
     * @param string $priority
     *
     * @return mixed
     */
    public function runBackground($function, $data = null, $unique_id = '', $priority = self::PRIORITY_NORMAL)
    {
        return $this->_run($this->_findMethod(__FUNCTION__, $priority), $function, $data, $unique_id);
    }

    /**
     * @param        $function
     * @param mixed  $data
     * @param string $unique_id
     * @param string $priority
     *
     * @return mixed
     */
    public function queue($function, $data = null, $unique_id = '', $priority = self::PRIORITY_NORMAL)
    {
        return $this->_run($this->_findMethod(__FUNCTION__, $priority), $function, $data, $unique_id);
    }

    /**
     * @param        $function
     * @param mixed  $data
     * @param string $unique_id
     * @param string $priority
     *
     * @return mixed
     */
    public function queueBackground($function, $data = null, $unique_id = '', $priority = self::PRIORITY_NORMAL)
    {
        return $this->_run($this->_findMethod(__FUNCTION__, $priority), $function, $data, $unique_id);
    }

    public function runQueue()
    {
        return $this->getClient()->runTasks();
    }

    /**
     * @param string $caller
     * @param string $priority
     *
     * @return string
     */
    protected function _findMethod($caller, $priority)
    {
        // normalize input
        $caller   = strtolower($caller);
        $priority = array_key_exists($priority, $this->_methods)          ? $priority : self::PRIORITY_NORMAL;
        $type     = array_key_exists($caller, $this->_methods[$priority]) ? $caller     : 'run';

        return $this->_methods[$priority][$type];
    }

    /**
     *
     * @param string $method
     * @param string $function
     * @param mixed  $data
     * @param string $unique_id
     *
     * @return mixed
     */
    protected function _run($method, $function, $data, $unique_id)
    {
        $data     = json_encode($data);
        $client   = $this->getClient();
        $callable = array($client, $method);
        $function = $this->getPrefix() . $function;
        do {
            $response   = call_user_func_array($callable, array($function, $data, $unique_id));
            $returnCode = $client->returnCode();
            switch($returnCode)
            {
                case GEARMAN_SUCCESS:
                    // success
                    break;

                case GEARMAN_WORK_FAIL:
                    // failure
                    return $returnCode;
                    break;
            }
        } while($returnCode !== GEARMAN_SUCCESS);

        return $response;
    }
}