<?php

/**
 * @see       https://github.com/laminas/laminas-console for the canonical source repository
 * @copyright https://github.com/laminas/laminas-console/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-console/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Console\Prompt;

class Char extends AbstractPrompt
{
    /**
     * @var string
     */
    protected $promptText;

    /**
     * @var bool
     */
    protected $allowEmpty;

    /**
     * @var string
     */
    protected $allowedChars;

    /**
     * @var bool
     */
    protected $ignoreCase;

    /**
     * @var bool
     */
    protected $echo;

    /**
     * Ask the user for a single key stroke
     *
     * @param string $promptText   The prompt text to display in console
     * @param string $allowedChars A list of allowed chars (i.e. "abc12345")
     * @param bool   $ignoreCase   If true, case will be ignored and prompt will always return lower-cased response
     * @param bool   $allowEmpty   Is empty response allowed?
     * @param bool   $echo         Display the selection after user presses key
     */
    public function __construct(
        $promptText = 'Please hit a key',
        $allowedChars = '0123456789abcdefghijklmnopqrstuvwxyz',
        $ignoreCase = true,
        $allowEmpty = false,
        $echo = true
    ) {
        $this->setPromptText($promptText);
        $this->setAllowEmpty($allowEmpty);
        $this->setIgnoreCase($ignoreCase);

        if (null != $allowedChars) {
            if ($this->ignoreCase) {
                $this->setAllowedChars(strtolower($allowedChars));
            } else {
                $this->setAllowedChars($allowedChars);
            }
        }

        $this->setEcho($echo);
    }

    /**
     * Show the prompt to user and return a single char.
     *
     * @return string
     */
    public function show()
    {
        $this->getConsole()->write($this->promptText);
        $mask = $this->getAllowedChars();

        /*
         * Normalize the mask if case is irrelevant
         */
        if ($this->ignoreCase) {
            $mask = strtolower($mask);    // lowercase all
            $mask .= strtoupper($mask);   // uppercase and append
            $mask = str_split($mask);     // convert to array
            $mask = array_unique($mask);  // remove duplicates
            $mask = implode('', $mask);   // convert back to string
        }

        /*
         * Read char from console
         */
        $char = $this->getConsole()->readChar($mask);

        if ($this->echo) {
            $this->getConsole()->writeLine(trim($char));
        } else {
            if ($this->promptText) {
                $this->getConsole()->writeLine();  // skip to next line but only if we had any prompt text
            }
        }

        return $this->lastResponse = $char;
    }

    /**
     * @param bool $allowEmpty
     */
    public function setAllowEmpty($allowEmpty)
    {
        $this->allowEmpty = (bool) $allowEmpty;
    }

    /**
     * @return bool
     */
    public function getAllowEmpty()
    {
        return $this->allowEmpty;
    }

    /**
     * @param string $promptText
     */
    public function setPromptText($promptText)
    {
        $this->promptText = $promptText;
    }

    /**
     * @return string
     */
    public function getPromptText()
    {
        return $this->promptText;
    }

    /**
     * @param string $allowedChars
     */
    public function setAllowedChars($allowedChars)
    {
        $this->allowedChars = $allowedChars;
    }

    /**
     * @return string
     */
    public function getAllowedChars()
    {
        return $this->allowedChars;
    }

    /**
     * @param bool $ignoreCase
     */
    public function setIgnoreCase($ignoreCase)
    {
        $this->ignoreCase = (bool) $ignoreCase;
    }

    /**
     * @return bool
     */
    public function getIgnoreCase()
    {
        return $this->ignoreCase;
    }

    /**
     * @param bool $echo
     */
    public function setEcho($echo)
    {
        $this->echo = (bool) $echo;
    }

    /**
     * @return bool
     */
    public function getEcho()
    {
        return $this->echo;
    }
}
