<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');


/**
 * Memcached Class
 *
 * @package         zsb
 * @subpackage      Libraries
 * @category        Libraries
 * @author          esf Dev Team
 * @link
 */
class My_memcached2
{
    private $config;
    private $local_cache = array();
    private $m;
    private $client_type;
    private $ci;
    protected $errors = array();
    private $connstate = FALSE; //mc连接状态（非必要时不连接状态）

    public function __construct()
    {
        $this->ci =& get_instance();

        // Lets try to load Memcache or Memcached Class
        $this->client_type = class_exists('Memcache') ? "Memcache" : (class_exists('Memcached') ? "Memcached" : FALSE);

        if($this->client_type)
        {
            $this->ci->load->config('memcached');
            $this->config = $this->ci->config->item('memcached');



            // Which one should be loaded
            switch($this->client_type)
            {
                case 'Memcached':
                    $this->m = new Memcached();
                    break;
                case 'Memcache':
                    $this->m = new Memcache();
                    // Set Automatic Compression Settings
                    if ($this->config['config']['auto_compress_tresh'])
                    {
                        $this->setcompressthreshold($this->config['config']['auto_compress_tresh'], $this->config['config']['auto_compress_savings']);
                    }
                    break;
            }
            log_message('debug', "Memcached Library: $this->client_type Class Loaded");

            //$this->auto_connect();	//非必要时不连接状态
        }
        else
        {
            log_message('error', "Memcached Library: Failed to load Memcached or Memcache Class");
        }
    }

    /*
    +-------------------------------------+
            Name: auto_connect
            Purpose: runs through all of the servers defined in
            the configuration and attempts to connect to each
            @param return : none
    +-------------------------------------+
    */
    private function auto_connect()
    {
        foreach($this->config['servers2'] as $key=>$server)
        {
            if(!$this->add_server($server))
            {
                $this->errors[] = "Memcached Library: Could not connect to the server named $key";
                log_message('error', 'Memcached Library: Could not connect to the server named "'.$key.'"');
            }
            else
            {
                log_message('debug', 'Memcached Library: Successfully connected to the server named "'.$key.'"');
            }
        }
    }

    /*
    +-------------------------------------+
            Name: add_server
            Purpose: 
            @param return : TRUE or FALSE
    +-------------------------------------+
    */
    public function add_server($server)
    {
        if($this->connstate === FALSE)
        {
            extract($server);
            $this->connstate = $this->client_type == 'Memcache' ? $this->m->connect($host, $port) : $this->m->addServer($host, $port, $weight);
        }

        return $this->connstate;
    }

    /*
    +-------------------------------------+
            Name: add
            Purpose: add an item to the memcache server(s)
            @param return : TRUE or FALSE
    +-------------------------------------+
    */
    public function add($key = NULL, $value = NULL, $expiration = NULL)
    {
        $key =GB_CITY.$key;
        $this->auto_connect();

        if(is_null($expiration))
        {
            $expiration = $this->config['config']['expiration'];
        }
        if(is_array($key))
        {
            foreach($key as $multi)
            {
                if(!isset($multi['expiration']) || $multi['expiration'] == '')
                {
                    $multi['expiration'] = $this->config['config']['expiration'];
                }
                $this->add($this->key_name($multi['key']), $multi['value'], $multi['expiration']);
            }
        }
        else
        {
            $this->local_cache[$this->key_name($key)] = $value;
            switch($this->client_type)
            {
                case 'Memcache':
                    $add_status = $this->m->add($this->key_name($key), $value, $this->config['config']['compression'], $expiration);
                    break;

                default:
                case 'Memcached':
                    $add_status = $this->m->add($this->key_name($key), $value, $expiration);
                    break;
            }

            return $add_status;
        }
    }

    /*
    +-------------------------------------+
            Name: set
            Purpose: similar to the add() method but uses set
            @param return : TRUE or FALSE
    +-------------------------------------+
    */
    public function set($key = NULL, $value = NULL, $expiration = NULL)
    {
        $key =GB_CITY.$key;
        $this->auto_connect();

        if(is_null($expiration))
        {
            $expiration = $this->config['config']['expiration'];
        }
        if(is_array($key))
        {
            foreach($key as $multi)
            {
                if(!isset($multi['expiration']) || $multi['expiration'] == '')
                {
                    $multi['expiration'] = $this->config['config']['expiration'];
                }
                $this->set($this->key_name($multi['key']), $multi['value'], $multi['expiration']);
            }
        }
        else
        {
            $this->local_cache[$this->key_name($key)] = $value;
            switch($this->client_type)
            {
                case 'Memcache':
                    $add_status = $this->m->set($this->key_name($key), $value, $this->config['config']['compression'], $expiration);
                    break;

                default:
                case 'Memcached':
                    $add_status = $this->m->set($this->key_name($key), $value, $expiration);
                    break;
            }

            return $add_status;
        }
    }

    /*
    +-------------------------------------+
            Name: get
            Purpose: gets the data for a single key or an array of keys
            @param return : array of data or multi-dimensional array of data
    +-------------------------------------+
    */
    public function get($key = NULL)
    {
        $key =GB_CITY.$key;
        $this->auto_connect();

        if($this->m)
        {
            if(isset($this->local_cache[$this->key_name($key)]))
            {
                return $this->local_cache[$this->key_name($key)];
            }
            if(is_null($key))
            {
                $this->errors[] = 'The key value cannot be NULL';
                return FALSE;
            }

            if(is_array($key))
            {
                foreach($key as $n=>$k)
                {
                    $key[$n] = $this->key_name($k);
                }
                return $this->m->getMulti($key);
            }
            else
            {
                return $this->m->get($this->key_name($key));
            }
        }
        return FALSE;
    }


    /*
    +-------------------------------------+
            Name: delete
            Purpose: deletes a single or multiple data elements from the memached servers
            @param return : none
    +-------------------------------------+
    */
    public function delete($key, $expiration = NULL)
    {
        $key =GB_CITY.$key;
        $this->auto_connect();

        if(is_null($key))
        {
            $this->errors[] = 'The key value cannot be NULL';
            return FALSE;
        }

        if(is_null($expiration))
        {
            $expiration = $this->config['config']['delete_expiration'];
        }

        if(is_array($key))
        {
            foreach($key as $multi)
            {
                $this->delete($multi, $expiration);
            }
        }
        else
        {
            unset($this->local_cache[$this->key_name($key)]);
            return $this->m->delete($this->key_name($key), $expiration);
        }
    }

    /*
    +-------------------------------------+
            Name: replace
            Purpose: replaces the value of a key that already exists
            @param return : none
    +-------------------------------------+
    */
    public function replace($key = NULL, $value = NULL, $expiration = NULL)
    {
        $key =GB_CITY.$key;
        $this->auto_connect();

        if(is_null($expiration))
        {
            $expiration = $this->config['config']['expiration'];
        }
        if(is_array($key))
        {
            foreach($key as $multi)
            {
                if(!isset($multi['expiration']) || $multi['expiration'] == '')
                {
                    $multi['expiration'] = $this->config['config']['expiration'];
                }
                $this->replace($multi['key'], $multi['value'], $multi['expiration']);
            }
        }
        else
        {
            $this->local_cache[$this->key_name($key)] = $value;

            switch($this->client_type)
            {
                case 'Memcache':
                    $replace_status = $this->m->replace($this->key_name($key), $value, $this->config['config']['compression'], $expiration);
                    break;

                default:
                case 'Memcached':
                    $replace_status = $this->m->replace($this->key_name($key), $value, $expiration);
                    break;
            }

            return $replace_status;
        }
    }

    /*
    +-------------------------------------+
            Name: flush
            Purpose: flushes all items from cache
            @param return : none
    +-------------------------------------+
    */
    public function flush()
    {
        $this->auto_connect();

        return $this->m->flush();
    }

    /*
    +-------------------------------------+
            Name: getversion
            Purpose: Get Server Vesion Number
            @param Returns a string of server version number or FALSE on failure. 
    +-------------------------------------+
    */
    public function getversion()
    {
        $this->auto_connect();

        return $this->m->getVersion();
    }

    /*
    +-------------------------------------+
            Name: getstats
            Purpose: Get Server Stats
            Possible: "reset, malloc, maps, cachedump, slabs, items, sizes"
            @param returns an associative array with server's statistics. Array keys correspond to stats parameters and values to parameter's values.
    +-------------------------------------+
    */
    public function getstats($type="items")
    {
        $this->auto_connect();

        switch($this->client_type)
        {
            case 'Memcache':
                $stats = $this->m->getStats($type);
                break;

            default:
            case 'Memcached':
                $stats = $this->m->getStats();
                break;
        }
        return $stats;
    }

    /*
    +-------------------------------------+
            Name: setcompresstreshold
            Purpose: Set When Automatic compression should kick-in
            @param return TRUE/FALSE
    +-------------------------------------+
    */
    public function setcompressthreshold($tresh, $savings=0.2)
    {
        $this->auto_connect();

        switch($this->client_type)
        {
            case 'Memcache':
                $setcompressthreshold_status = $this->m->setCompressThreshold($tresh, $savings=0.2);
                break;

            default:
                $setcompressthreshold_status = TRUE;
                break;
        }
        return $setcompressthreshold_status;
    }


    /*
    +-------------------------------------+
            Name: key_name
            Purpose: standardizes the key names for memcache instances
            @param return : md5 key name
    +-------------------------------------+
    */
    private function key_name($key)
    {
        return md5(strtolower($this->config['config']['prefix'].$key));
    }


    public function close()
    {
        if($this->client_type=='Memcache')
        {
            $this->m->close();
        }

    }
}

/* End of file memcached_library.php */
/* Location: ./application/libraries/memcached_library.php */