<?php

declare(strict_types=1);

/*
 * This file is part of dacore bundle for Contao.
 *
 * (c) Benjamin Roth
 *
 * @license commercial
 */

namespace vossmedien\DacoreBundle\Generator;

class CodeGenerator
{
    /**
     * Seed presets
     */
    public const SEED_NUMERIC = 1;
    public const SEED_LETTERS_LOWER = 2;
    public const SEED_LETTERS_UPPER = 4;
    public const SEED_SYMBOLS = 8;

    public const SEED_READABLE = 5;
    public const SEED_LETTERS_MIXED = 6;
    public const SEED_SECURE = 15;


    /**
     * Generate a code
     *
     * @param array $arrOptions
     * @return string
     */
    public function generate($arrOptions = [])
    {
        $arrOptions = array_merge
        (
            array
            (
                'length'      => 12, // ToDo: Retrieve default length from global settings
                'seed_preset' => self::SEED_SECURE,
                'custom_seed' => null,
                'prefix'      => '',
                'suffix'      => '',
            ),$arrOptions
        );


        if (intval($arrOptions['length']) < 5)
        {
            throw new \InvalidArgumentException('The length option has to be at least 5.');
        }

        // Seed presets
        $numbers     = [1,2,3,4,5,6,7,8,9];
        $lowercase   = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
        $uppercase   = ['A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z'];
        $symbols     = ['°','!','§','$','%','&','/','(',')','=','?','*','+','~','#','-','_','.',':',';','>','<','|','[',']','{','}','\\'];

        $seed = [];
        $code = '';

        // Use custom seed
        if ($arrOptions['custom_seed'] !== null)
        {
            if (is_array($arrOptions['custom_seed']))
            {
                $seed = $arrOptions['custom_seed'];
            } elseif (is_string($arrOptions['custom_seed']))
            {
                $seed = str_split($arrOptions['custom_seed'],1);
            } else {
                throw new \InvalidArgumentException('The custom_seed option needs to be an array or string.');
            }
        } else
        {
            // Add numbers to seed
            if ($arrOptions['seed_preset'] & self::SEED_NUMERIC)
            {
                $seed = array_merge($seed, $numbers, $numbers); // add numbers twice to increase their occurrence in generated code
            }

            // Add lowercase letters to seed
            if ($arrOptions['seed_preset'] & self::SEED_LETTERS_LOWER)
            {
                $seed = array_merge($seed, $lowercase);
            }

            // Add uppercase letters to seed
            if ($arrOptions['seed_preset'] & self::SEED_LETTERS_UPPER)
            {
                $seed = array_merge($seed, $uppercase);
            }

            // Add symbols to seed
            if ($arrOptions['seed_preset'] & self::SEED_SYMBOLS)
            {
                $seed = array_merge($seed, $symbols);
            }
        }

        // Generate random code string
        for ($i = 0; $i < intval($arrOptions['length']); $i++) {
            $code .= substr(strval($seed[mt_rand(0, count($seed) - 1)]),0,1);
        }

        // Add optional prefix
        if ($arrOptions['prefix'])
        {
            $code = $arrOptions['prefix'].$code;
        }

        // Add optional suffix
        if ($arrOptions['suffix'])
        {
            $code = $arrOptions['suffix'].$code;
        }

        return $code;
    }

}