<?php

/*
 * This file is part of the Keygen package.
 *
 * (c) Glad Chinda <gladxeqs@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Keygen\Traits;

use BadMethodCallException;
use InvalidArgumentException;

trait KeyManipulation
{
	use IntegerCasting;

	/**
	 * Length of keys to be generated by the generator.
	 * 
	 * @var int
	 */
	protected $length;

	/**
	 * Key prefix.
	 * 
	 * @var string
	 */
	protected $prefix;

	/**
	 * Key suffix.
	 * 
	 * @var string
	 */
	protected $suffix;

	/**
	 * Propagates property mutation to listed mutable generators.
	 * 
	 * @param string $prop
	 * @param bool $propagate
	 * @return $this
	 */
	protected function propagateMutation($prop, $propagate)
	{
		$propagate = !is_bool($propagate) ? true : $propagate;

		if ($propagate && isset($this->mutates)) {

			foreach ($this->mutates as $obj) {

				if (in_array($prop, $obj->mutables)) {
					call_user_func(array($obj, $prop), $this->{$prop});
				}

			}

		}

		return $this;
	}

	/**
	 * Sets the length of keys to be generated by the generator.
	 * 
	 * @param numeric $length
	 * @param bool $propagate
	 * @return $this
	 * 
	 * @throws \InvalidArgumentException
	 */
	protected function length($length, $propagate = true)
	{
		$this->length = $this->intCast($length ?: $this->length);
		return $this->propagateMutation('length', $propagate);
	}

	/**
	 * Affixes string to generated keys.
	 * 
	 * @param string $affix Affix type (either 'prefix' or 'suffix')
	 * @param string $value
	 * @param bool $propagate
	 * @return $this
	 * 
	 * @throws \InvalidArgumentException
	 */
	protected function affix($affix, $value, $propagate = true)
	{
		$affixes = ['prefix', 'suffix'];

		if (in_array($affix, $affixes)) {

			if (is_scalar($value)) {
				$this->{$affix} = strval($value);
				return $this->propagateMutation($affix, $propagate);
			}

			throw new InvalidArgumentException("The given {$affix} cannot be converted to a string.");

		}
	}

	/**
	 * Prepends string to generated keys.
	 * 
	 * @param string $prefix
	 * @param bool $propagate
	 * @return $this
	 * 
	 * @throws \InvalidArgumentException
	 */
	protected function prefix($prefix, $propagate = true)
	{
		return $this->affix('prefix', $prefix, $propagate);
	}

	/**
	 * Appends string to generated keys.
	 * 
	 * @param string $suffix
	 * @param bool $propagate
	 * @return $this
	 * 
	 * @throws \InvalidArgumentException
	 */
	protected function suffix($suffix, $propagate = true)
	{
		return $this->affix('suffix', $suffix, $propagate);
	}

	/**
	 * Gets the key length less the prefix length and suffix length.
	 * 
	 * @return int
	 */
	protected function getAdjustedKeyLength()
	{
		return $this->length - intval(strlen($this->prefix) + strlen($this->suffix));
	}

	/**
	 * Overload helper for internal method calls.
	 * 
	 * @param string $method
	 * @param array $args
	 * @return $this
	 * 
	 * @throws \BadMethodCallException
	 */
	protected function __overloadMethods($method, $args)
	{
		$_method = strtolower($method);

		if (in_array($_method, ['prefix', 'suffix'])) {
			return call_user_func_array(array($this, 'affix'), array_merge([$_method], $args));
		}

		if ($_method == 'length') {
			return call_user_func_array(array($this, 'length'), $args);
		}

		throw new BadMethodCallException(sprintf("Call to unknown method %s::%s()", get_called_class(), $method));
	}
}
