<?php

class SetupCommon
{
    public static function setTpl($path)
    {
        return new Template(Storage::get($path), new ACMS_Corrector());
    }

    public static function getTpl($Tpl)
    {
        $resource = $Tpl->get();

        $pair = [
            '[*PHP_VERSION*]' => PHP_VERSION,
            '[*VERSION*]' => VERSION,
            '[*HTTP_HOST*]' => HTTP_HOST,
            '[*DOMAIN*]' => DOMAIN,
            '[*DB_HOST*]' => DB_HOST,
            '[*DB_NAME*]' => DB_NAME,
            '[*DB_USER*]' => DB_USER,
            '[*DB_PASS*]' => DB_PASS,
            '[*DB_PREFIX*]' => DB_PREFIX,
            '[*DB_CHARSET*]' => DB_CHARSET,
            '[*ROOT_DIR*]' => ROOT_DIR,
            '[*HTTP_ROOT*]' => SetupCommon::fixPathSeparator(HTTP_ROOT),
            '[*SETUP_DIR*]' => SETUP_DIR,
        ];

        foreach ($pair as $search => $replace) {
            $resource = str_replace($search, $replace, $resource);
        }

        return $resource;
    }

    public static function getSequence()
    {
        return [
            'blog_id' => '1',
            'alias_id' => '0',
            'user_id' => '0',
            'category_id' => '0',
            'entry_id' => '0',
            'column_id' => '0',
            'comment_id' => '0',
            'trackback_id' => '0',
            'rule_id' => '0',
            'module_id' => '0',
            'form_id' => '0',
            'media_id' => '0',
            'role_id' => '0',
            'usergroup_id' => '0',
            'approval_id' => '0',
            'schedule_id' => '0',
            'shop_address_id' => '0',
            'system_version' => VERSION,
        ];
    }

    public static function getConfigServer()
    {
        return [
            'DOMAIN' => '',
            'DOMAIN_BASE' => '',
            '1' => 'BR',
            'DB_TYPE' => 'mysql',
            'DB_HOST' => '',
            'DB_NAME' => '',
            'DB_USER' => '',
            'DB_PASS' => '',
            'DB_PORT' => null,
            'DB_CHARSET' => 'UTF-8',
            'DB_CONNECTION_CHARSET' => null,
            'DB_PREFIX' => '',
            'DB_SLOW_QUERY_TIME' => 0.2,
            '2' => 'BR',
            'COMMENT_2' => 'GETTEXT_TYPE: fix|user|auto',
            'GETTEXT_TYPE' => 'user',
            'COMMENT_3' => 'GETTEXT_APPLICATION_RANGE: admin|login|all',
            'GETTEXT_APPLICATION_RANGE' => 'all',
            'GETTEXT_DEFAULT_LOCALE' => 'ja_JP.UTF-8',
            'GETTEXT_DOMAIN' => 'messages',
            'GETTEXT_PATH' => 'lang',
            'PROXY_BR' => 'BR',
            'COMMENT_4' => 'プロキシが入っている場合、X-Forwarded-ForヘッダーからクライアントIPアドレスを特定するため、',
            'COMMENT_5' => '信頼できるプロキシのIPを設定します。 例: xxx.xxx.xxx.xxx,yyy.yyy.yyy.yyy',
            'TRUSTED_PROXY_LIST' => '',
            'PROXY_IP_HEADER' => 'HTTP_X_FORWARDED_FOR',
            'COMMENT_6' => 'オンラインアップデート、Webhook、SNSログイン（LINE）のみ対応',
            'PROXY_PORT' => '',
            'PROXY_IP' => '',
            '3' => 'BR',
            'SSL_ENABLE' => 0,
            'FULLTIME_SSL_ENABLE' => 0,
            'COOKIE_SECURE' => 0,
            'COOKIE_HTTPONLY' => 1,
            'HOOK_ENABLE' => 0,
            'RESOLVE_PATH' => 1,
            'URL_SUFFIX_SLASH' => 1,
            'SESSION_NAME' => 'sid',
            'ACMS_HASH_NAME' => 'acms_hash',
            'REWRITE_FORCE' => 1,
            'MAX_PUBLISHES' => 3,
            'MAX_EXECUTION_TIME' => 30,
            'DEFAULT_TIMEZONE' => 'Asia/Tokyo',
            'DOCUMENT_ROOT_FORCE' => null,
            'PHP_SESSION_USE_DB' => 0,
            '4' => 'BR',
            'THEMES_DIR' => 'themes/',
            'ARCHIVES_DIR' => 'archives/',
            'MEDIA_LIBRARY_DIR' => 'media/',
            'MEDIA_STORAGE_DIR' => 'storage/',
            'CACHE_DIR' => 'cache/',
            'ARCHIVES_CACHE_SERVER' => '',
            'PHP_DIR' => 'php/',
            'JS_DIR' => 'js/',
            'IMAGES_DIR' => 'images/',
            '5' => 'BR',
            'CONFIG_FILE' => 'private/config.system.yaml',
            'CONFIG_DEFAULT_FILE' => 'private/config.system.default.yaml',
            'MIME_TYPES_FILE' => 'private/mime.types',
            'REWRITE_PATH_EXTENSION' => 'pdf|doc|docx|ppt|pptx|xls|xlsx|lzh|zip|rar',
            'ERROR_LOG_FILE' => '',
            'ASYNC_PROCESS_LOG_PATH' => '',
            'COMMENT_7' => '非同期処理でPHPパスが合わない場合に使用。例1: PHP_BINDIR . \'/php -c /path/to/php.ini\' 例2: \'C:\xampp\php\php.exe\'',
            'PHP_PROCESS_BINARY' => '',
            '6' => 'BR',
            'BID_SEGMENT' => 'bid',
            'AID_SEGMENT' => 'aid',
            'UID_SEGMENT' => 'uid',
            'CID_SEGMENT' => 'cid',
            'EID_SEGMENT' => 'eid',
            'UTID_SEGMENT' => 'utid',
            'CMID_SEGMENT' => 'cmid',
            'TBID_SEGMENT' => 'tbid',
            'KEYWORD_SEGMENT' => 'keyword',
            'TAG_SEGMENT' => 'tag',
            'FIELD_SEGMENT' => 'field',
            'ORDER_SEGMENT' => 'order',
            'ALT_SEGMENT' => 'alt',
            'TPL_SEGMENT' => 'tpl',
            'PAGE_SEGMENT' => 'page',
            'PROXY_SEGMENT' => 'proxy',
            'TRACKBACK_SEGMENT' => 'tarckback',
            'SPAN_SEGMENT' => '-',
            'ADMIN_SEGMENT' => 'admin',
            'MEDIA_FILE_SEGMENT' => 'media-download',
            'LOGIN_SEGMENT' => 'login',
            'ADMIN_RESET_PASSWORD_SEGMENT' => 'admin-reset-password',
            'ADMIN_RESET_PASSWORD_AUTH_SEGMENT' => 'admin-reset-password-auth',
            'ADMIN_TFA_RECOVERY_SEGMENT' => 'admin-tfa-recovery',
            'SIGNIN_SEGMENT' => 'signin',
            'SIGNUP_SEGMENT' => 'signup',
            'RESET_PASSWORD_SEGMENT' => 'reset-password',
            'RESET_PASSWORD_AUTH_SEGMENT' => 'reset-password-auth',
            'TFA_RECOVERY_SEGMENT' => 'tfa-recovery',
            'PROFILE_UPDATE_SEGMENT' => 'mypage/update-profile',
            'PASSWORD_UPDATE_SEGMENT' => 'mypage/update-password',
            'EMAIL_UPDATE_SEGMENT' => 'mypage/update-email',
            'TFA_UPDATE_SEGMENT' => 'mypage/update-tfa',
            'WITHDRAWAL_SEGMENT' => 'mypage/withdrawal',
            'LIMIT_SEGMENT' => 'limit',
            'DOMAIN_SEGMENT' => 'domain',
            'API_SEGMENT' => 'api',
            'IOS_APP_UA' => 'acms_iOS_app',
            '7' => 'BR',
            'COMMENT_8' => '本番運用時にDEBUG_MODEを 0 に設定して下さい',
            'DEBUG_MODE' => 0,
            'BENCHMARK_MODE' => 0
        ];
    }

    public static function fixCRLF($txt, $replace = "\x0d\x0a\x0a\x0d")
    {
        $target = ["\x0d\x0d", "\x0a\x0a", "\x0d\x0a\x0d\x0a"];
        $txt = str_replace($target, $replace, $txt);
        return $txt;
    }

    public static function fixPathSeparator($path)
    {
        if (DIRECTORY_SEPARATOR == '\\') {
            return implode('/', explode('\\', $path));
        } else {
            return $path;
        }
    }

    public static function rebuildConfig($replace = null)
    {
        if (!is_array($replace) && !empty($replace)) {
            return false;
        }

        $defines = SetupCommon::getConfigServer();

        /*$EOL = PHP_EOL;*/
        // PHP_EOL is already initialized by Setup::initialize method.
        $EOL = "\r\n";

        $config = '<?php' . $EOL . $EOL;

        foreach ($defines as $def => $val) {
            if ($val === 'BR') {
                $config .= $EOL;
            } elseif (preg_match('/^COMMENT_\d/', $def)) {
                $config .= '// ' . $val . $EOL;
            } else {
                if (!defined($def)) {
                    define($def, $val);
                }
                $const = constant($def);
                if (is_bool($const)) {
                    $const = $const ? 1 : 0;
                }
                if (!empty($replace[$def])) {
                    $const = $replace[$def];
                }
                $const = is_string($const) ? "'$const'" : $const; // fix strings
                $const = $const === null ? 'null' : $const; // fix null
                $config .= "define('$def', $const);" . $EOL; // add row
            }
        }

        $open = fopen(PATH_CONFIG, 'w+');
        $write = fwrite($open, $config);
        $close = fclose($open);

        if (empty($open) || empty($write) || empty($close)) {
            return false;
        }
        return true;
    }

    public static function checkPermission($path, $perm = '777')
    {
        if (PHP_OS === 'WIN32' || PHP_OS === 'WINNT') {
            if (!Storage::isReadable($path) || !Storage::isWritable($path)) {
                return false;
            }
        } elseif ($perm === '666') {
            if (!Storage::isReadable($path) || !Storage::isWritable($path)) {
                return false;
            }
        } elseif ($perm === '777') {
            if (!Storage::isReadable($path) || !Storage::isWritable($path) || !Storage::isExecutable($path)) {
                return false;
            }
        }
        return true;
    }

    public static function checkAlterPerm()
    {
        $DB = DB::singleton(dsn());
        $DB->setThrowException(true);
        $result = true;
        try {
            $q = "ALTER TABLE `"
                . DB_PREFIX
                . "sequence` CHANGE `sequence_system_version` `sequence_system_version` VARCHAR(32) NOT NULL";
            $res = $DB->query($q, 'exec');
            if ($res == false) {
                throw new \RuntimeException('テーブルの作成に失敗しました');
            }
        } catch (\Exception $e) {
            $result = false;
        }
        $DB->setThrowException(false);
        return $result;
    }

    public static function initEntryHash($bid)
    {
        $DB = DB::singleton(dsn());

        /*
         * get SYSTEM_GENERATE_DATETIME
         */
        $SQL = SQL::newSelect('blog');
        $SQL->addSelect('blog_generated_datetime');
        $SQL->addWhereOpr('blog_parent', 0);
        $SQL->setLimit(1);
        $gen = $DB->query($SQL->get(dsn()), 'one');

        /*
         * get ENTRY_LIST
         */
        $SQL = SQL::newSelect('entry');
        $SQL->addWhereOpr('entry_blog_id', $bid);
        $q = $SQL->get(dsn());
        $DB->query($q, 'fetch');

        /*
         * update ENTRY_HASH
         */
        $sec = 0;
        while ($row = $DB->fetch($q)) {
            $sec += rand(0, 60);
            $posted = date('Y-m-d H:i:s', mktime(
                intval(date('H')),
                intval(date('i')),
                intval($sec),
                intval(date('m')),
                intval(date('d')),
                intval(date('Y'))
            ));
            $hash = md5($gen . $posted);

            $SQL = SQL::newUpdate('entry');
            $SQL->addUpdate('entry_posted_datetime', $posted);
            $SQL->addUpdate('entry_hash', $hash);
            $SQL->addWhereOpr('entry_id', $row['entry_id']);
            $DB->query($SQL->get(dsn()), 'exec');
        }
    }

    public static function themeParser($theme)
    {
        if (!preg_match('@^(.*?)\[(.*)\]$@', $theme, $matches)) {
            return ['key' => null, 'val' => $theme];
        }

        $root = $matches[1];
        $token = $matches[2];

        $themeTree[$root] = [];

        $children = preg_split('@\|@', $token);
        $store = [];
        $right = false;
        $left = false;

        // parse level +1
        foreach ($children as $child) {
            $l = substr_count($child, '[');
            $r = substr_count($child, ']');

            /*add detection*/
            if (($r - $l) != 0 && !empty($store)) {
                end($store);
                list($key, $val) = $store[0]; // @phpstan-ignore-line
                reset($store);

                if ($right === true) {
                    $store[$key] = $val . '|' . $child;
                    $right = false;
                } elseif ($left === true) {
                    $store[$key] = $child . '|' . $val;
                    $left = false;
                } else {
                    $store[] = $child;
                }
            } else {
                $store[] = $child;
            }

            if ($l > $r) {
                $right = true;
            }
            if ($r < $l) {
                $left = true;
            }

            /*reset*/
            $end = end($store);
            $_l = substr_count($end, '[');
            $_r = substr_count($end, ']');
            if ($_l === $_r) {
                $right = false;
                $left = false;
            }
        }

        // recursive
        $axis = [];
        foreach ($store as $child) {
            $res = SetupCommon::themeParser($child);
            if ($res['key'] == null) {
                $axis[] = $res['val'];
            } else {
                $axis[$res['key']] = $res['val'];
            }
        }

        return ['key' => $root, 'val' => $axis];
    }
}
