<?php

class DumpBak
{
    // 文件夹路径符
    private static $DS = '/';
    // 是否分子文件夹存储
    private static $CREATE_PHP_CONFIG_IN_CHILD_DIR = 3;
    // 是否分子文件存储
    private static $CREATE_CHILD_PHP_CONFIG = 4;

    /**
     * @var string
     */
    private $appName;

    /**
     * @var string
     */
    private $dumpName;

    /**
     * 是否需要分子目录
     *
     * @var boolean
     */
    private $needChildDir = false;

    /**
     * 是否切割配置文件
     *
     * @var boolean
     */
    private $needSplitConfig = false;

    /**
     * Dump constructor.
     *
     * @param array $argv
     */
    public function __construct($argv)
    {
        self::vd(sprintf("argv: %s", var_export($argv, true)));
        $this->appName  = $argv[1];
        $this->dumpName = $argv[2];
        if (isset($argv[3])) {
            $this->outputOption = $argv['3'];
        }

        // 初始化是否需要分子目录
        self::vd(sprintf("outputOption: %s", $this->outputOption));
        if (!is_null($this->outputOption)) {
            $this->needChildDir = $this->outputOption & self::$CREATE_PHP_CONFIG_IN_CHILD_DIR;
        }
        self::vd(sprintf("needChildDir: %s", var_export($this->needChildDir, true)));


        // 初始化是否需要切割配置文件
        if (!is_null($this->outputOption)) {
            $this->needSplitConfig = $this->outputOption & self::$CREATE_CHILD_PHP_CONFIG;
        }
        self::vd(sprintf("needSplitConfig: %s", var_export($this->needSplitConfig, true)));
    }

    /**
     * 执行主函数
     */
    public function run()
    {
        // 判断参数是否正确
        self::vd("App Name: {$this->appName}, Dump Name: {$this->dumpName}, Option: {$this->outputOption}");
        if (!$this->appName || !$this->dumpName) {
            self::vd("App Name or Dump Name not provided, quit ...", true);
        }

        // 组装导出目录
        $dumpBase = '..' . self::$DS . '..' . self::$DS . 'output' . self::$DS . $this->appName;
        self::vd($dumpBase);

        // 找到最后一次导出目录
        $lastDumpDir = $this->getLastDumpDir($dumpBase);
        self::vd("Last Dump Dir: " . $lastDumpDir);

        // 获取json文件路径
        $jsonPath = $lastDumpDir . self::$DS . 'PHP' . self::$DS . $this->dumpName . '.json';

        // 读取json文件，并解析成数组
        $json = $this->getJsonData($jsonPath);

        // 写配置文件
        $this->writeData($json, $lastDumpDir, $this->dumpName);

        // 判断此配置文件是否有特殊逻辑
        $methodName = $this->dumpName . '_handler';
        if (method_exists($this, $methodName)) {
            $this->$methodName($json, $lastDumpDir, $this->dumpName);
            self::vd("{$methodName} Done...");
        }

        // 删除json文件
        unlink($jsonPath);

        // 退出
        self::vd("Dump Done ...", true);
    }

    /**
     * 写入配置文件
     *
     * @param string $json
     * @param string $dumpDir             文件输出目录
     * @param string $dumpName            输出文件名
     * @param boolean $handlerNoNeedSplit default false, 强制不切割通过handler生成的文件
     */
    private function writeData($json, $dumpDir, $dumpName, $handlerNoNeedSplit = false)
    {
        $dumpPath = $dumpDir . self::$DS . 'PHP';

        // 如果需要分子目录存储,则需要再生成一层子目录
        if ($this->needChildDir) {
            $dumpNameArray = explode('_', $dumpName);
            if (count($dumpNameArray) >= 2) {
                $dumpPath .= self::$DS . $dumpNameArray[0] . '_' . $dumpNameArray[1];

                // 创建目录
                if (!file_exists($dumpPath)) {
                    var_dump(mkdir($dumpPath));

                    self::vd("make dir: " . $dumpPath);
                }
            }
        }

        $phpFile = $dumpPath . self::$DS . $dumpName . '.config.php';
        $this->writeFile($phpFile, $json);

        // 切割配置文件
        if ($this->needSplitConfig && !$handlerNoNeedSplit) {
            // 切割文件都统一放到以原文件名命名的文件夹内
            $dumpPath .= self::$DS . $dumpName;
            if (!file_exists($dumpPath)) {
                mkdir($dumpPath);
                self::vd("make dir: " . $dumpPath);
            }

            // 按行切割文件
            foreach ($json as $configId => $config) {
                $phpFile = $dumpPath . self::$DS . $configId . '.config.php';
                $this->writeFile($phpFile, $config);
            }
        }
    }

    /**
     * 写入php文件
     *
     * @param string $file 写入文件路径
     * @param string $data 写入文件内容
     * @return void
     */
    private function writeFile($file, $data)
    {
        // 写入配置文件
        $configs = var_export($data, true);
        // 整理输出格式
        $config = <<<TXT
<?php
return {$configs};
TXT;

        // 写入导出文件
        file_put_contents($file, $config);
    }

    /**
     * 读取json数据
     *
     * @param string $jsonPath
     * @return array
     */
    private function getJsonData($jsonPath)
    {
        if (!file_exists($jsonPath)) {
            self::vd("Target json file not found, quit: {$jsonPath}", true);
        }

        $jsonStr = file_get_contents($jsonPath);
        $json    = json_decode($jsonStr, true);

        // 轮询数组的value，将子json结构成数组结构
        foreach ($json as $key => $valueArr) {
            foreach ($valueArr as $valueKey => $value) {
                $decodedValue = @json_decode($value, true); // 如果$value是数组输入的话，会报warning，压制掉
                if (is_array($decodedValue)) {
                    $json[$key][$valueKey] = $decodedValue;
                }
            }
        }

        ksort($json);

        return $json;
    }

    /**
     * 找到最后一次导出目录
     *
     * @param string $dumpBase
     * @return string
     */
    private function getLastDumpDir($dumpBase)
    {
        $lastDumpDir = null;
        $dumpBaseDir = new DirectoryIterator($dumpBase);

        /* @var DirectoryIterator $info */
        foreach ($dumpBaseDir as $info) {
            if ($info->isDir()) {
                $lastDumpDir = $info->getFilename();
            }
        }

        return $dumpBase . self::$DS . $lastDumpDir;
    }

    /**
     * 输出调试信息
     *
     * @param string $msg
     * @param boolean $exit default false, 是否退出程序执行
     * @return void
     */
    private static function vd($msg, $exit = false)
    {
        echo $msg . "\r\n";
        if ($exit) {
            exit;
        }
    }

    /**
     * 处理成就, 找出entityId => configId对应关系
     *
     * @param array $originData
     * @param string $dumpDir
     * @param string $originName
     * @return void
     */
    private function module_achievement_handler($originData, $dumpDir, $originName)
    {
        // 生成新数据
        $data = [];
        foreach ($originData as $config) {
            if (!$config['require']) {
                continue;
            }

            foreach ($config['require'] as $entityId => $value) {
                if (!isset($data[$entityId])) {
                    $effects = [];
                } else {
                    $effects = $data[$entityId]['effects'];
                }
                $effects[]       = $config['configId'];
                $data[$entityId] = [
                    'entityId' => $entityId,
                    'effects'  => $effects,
                ];
            }
        }

        // 生成配置文件
        $dumpName = 'module_achievement_effects';
        $this->writeData($data, $dumpDir, $dumpName);
    }

    /**
     * 处理任务, 生成等级任务表
     *
     * @param array $originData
     * @param string $dumpDir
     * @param string $originName
     * @return void
     */
    private function module_mission_handler($originData, $dumpDir, $originName)
    {
        $data = [];
        foreach ($originData as $config) {
            $typeKey = null;
            switch ($config['type']) {
                case 2:
                    $typeKey = 'dailyMission';
                    break;
                case 3:
                    $typeKey = 'dailyTimeMission';
                    break;
                case 4:
                    $typeKey = 'dailyVipMission';
                    break;
                default:
                    break;
            }

            if (is_null($typeKey)) {
                continue;
            }

            $maxLv = $config['level'] + 10;
            for ($lv = $config['level']; $lv < $maxLv; ++$lv) {
                if (!isset($data[$lv])) {
                    $data[$lv] = [
                        'configId'         => $lv,
                        'level'            => $lv,
                        'dailyMission'     => [],
                        'dailyVipMission'  => [],
                        'dailyTimeMission' => [],
                    ];
                }

                $data[$lv][$typeKey][] = $config['configId'];
            }
        }

        // 生成配置文件
        $dumpName = 'module_mission_daily';
        $this->writeData($data, $dumpDir, $dumpName);
    }

    /**
     * 处理dol_social_help, 生成一张以helpId为主键的表
     *
     * @param array $originData
     * @param string $dumpDir
     * @param string $originName
     * @return void
     */
    private function dol_social_help_handler($originData, $dumpDir, $originName)
    {
        // 整理数据
        $data = [];
        foreach ($originData as $config) {
            $helpId        = strval($config['helpId']);
            $data[$helpId] = $config;
        }

        // 生成配置文件
        $dumpName = 'dol_social_help_auto_create';
        $this->writeData($data, $dumpDir, $dumpName);
    }

    /**
     * 处理dol_social_request, 生成一张以requestDefId为主键的表
     *
     * @param array $originData
     * @param string $dumpDir
     * @param string $originName
     * @return void
     */
    private function dol_social_request_handler($originData, $dumpDir, $originName)
    {
        // 整理数据
        $data = [];
        foreach ($originData as $config) {
            $helpId        = strval($config['requestDefId']);
            $data[$helpId] = $config;
        }

        // 生成配置文件
        $dumpName = 'dol_social_request_auto_create';
        $this->writeData($data, $dumpDir, $dumpName);
    }

    /**
     * 处理dol_social_feed, 生成一张以feedDefId为主键的表
     *
     * @param array $originData
     * @param string $dumpDir
     * @param string $originName
     * @return void
     */
    private function dol_social_feed_handler($originData, $dumpDir, $originName)
    {
        // 整理数据
        $data = [];
        foreach ($originData as $config) {
            $helpId        = strval($config['feedDefId']);
            $data[$helpId] = $config;
        }

        // 生成配置文件
        $dumpName = 'dol_social_feed_auto_create';
        $this->writeData($data, $dumpDir, $dumpName);
    }

    /**
     * 处理dol_drop, 切割掉落配置文件, 将配置文件按组切成一个个的配置文件
     *
     * @param array $originData
     * @param string $dumpDir
     * @param string $originName
     * @return void
     */
    private function dol_drop_handler($originData, $dumpDir, $originName)
    {
        $groupData = [];

        // 按组划分数组
        foreach ($originData as $configId => $config) {
            $groupData[$config['groupId']][$configId] = $config;
        }

        // 分组写入文件
        $namePrefix = 'dol_drop_group_';
        foreach ($groupData as $groupId => $data) {
            $dumpName = $namePrefix . $groupId;
            $this->writeData($data, $dumpDir, $dumpName, true);
        }
    }

}

$dump = new Dump($argv);
$dump->run();
