<?php

class sfMemcacheCache
{
  const WAIT_FLAG = -4479;
  const DEFAULT_NAMESPACE = '';
  protected static $instances = array();
  protected $mem = null;

  public static function getInstance($bucket = 'default') {
    if (!isset(self::$instances[$bucket])) self::$instances[$bucket] = new sfMemcacheCache($bucket);
    return self::$instances[$bucket];
  }

  public function __construct($bucket = 'default') {
    // Our config/memcache.yml file includes all of our hosts that we should connect to.
    include (sfConfigCache::getInstance()->checkConfig(sfConfig::get('sf_app_config_dir_name').'/memcache.yml'));
    $conf = sfConfig::get('memcache_servers');
    $servers = @$conf[$bucket];
    $this->mem = new Memcache();
    foreach ($servers['servers'] as $server) {
      $this->mem->addServer($server['host'], $server['port'], $server['persistent'], $server['weight'], 1, 3);
    }
  }

  public function set($id, $namespace = self::DEFAULT_NAMESPACE, $data, $timeout = 300) {
    $std = new Stdclass;
    $std->data = $data;
    $std->lastModified = time();
    $this->mem->set($namespace . $id, $std, 0, (int)($timeout * (1 + rand(0, 20)/100)));
  }

  public function get($id, $namespace = self::DEFAULT_NAMESPACE) {
    $std = $this->mem->get($namespace . $id);
    if ($std instanceof Stdclass && isset($std->data)) return $std->data;
    return null;
  }

  public function getWithQueue($id, $namespace = self::DEFAULT_NAMESPACE, $waittime = 10) {
    for ($i = 0; $i < $waittime + rand(0, 5); $i++) {
      $data = $this->get($id, $namespace);
      if ($data === self::WAIT_FLAG) {sleep(1); continue;}
      if ($data === null) break;
      return $data;
    }
    $this->set($id, $namespace, self::WAIT_FLAG, $waittime);
    return null;
  }

  public function remove($id = null, $namespace = self::DEFAULT_NAMESPACE) {
    if ($id !== null) $this->mem->delete($namespace . $id);
    else $this->mem->flush();
  }
}
