<?php

namespace Guardian\User\Caller;

use Assert\Assertion;
use Guardian\Caller\HasLoginToken;
use Guardian\User\Caller;

/**
 * Simple user caller
 *
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 */
class User implements Caller, HasLoginToken, \ArrayAccess
{
    /**
     * @var string|integer
     */
    protected $id;

    /**
     * @var array
     */
    protected $data;

    /**
     * @param string|integer $id
     * @param array          $data
     */
    public function __construct($id, $data)
    {
        // TODO: check for id's type
        Assertion::choicesNotEmpty($data, ['username', 'password']);

        $this->id = $id;
        $this->data = $data;
    }

    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * {@inheritdoc}
     */
    public function getLoginToken()
    {
        return $this->id;
    }

    /**
     * {@inheritdoc}
     */
    public function getUsername()
    {
        return $this->data['username'];
    }

    /**
     * {@inheritdoc}
     */
    public function getPassword()
    {
        return $this->data['password'];
    }

    /**
     * Returns dynamic properties passed to the object
     *
     * Notice: property names should be camelCased
     *
     * @param string $method
     * @param array  $arguments
     *
     * @return mixed
     *
     * @throws BadMethodCallException If $method is not a property
     */
    public function __call($method, array $arguments)
    {
        if (substr($method, 0, 3) === 'get' and $property = substr($method, 3)) {
            $property = lcfirst($property);
            Assertion::notEmptyKey($this->data, $property, 'User does not have a(n) "%s" property');

            return $this->data[$property];
        }

        throw new \BadMethodCallException(sprintf('Method "%s" does not exists', $method));
    }

    /**
     * {@inheritdoc}
     */
    public function offsetSet($offset, $value)
    {
        if (is_null($offset)) {
            $this->data[] = $value;
        } else {
            $this->data[$offset] = $value;
        }
    }

    /**
     * {@inheritdoc}
     */
    public function offsetExists($offset)
    {
        return isset($this->data[$offset]);
    }

    /**
     * {@inheritdoc}
     */
    public function offsetUnset($offset)
    {
        if (isset($this->data[$offset])) {
            unset($this->data[$offset]);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function offsetGet($offset)
    {
        if (isset($this->data[$offset])) {
            return $this->data[$offset];
        }
    }
}
