<?php

###############################################################################
#
# Mapped Array
#
# A class similar to HashedArray and made according to its templates, but
# improved in the following:
# - works with both objects and arrays;
# - an additional replace() method allows you to replace an element in an array;
# - the constructor allows you to specify the name of the method or the key of
#   the array of stored elements, and also indicate the type of stored
#   elements (objects or assoc. arrays);
#
# Author: Brigadir (forum.mydune.ru)
# Date: 09-12-2018
# Latest update: 12-04-2020
#
###############################################################################

class MappedArray implements Iterator
{

    ///////////////////////////////////////////////////////////////////////////

    protected $seq;
    protected $map;
    protected $pos;
    protected $key;
    protected $assoc;

    ///////////////////////////////////////////////////////////////////////////

    public function __construct($key = 'get_id', $assoc = false)
    {
        $this->seq = array();
        $this->map = array();
        $this->pos = 0;
        $this->key = $key;
        $this->assoc = $assoc;
    }

    public function size()
    {
        return count($this->seq);
    }

    public function get_by_ndx($ndx)
    {
        return $this->seq[$ndx];
    }

    public function get($key)
    {
        return isset($this->map[$key])? $this->seq[$this->map[$key]] : null;
    }

    public function put($o)
    {
    	$idx = $this->size();
        $this->seq[$idx] = $o;
        $this->map[$this->assoc? $o[$this->key] : $o->{"$this->key"}()] = $idx;
    }

    public function replace($o)
    {
    	$id = $this->assoc? $o[$this->key] : $o->{"$this->key"}();
        foreach ($this->seq as $key => $so) {
        	$sid = $this->assoc? $so[$this->key] : $so->{"$this->key"}();
			if ($id == $sid) {
				$this->seq[$key] = $o;
				break;
			}
        }
    }

    public function has($key)
    {
        return isset($this->map[$key]);
    }

    ///////////////////////////////////////////////////////////////////////

    public function usort($callback_name)
    {
    	usort($this->seq, $callback_name);

    	$this->map = array();
    	foreach ($this->seq as $idx => $o) {
			$this->map[$this->assoc? $o[$this->key] : $o->{"$this->key"}()] = $idx;
    	}
    }

    ///////////////////////////////////////////////////////////////////////

    public function rewind()
    {
        $this->pos = 0;
    }

    public function current()
    {
        return $this->seq[$this->pos];
    }

    public function key()
    {
    	return $this->assoc? $this->seq[$this->pos][$this->key] : $this->seq[$this->pos]->{"$this->key"}();
    }

    public function next()
    {
        ++$this->pos;
    }

    public function valid()
    {
        return $this->pos < count($this->seq);
    }
}

?>
