<?php

namespace Aws;

use HashContext;

/**
 * Incremental hashing using PHP's hash functions.
 */
class PhpHash implements HashInterface {
	/** @var resource|HashContext */
	private $context;

	/** @var string */
	private $algo;

	/** @var array */
	private $options;

	/** @var string */
	private $hash;

	/**
	 * @param string $algo Hashing algorithm. One of PHP's hash_algos()
	 *     return values (e.g. md5, sha1, etc...).
	 * @param array $options Associative array of hashing options:
	 *     - key: Secret key used with the hashing algorithm.
	 *     - base64: Set to true to base64 encode the value when complete.
	 */
	public function __construct( $algo, array $options = [] ) {
		$this->algo    = $algo;
		$this->options = $options;
	}

	public function update( $data ) {
		if ( $this->hash !== null ) {
			$this->reset();
		}

		hash_update( $this->getContext(), $data );
	}

	public function reset() {
		$this->context = $this->hash = null;
	}

	/**
	 * Get a hash context or create one if needed
	 *
	 * @return resource|HashContext
	 */
	private function getContext() {
		if ( ! $this->context ) {
			$key           = isset( $this->options['key'] ) ? $this->options['key'] : null;
			$this->context = hash_init(
				$this->algo,
				$key ? HASH_HMAC : 0,
				$key
			);
		}

		return $this->context;
	}

	public function complete() {
		if ( $this->hash ) {
			return $this->hash;
		}

		$this->hash = hash_final( $this->getContext(), true );

		if ( isset( $this->options['base64'] ) && $this->options['base64'] ) {
			$this->hash = base64_encode( $this->hash );
		}

		return $this->hash;
	}
}
