/**
 * 
 * 
 * @param int $argc
 * @param array $argv
 * 
 * @return void
 * 
 * @throws \InvalidArgumentException
 * @throws \RuntimeException if this function is called in a script that is not run at the command line.
 */
function createController($argc, array $argv)
{
    //////////////////////////////////////////
    // START: Environment and Args Validation
    //////////////////////////////////////////
    if (!isPhpRunningInCliMode()) {
        $err_msg = '`' . __FUNCTION__ . '($argc, array $argv)` should only be called from within' . ' php scripts that should be run via the command line!!!' . PHP_EOL;
        throw new \RuntimeException($err_msg);
    }
    if (is_string($argc) && is_numeric($argc)) {
        $argc = (int) $argc;
    }
    if (!is_int($argc)) {
        $err_msg = 'The expected value for the first argument to ' . '`' . __FUNCTION__ . '($argc, array $argv)` should be an int.' . ' `' . ucfirst(gettype($argc)) . '` with the value below was supplied:' . PHP_EOL . var_export($argc, true) . PHP_EOL . PHP_EOL . 'Good bye!!!';
        throw new \InvalidArgumentException($err_msg);
    }
    if (count($argv) < 1) {
        $err_msg = 'The expected value for the second argument to ' . '`' . __FUNCTION__ . '($argc, array $argv)` should be an array with at least one element. Empty Array was supplied.' . 'This second argument is expected to be the $argv array passed by PHP to the script calling this function.';
        throw new \InvalidArgumentException($err_msg);
    }
    //////////////////////////////////////////
    // END: Environment and Args Validation
    //////////////////////////////////////////
    //////////////////////////////////
    ///START: COMMAND PROCESSING
    //////////////////////////////////
    $ds = DIRECTORY_SEPARATOR;
    if ($argc < 5 || in_array('--help', $argv) || in_array('-help', $argv) || in_array('-h', $argv) || in_array('-?', $argv)) {
        displayHelp(basename($argv[0]));
    } else {
        if ($argc === 5 && (in_array('--controller-name', $argv) || in_array('-c', $argv)) && (in_array('--path-to-src-folder', $argv) || in_array('-p', $argv)) || $argc >= 7 && (in_array('--controller-name', $argv) || in_array('-c', $argv)) && (in_array('--path-to-src-folder', $argv) || in_array('-p', $argv)) && (in_array('--extends-controller', $argv) || in_array('-e', $argv))) {
            $templates_dir = dirname(__DIR__) . $ds . 'templates' . $ds;
            $controller_name = getOptVal('--controller-name', $argv);
            if ($controller_name === false) {
                $controller_name = getOptVal('-c', $argv);
            }
            $studly_controller_name = \Slim3MvcTools\Functions\Str\dashesToStudly(\Slim3MvcTools\Functions\Str\underToStudly($controller_name));
            $dashed_controller_name = \Slim3MvcTools\Functions\Str\toDashes($controller_name);
            if (!isValidClassName($studly_controller_name)) {
                printError("Invalid controller class name `{$controller_name}` supplied. Goodbye!!");
                return;
            }
            $src_folder_path = getOptVal('--path-to-src-folder', $argv);
            if ($src_folder_path === false) {
                $src_folder_path = getOptVal('-p', $argv);
            }
            $src_folder_path = normalizeFolderPathForOs($src_folder_path);
            if (!file_exists($src_folder_path) || !is_dir($src_folder_path)) {
                printError("The src folder path `{$src_folder_path}` supplied is a non-existent directory. Goodbye!!");
                return;
            }
            ////////////////////////////////////////////////////////////////////////////
            $default_controller_2_extend = '\\Slim3MvcTools\\Controllers\\BaseController';
            $controller_2_extend = getOptVal('--extends-controller', $argv);
            if ($controller_2_extend === false) {
                $controller_2_extend = getOptVal('-e', $argv);
                if ($controller_2_extend !== false) {
                    if (!isValidExtendsClassName($controller_2_extend)) {
                        printError("Invalid controller class name `{$controller_2_extend}` for extension supplied. Goodbye!!");
                        return;
                    }
                } else {
                    //use default controller class to be extended
                    $controller_2_extend = $default_controller_2_extend;
                }
            } else {
                if (!isValidExtendsClassName($controller_2_extend)) {
                    printError("Invalid controller class name `{$controller_2_extend}` for extension supplied. Goodbye!!");
                    return;
                }
            }
            ////////////////////////////////////////////////////////////////////////////
            $namepace_declaration = '';
            //omit namespace declaration by default
            $namepace_4_controller = getOptVal('--namespace-4-controller', $argv);
            if ($namepace_4_controller === false) {
                $namepace_4_controller = getOptVal('-n', $argv);
                if ($namepace_4_controller !== false) {
                    if (!isValidNamespaceName($namepace_4_controller)) {
                        printError("Invalid namespace `{$namepace_4_controller}` supplied. Goodbye!!");
                        return;
                    }
                    //validation passed
                    $namepace_declaration = "namespace {$namepace_4_controller};";
                } else {
                    $namepace_4_controller = '';
                }
            } else {
                if (!isValidNamespaceName($namepace_4_controller)) {
                    printError("Invalid namespace `{$namepace_4_controller}` supplied. Goodbye!!");
                    return;
                }
                //validation passed
                $namepace_declaration = "namespace {$namepace_4_controller};";
            }
            //read template controller and substitute __TEMPLTATE_CONTROLLER__ with given controller name \Slim3MvcTools\Functions\Str\underToStudly(dashesToStudly($controller_name_from_cli))
            //substitute {{TEMPLTATE_CONTROLLER_VIEW_FOLDER}} with the view folder name \Slim3MvcTools\Functions\Str\toDashes($controller_name_from_cli)
            //write processed controller file to S3MVC_APP_ROOT_PATH.$ds.'src'.$ds.'controllers'.$ds
            //make the dir S3MVC_APP_ROOT_PATH.$ds.'src'.$ds.'views'.$ds.\Slim3MvcTools\Functions\Str\toDashes($controller_name_from_cli)
            //read template controller index view and substitute __TEMPLTATE_CONTROLLER__ with given controller name \Slim3MvcTools\Functions\Str\underToStudly(dashesToStudly($controller_name_from_cli))
            //write processed controller file to S3MVC_APP_ROOT_PATH.$ds.'src'.$ds.'views'.$ds.\Slim3MvcTools\Functions\Str\toDashes($controller_name_from_cli)
            $template_controller_file = $templates_dir . 'controller-class-template.php.tpl';
            $dest_controller_class_file_folder = $src_folder_path . 'controllers' . $ds;
            $dest_controller_class_file = $dest_controller_class_file_folder . "{$studly_controller_name}.php";
            if (!file_exists($dest_controller_class_file_folder) && !mkdir($dest_controller_class_file_folder, 0775, true)) {
                printError("Failed to create `{$dest_controller_class_file_folder}`; the folder supposed to contain the controller named `{$studly_controller_name}`. Goodbye!!");
                return;
            }
            $template_view_file = $templates_dir . 'index-view-template.php';
            $dest_view_file_folder = $src_folder_path . 'views' . $ds . "{$dashed_controller_name}{$ds}";
            $dest_view_file = "{$dest_view_file_folder}index.php";
            if (!file_exists($dest_view_file_folder) && !mkdir($dest_view_file_folder, 0775, true)) {
                printError("Failed to create `{$dest_view_file_folder}`; the folder supposed to contain views for the controller named `{$studly_controller_name}`. Goodbye!!");
                return;
            }
            if (file_exists($dest_controller_class_file)) {
                printError("Controller class `{$studly_controller_name}` already exists in `{$dest_controller_class_file}`. Goodbye!!");
                return;
            }
            if (file_exists($dest_view_file)) {
                printError("View file `{$dest_view_file}` already exists for Controller class `{$studly_controller_name}`. Goodbye!!");
                return;
            }
            printInfo("Creating Controller Class `{$studly_controller_name}` in `{$dest_controller_class_file}` ....");
            ////////////////////////////////////////////////////////////////////////////
            $replaces = ['__CONTROLLER_2_EXTEND__' => $controller_2_extend, '__TEMPLTATE_CONTROLLER__' => $studly_controller_name, 'namespace __NAMESPACE_2_REPLACE__;' => $namepace_declaration, '{{TEMPLTATE_CONTROLLER_VIEW_FOLDER}}' => $dashed_controller_name, "'__login_success_redirect_controller__'" => "'{$dashed_controller_name}'"];
            if (processTemplateFile($template_controller_file, $dest_controller_class_file, $replaces) === false) {
                printError("Failed transforming template controller `{$template_controller_file}` to `{$dest_controller_class_file}`. Goodbye!!");
            } else {
                printInfo("Successfully created `{$dest_controller_class_file}` ...." . PHP_EOL);
            }
            printInfo("Creating index view for `{$studly_controller_name}::actionIndex()` in `{$dest_view_file}` ....");
            $replaces['__TEMPLTATE_CONTROLLER__'] = rtrim($namepace_4_controller, '\\') . '\\' . $studly_controller_name;
            if (processTemplateFile($template_view_file, $dest_view_file, $replaces) === false) {
                printError("Failed creating index view for `{$studly_controller_name}::actionIndex()` in `{$dest_view_file}`.");
                printInfo("Deleting `{$dest_controller_class_file}` ....");
                if (!unlink($dest_controller_class_file)) {
                    printInfo("Failed to delete `{$dest_controller_class_file}`. Please delete it manually. Goodbye!!");
                } else {
                    printInfo("Goodbye!!");
                }
                return;
            } else {
                printInfo("Successfully created `{$dest_view_file}` ...." . PHP_EOL);
            }
            printInfo("All done!!");
            if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
                //test if composer is avaliable only if server OS on which this script is being run
                //is not windows
                if (isCommandAvailableOnOs('composer')) {
                    passthru('composer dumpautoload');
                } else {
                    printInfo("Remember to run `composer dumpautoload` so that composer can pick up the newly created controller class `{$studly_controller_name}` in `{$dest_controller_class_file}`.");
                }
            } else {
                printInfo("Remember to run `composer dumpautoload` so that composer can pick up the newly created controller class `{$studly_controller_name}` in `{$dest_controller_class_file}`.");
            }
            //we are done
        } else {
            displayHelp(basename($argv[0]));
        }
    }
    //////////////////////////////////
    ///END: COMMAND PROCESSING
    //////////////////////////////////
}
 public function testThatNormalizeFolderPathForOsWorksAsExpected()
 {
     $path1 = __DIR__ . '/';
     $path2 = __DIR__ . '\\';
     $expected_normalized_path = __DIR__ . DIRECTORY_SEPARATOR;
     $this->assertEquals($expected_normalized_path, normalizeFolderPathForOs($path1));
     $this->assertEquals($expected_normalized_path, normalizeFolderPathForOs($path2));
     ///////////////////////////////////////////
     //Test \InvalidArgumentException messages
     ///////////////////////////////////////////
     $args = array('Integer' => 111, 'Double' => 111.1234, 'Boolean' => true, 'Array' => [], 'Object' => new stdclass(), 'NULL' => null, 'Resource' => tmpfile());
     $function_sig_in_err_msg = 'normalizeFolderPathForOs($path)';
     foreach ($args as $arg_type => $arg) {
         try {
             normalizeFolderPathForOs($arg);
             $msg = '\\InvalidArgumentException should have been thrown in `' . __FILE__ . '`' . ' on line ' . (__LINE__ - 1);
             static::fail($msg);
         } catch (\InvalidArgumentException $e) {
             $msg_substr = "The expected value for the first argument to `{$function_sig_in_err_msg}`" . " should be a String value. `{$arg_type}` with the value below was supplied:";
             $this->assertContains($msg_substr, $e->getMessage());
         }
     }
     // test the callable type
     try {
         normalizeFolderPathForOs(function () {
             echo 'blah';
         });
         $msg = '\\InvalidArgumentException should have been thrown in `' . __FILE__ . '`' . ' on line ' . (__LINE__ - 1);
         static::fail($msg);
     } catch (\InvalidArgumentException $e) {
         $msg_substr = "The expected value for the first argument to `{$function_sig_in_err_msg}`" . " should be a String value. `Object` with the value below was supplied:";
         $this->assertContains($msg_substr, $e->getMessage());
     }
 }