<?php

namespace Illuminate\Console;

use Illuminate\Support\Str;
use InvalidArgumentException;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
// my name space
class Parser
{
    /**
     * Parse the given console command definition into an array.
     *
     * @param  string  $expression
     * @return array
     *
     * @throws \InvalidArgumentException
     */
    public static function parse($expression)//Parse the given console command definition into array.
    {
        if (trim($expression) === '') {
            throw new InvalidArgumentException('Console command definition is empty.');
        }// trim the expression ,if have the null
       // throw new

        preg_match('/[^\s]+/', $expression, $matches);// get you  want value in the big date.

        if (isset($matches[0])) {// is has the match value ,only get one
            $name = $matches[0];// use the name to save the matches[0] value
        } else {
            throw new InvalidArgumentException('Unable to determine command name from signature.');
        }// else throw new trouble.

        preg_match_all('/\{\s*(.*?)\s*\}/', $expression, $matches);// get all the value that be match

        $tokens = isset($matches[1]) ? $matches[1] : [];// $tokens check the matches

        if (count($tokens)) {// count($tokens) count array(); this is the matches results
            return array_merge([$name], static::parameters($tokens));// array_merge  parameters ,change the parameters
        }

        return [$name, [], []];// return the result
    }// this is  a change the
   // the $name to

    /**
     * Extract all of the parameters from the tokens.
     *
     * @param  array  $tokens
     * @return array
     */
    protected static function parameters(array $tokens)//Extract all of the parameters from the tokens.
    {
        $arguments = [];// store the arguments

        $options = [];// store the options

        foreach ($tokens as $token) {// all the tokens as token
            if (! Str::startsWith($token, '--')) {// !Str::starsWith() get the true of false
                $arguments[] = static::parseArgument($token);//
            } else {
                $options[] = static::parseOption(ltrim($token, '-'));// get the options
            }
        }

        return [$arguments, $options];// back the result from tokens
    }// one is arguments,
   // one is options

    /**
     * Parse an argument expression.
     *
     * @param  string  $token
     * @return \Symfony\Component\Console\Input\InputArgument
     */
    protected static function parseArgument($token)//Parse an argument expression.
    {
        $description = null;// a store string

        if (Str::contains($token, ' : ')) {// a function to get the token get the result true or false
            list($token, $description) = explode(' : ', $token, 2);// extract the list array to the token and description

            $token = trim($token);// trim the token

            $description = trim($description);// trim the description
        }

        switch (true) {// true is value , and the value no break
            case Str::endsWith($token, '?*'):// case 1 set the flag
                return new InputArgument(trim($token, '?*'), InputArgument::IS_ARRAY, $description);

            case Str::endsWith($token, '*'):// case 2 set the flag
                return new InputArgument(trim($token, '*'), InputArgument::IS_ARRAY | InputArgument::REQUIRED, $description);

            case Str::endsWith($token, '?'):// case 3 set the flag
                return new InputArgument(trim($token, '?'), InputArgument::OPTIONAL, $description);

            case preg_match('/(.+)\=(.+)/', $token, $matches):// case 4 more different matches
                return new InputArgument($matches[1], InputArgument::OPTIONAL, $description, $matches[2]);

            default:
                return new InputArgument($token, InputArgument::REQUIRED, $description);
        }// change the InputArgument value
    }

    /**
     * Parse an option expression.
     *
     * @param  string  $token
     * @return \Symfony\Component\Console\Input\InputOption
     */
    protected static function parseOption($token)//Parse an option expression
    {
        $description = null;// ParseOption

        if (Str::contains($token, ' : ')) {// check the str
            list($token, $description) = explode(' : ', $token);// list the each()
            $token = trim($token);
            $description = trim($description);
        }// back the token description

        $shortcut = null;// null shortcut

        $matches = preg_split('/\s*\|\s*/', $token, 2);// split the str by preg.

        if (isset($matches[1])) {
            $shortcut = $matches[0];
            $token = $matches[1];
        }// get the value from the token

        switch (true) {
            case Str::endsWith($token, '='):// case 1
                return new InputOption(trim($token, '='), $shortcut, InputOption::VALUE_OPTIONAL, $description);

            case Str::endsWith($token, '=*'):// case 2
                return new InputOption(trim($token, '=*'), $shortcut, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, $description);

            case preg_match('/(.+)\=(.+)/', $token, $matches):
                return new InputOption($matches[1], $shortcut, InputOption::VALUE_OPTIONAL, $description, $matches[2]);

            default:
                return new InputOption($token, $shortcut, InputOption::VALUE_NONE, $description);
        }// input Option

    }// at last you will found is a safe way to get you  input argument or option from a token
}