<?php

namespace Mall\Framework\Swoole;

class WebsocketServer
{
    private $moduleServer;

    private $moduleData;

    private $serviceModuleName;

    private $isSetConfig;

    function __construct($options = [])
    {
        class_exists('swoole_websocket_server') or die("swoole_websocket_server: check swoole extension");
        if($options['ssl'] == true){
            $this->moduleServer = new \swoole_websocket_server($options['host'], $options['port'], SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
        }else{
            $this->moduleServer = new \swoole_websocket_server($options['host'], $options['port']);
        }

        if (!isset($options['module']) && $options['module']) {
            throw new \Exception('Please define the module name first');
        }
        $this->serviceModuleName = ucfirst($options['module']);
    }

    public function setConfig($options = [])
    {
        $defaultOptions = [
            'worker_num' => 8, // 建议开启核数的1-4倍
            'daemonize' => true,
        ];
        $options = $options ?: $defaultOptions;

        $this->moduleServer->set($options);
        $this->isSetConfig = true;

        return $this;
    }

    public function begin()
    {
        if (!$this->isSetConfig) {
            throw new \Exception('Please set the configuration file first');
        }

        $this->registerEvent();

        $this->moduleServer->start();
    }

    private function registerEvent()
    {
        $this->moduleServer->on('Start', array($this, 'onStart'));
        $this->moduleServer->on('Connect', array($this, 'onConnect'));
        $this->moduleServer->on('open', array($this, 'onOpen'));
        $this->moduleServer->on('message', array($this, 'onMessage'));
        $this->moduleServer->on('Close', array($this, 'onClose'));
        //$this->moduleServer->on('ManagerStart', array($this, 'onManagerStart'));
        //$this->moduleServer->on('WorkerStart', array($this, 'onWorkerStart'));
        //$this->moduleServer->on('WorkerStop', array($this, 'onManagerStop'));
    }

    //启动server时候会触发。
    public function onStart($server)
    {
        echo "Start swoole_websocket_server \n";
    }

    //client连接成功后触发。
    public function onConnect($server, $fd, $from_id)
    {
        echo "Client id {$fd}:{$from_id} \n";
        //var_dump($this->moduleServer->connection_info($fd));
    }

    //client连接成功后触发。
    public function onOpen(\swoole_websocket_server $server, $request)
    {
        echo "server: handshake success with fd{$request->fd}\n";
    }

    //接收client发过来的请求
    public function onMessage( $server, $frame)
    {
        $moduleData = str_replace(PACKAGE_EOF, '', $frame->data);
        echo "Get Message From Client {$frame->fd}:{$moduleData}\n";

        if (!$moduleData = json_decode($moduleData, true)) {
            throw new \Exception('Please send data to JSON format');
        }

        $namespace = '\Service\\' . $this->serviceModuleName . '\\Controller\\' . $moduleData['controller'];
        $resource = new $namespace();
        if (isset($moduleData['params']) && $moduleData['params']) {
            $moduleData['params']['fromId'] = $frame->fd;
            $data = call_user_func([$resource, $moduleData['action']], $moduleData['params']);
        } else {
            $data = call_user_func([$resource, $moduleData['action']]);
        }

        try{
            if(!empty($data)){
                $result = true;
                foreach ($data['fromId'] as $key => $value){
                    if($server->exist($value)){
                        $result = $server->push($value, $data['sendData']);
                    }else{
                        echo "Client {$value} connect not exist\n";
                    }
                }
                if(!in_array($frame->fd, $data['fromId'])){
                    $result = $server->push($frame->fd, json_encode(['state'=>true,'data'=>'服务端脚本完毕']));
                }
            }else{
                $result = $server->push($frame->fd, json_encode(['state'=>false,'data'=>'服务端脚本处理异常']));
            }
        }catch (\Exception $e){
            echo $e->getMessage();
        }

        if(!$result){
            echo $this->moduleServer->getLastError();
        }
    }

    //客户端断开触发
    public function onClose($server, $fd)
    {
        echo "Client {$fd} close connection\n";

        $namespace = '\Service\BaseController';
        $resource = new $namespace();

        if(method_exists($resource, 'closeWebstock')){
            if( call_user_func([$resource, 'closeWebstock'], $fd) ){
                echo 'logout redis success';
            }
        }
    }

    public function onManagerStart(\swoole_server $server) {
        echo "On manager start.";
    }

    public function onManagerStop(\swoole_server $server) {
        echo "On manager start.";
    }

    public function onWorkerStart(\swoole_server $server, $workerId) {
        echo $workerId . '---';
    }

    public function getData()
    {
        return $this->moduleData;
    }

}