<?PHP
/**
 * Provides type-safe overrides of default PHP functions.
 */
declare(strict_types = 1);

/**
 * Standard class providing overrides of default PHP functions as static
 * functions.
 */
class MD_STD {

    /**
     * Wrapper around file_get_contents, that provides catches errors on it and returns
     * with type safety.
     *
     * @param string $filename Filepath of the file to read.
     *
     * @return string
     */
    public static function file_get_contents(string $filename):string {

        if (substr($filename, 0, 4) !== 'http' && !file_exists($filename)) {
            throw new MDFileDoesNotExist("There is no file {$filename}");
        }

        $contents = file_get_contents($filename);

        if (is_bool($contents)) {
            throw new MDFileIsNotReadable("File {$filename} is not readable");
        }

        return $contents;

    }

    /**
     * Returns the real path of a relative file path. Throws an error rather than
     * returning the default false.
     *
     * @param string $path File path to convert.
     *
     * @return string
     */
    public static function realpath(string $path):string {

        $output = realpath($path);
        if (!is_string($output)) throw new MDFileDoesNotExist("The file {$path} does not exist or is not readable.");
        return $output;

    }

    /**
     * Gets contents of a folder.
     *
     * @param string $filepath Directory path.
     *
     * @return array<string>
     */
    public static function scandir(string $filepath):array {

        if (!is_dir($filepath) || ($output = scandir($filepath)) === false) {
            throw new MDFileDoesNotExist("There is no file {$filepath}");
        }

        return array_values(array_diff($output, ['.', '..']));

    }

    /**
     * Type safe wrapper around ob_get_clean():  Gets the current buffer
     * contents and delete current output buffer.
     *
     * @return string
     */
    public static function ob_get_clean():string {

        $output = ob_get_clean();
        if ($output === false) throw new MDOutputBufferNotStarted("Output buffer was not started");
        return $output;

    }

    /**
     * Function checking if a string starts with another.
     *
     * @param string $haystack String to check.
     * @param string $needle   Potential start of $haystack.
     *
     * @return boolean
     */
    public static function startsWith(string $haystack, string $needle):bool {

        if (substr($haystack, 0, strlen($needle)) == $needle) return true;
        else return false;

    }

    /**
     * Function checking if a string starts with any input from the input array.
     *
     * @param string   $haystack String to check.
     * @param string[] $needles  Array containing potential start values of $haystack.
     *
     * @return boolean
     */
    public static function startsWithAny(string $haystack, array $needles):bool {

        $output = false;
        foreach ($needles as $needle) {
            $output = self::startsWith($haystack, $needle);
            if ($output == true) return $output;
        }
        return $output;

    }

}