<?php
/**
 * Copyright (c) 2016. PlatyHouse. all rights reserved.
 */

/**
 * Created by PhpStorm.
 * User: cpueblo
 * Date: 2016. 8. 6.
 * Time: 오후 5:00
 */

namespace platyFramework;

require_once(__DIR__ . "/loader.php");


/**
 * @property loader $loader
 * @property request $request;
 * @property req $req;
 * @property response $response;
 * @property ptyMysql $db;
 * @property ptyconfigItemsModel $config
 * @property ptyuserItemModel signedInItem
 */
class controller
{
    // var $platyFramework;

    /** @var ptyArrayItemModel */
    var $data;

    public function __construct()
    {
        /*
        GLOBAL $platyFramework;
        if ($platyFramework)
            $this->platyFramework = $platyFramework;
        */
        $this->data = new ptyArrayItemModel();
    }

    public function __destruct()
    {
    }


    public function __toString()
    {
        return "platyFramework\\controller";
    }

    public function __get($key)
    {
        global $platyFramework;
        if ($platyFramework)
            return $platyFramework->__get($key);
        else {
            debug_print_backtrace();
            die ("platyFramework::model::__get($key) error. this->platyFramework is null");
        }
    }

    public function registerGetAction($actionName, $class, $func, $priority = 1000)
    {
        global $platyFramework;
        if ($platyFramework)
            $platyFramework->registerGetAction($actionName, $class, $func, $priority);

    }

    public function registerCallAction($actionName, $class, $func, $priority = 1000)
    {
        global $platyFramework;
        if ($platyFramework)
            $platyFramework->registerCallAction($actionName, $class, $func, $priority);

    }


    public function setToFramework($key, $value)
    {
        global $platyFramework;
        if ($platyFramework)
            $platyFramework->__set($key, $value);
    }

    /**
     * POST 에 params:a=b&c=d 형식으로 전달된 파라미터를 파싱합니다
     *
     * @param string $keyName
     * @return ptyArrayItemModel
     */
    public function getPostJsonParams($keyName = "params")
    {
        ptyParseStr($_POST[$keyName], $p);
        ptyTrim($p);
        $p = ptyArrayItemModel::buildItem($p, false);
        return $p;
    }

    /**
     * [cpueblo] 2018-03-14
     * 다음의 데이터를 http_build_query 로 리턴합니다. 리턴한 함수들은 parse_str 로 가공하며, get_defined_vars() 를 통해 확인할 수 있습니다
     * ptyDebug(get_defined_vars());
     *
     * $_POST['data']
     * $this->>request->post
     * function args
     *
     * @return array|string|ptyArrayItemModel
     */
    public function getParams()
    {
        $p = array();

        // post 에 data 로 넘어온 경우 세팅
        if (isset($_POST['data'])) {
            ptyParseStr($_POST['data'], $p);
            ptyTrim($p);
        } // post 에 data 로 넘어온 경우 세팅
        else if (isset($_POST['params'])) {
            ptyParseStr($_POST['params'], $p);
            ptyTrim($p);
            $p = ptyArrayItemModel::buildItem($p, false);
            return $p;
        } // post 에 직접 넘어온 경우
        else if (file_get_contents('php://input') != "") {
            $p = json_decode(file_get_contents('php://input'), true);
        } else {
            $p = $this->request->request;      // post 로 강제할것인가, get & post 를 모두 받을 것인가
        }
        // else $p = $this->request->request;      // post 로 강제할것인가, get & post 를 모두 받을 것인가

        // 함수 arguments 로 넘어온 경우
        $p = self::funcGetNamedParams($p);
        $p = http_build_query($p);

        parse_str($p, $out);

        if ($out['encoded']) {
            $n = new ptyencoderAes256hmacModel();
            $p2 = $n->decrypt($out['encoded'], "jangbidabooler00jangbidabooler00");
            $p3 = json_decode($p2, true);
            // $p3['encodedAes256HMAC'] = true;

            $this->request->encoded = json_decode($p2, true);

            if ($this->request->request['debug']) {
                ptyDebug($p2, "request debugs");
                ptyDebug($p3, "request debug");
                // http_build_query()
                ptyDebug(http_build_query($p3), "request debug 2");
            }

            $this->callAction("onAppControllerGetParams", $p3);
            return $p3;
        }

        $this->callAction("onAppControllerGetParams", $out);
        return $out;
    }

    /**
     * @return ptyArrayItemModel
     */
    public function getPropertyParams()
    {
        return ptyArrayItemModel::buildItem($this->getParams(), false);
        // return $this->getParams();
    }

    /**
     * 2018-12-16
     * POST 내의 http 쿼리 형식으로 제공되는 params 필드를 가져옵니다. ptyPost 함수의 인자를 가져올 때 사용됩니다
     *
     * @return null|ptyArrayItemModel
     */
    public function getParamsFromPost()
    {
        if (isset($_POST['params'])) {
            ptyParseStr($_POST['params'], $p);
            ptyTrim($p);
            $p = ptyArrayItemModel::buildItem($p, false);
            return $p;
        }
        return NULL;
    }

    public static function funcGetNamedParams($params)
    {
        $func = debug_backtrace()[2]['function'];
        $args = debug_backtrace()[2]['args'];
        $class = debug_backtrace()[2]['class'];

        // $reflector = new \ReflectionClass(__CLASS__);
        $reflector = new \ReflectionClass($class);
        // $params = [];
        foreach ($reflector->getMethod($func)->getParameters() as $k => $parameter) {
            // $params[$parameter->name] = isset($args[$k]) ? $args[$k] : $parameter->getDefaultValue();
            if (isset($args[$k]))
                $params[$parameter->name] = $args[$k];
        }

        return $params;
    }

    function dieTrue($arrs = null)
    {
        $ret = array();
        $ret['return'] = 'true';

        if (is_array($arrs))
            $ret = array_merge($ret, $arrs);

        if ($this->request->request['debug']) {
            ptyDebug($ret, "output debug");
        }

        $this->callAction("onAppControllerDieTrueFalse", $ret);

        if ($this->request->request['encoded']) {
            $json = json_encode($ret, JSON_UNESCAPED_UNICODE);
            $n = new platyAes256hmacModel();
            $encoded = $n->encrypt($json, "jangbidabooler00jangbidabooler00");

            $ret = array();
            $ret['encoded'] = $encoded;
            die (json_encode($ret, JSON_UNESCAPED_UNICODE));
        } else {
            $json = json_encode($ret, JSON_UNESCAPED_UNICODE);
            die ($json);
        }
    }

    function dieFalse($arrs = null)
    {
        $ret = array();
        $ret['return'] = 'false';

        if (is_array($arrs))
            $ret = array_merge($ret, $arrs);

        if ($this->request->request['debug']) {
            ptyDebug($ret, "output debug");
        }

        $this->callAction("onAppControllerDieTrueFalse", $ret);

        if ($this->request->request['encoded']) {
            $json = json_encode($ret, JSON_UNESCAPED_UNICODE);
            $n = new platyAes256hmacModel();
            $encoded = $n->encrypt($json, "jangbidabooler00jangbidabooler00");

            $ret = array();
            $ret['encoded'] = $encoded;
            die (json_encode($ret, JSON_UNESCAPED_UNICODE));
        } else {
            $json = json_encode($ret, JSON_UNESCAPED_UNICODE);
            die ($json);
        }

    }

    function ptyJsonReturn($return)
    {
        $ret = array();

        if ($return == true) {
            $ret['return'] = 'true';
            if (is_array($this->returnFalse))
                $ret = array_merge($ret, $this->returnFalse);
        } else if ($return == false) {
            $ret['return'] = 'false';
            if (is_array($this->returnFalse))
                $ret = array_merge($ret, $this->returnFalse);
        }

        if ($this->request->request['debug']) {
            ptyDebug($ret, "output debug");
        }

        $this->callAction("onAppControllerDieTrueFalse", $ret);

        if ($this->request->request['encoded']) {
            $json = json_encode($ret, JSON_UNESCAPED_UNICODE);
            $n = new platyAes256hmacModel();
            $encoded = $n->encrypt($json, "jangbidabooler00jangbidabooler00");

            $ret = array();
            $ret['encoded'] = $encoded;
            die (json_encode($ret, JSON_UNESCAPED_UNICODE));
        } else {
            $json = json_encode($ret, JSON_UNESCAPED_UNICODE);
            die ($json);
        }
    }

    public function callAction($func, &$args = null, &$args2 = null, &$args3 = null, &$args4 = null)
    {
        global $platyFramework;
        $platyFramework->callAction($func, $args, $args2, $args3, $args4);
    }

    /**
     * @throws ptyException
     */
    public function checkAdmin()
    {
        $this->checkSignedInItem();

        if ($this->signedInItem == null || $this->signedInItem->isGuest()) {
            ptyThrow("로그인을 하신 후 접근 가능합니다", "ERROR_ACCESS_PERMISSION");
        }

        if ($this->signedInItem->level == "guest")

            if (!$this->signedInItem->isAdmin())
                ptyThrow("권한이 없습니다", "ERROR_ACCESS_PERMISSION");
    }

    /**
     * @throws ptyException
     */
    public function checkSuperAdmin()
    {
        $this->checkSignedInItem();

        if (!$this->signedInItem->isSuperAdmin())
            ptyThrow("최고 관리자 권한이 없습니다", "ERROR_ACCESS_PERMISSION");
    }

    /**
     * @throws ptyException
     */
    public function checkSignedInItem()
    {
        if (!$this->signedInItem)
            ptyThrow("로그인을 하셔야 합니다", "ERROR_NOT_SIGNED");
        // ptyAlertGo("로그인 후 이용 가능 합니다", (PLATYFRAMEWORK_APP_URL . "/ptyuser/signIn/?backUrl=" . urlencode($this->request->requestUrl));
    }


    /**
     * curl 로 들어온 apiKey 를 이용하여 userItem 을 가져옵니다
     *
     * @return ptyuserItemModel|null
     */
    public function getUserItemByApiKey()
    {
        $apiKey = mysqli_real_escape_string($this->db->_connection, $_SERVER['HTTP_APIKEY']);
        $apiKey = $_SERVER['HTTP_APIKEY'];

        if ($apiKey == "")
            ptyJsonReturnFalseDie(["message" => "apiKey is empty"]);

        /** @var ptyuserItemModel $userItem */
        $userItem = ptyuserItemsModel::build()->getItemBy(["enabled" => 1, "apiAccessToken" => $apiKey]);
        if (!$userItem) {
            ptyJsonReturnFalseDie(["message" => "apiKey is invalid."]);
        }

        return $userItem;
    }

    public function checkAccessToken($accessToken)
    {
        if ($_SERVER['HTTP_APIKEY']) {
            $GLOBALS['platyFramework']->signedInItem = $this->signedInItem = $this->getUserItemByApiKey();
            if ($this->signedInItem)
                return true;
        }

        if ($accessToken == "") {
            return false;
        }

        $aes256 = new platyAes256hmacModel();
        $d = json_decode($aes256->decrypt($accessToken, "APPS.PLATYHOUSE.APIKEY"), true);

        if ($d['expires_in'] < time()) {
            if (class_exists("platyFramework\\ptylogsItemsModel")) {
                $ptylogsItemsModel = ptylogsItemsModel::build();
                $ptylogsItemsModel->addLogs("ptyuser", "signIn", '', '', "토큰이 만료됨 #1 = " . print_r($d, true));
            }
            die ("토큰이 만료되었습니다. 새로고침을 진행해 주세요.");
        }

        if ($d['apiKey'] == "") {
            if (class_exists("platyFramework\\ptylogsItemsModel")) {
                $ptylogsItemsModel = ptylogsItemsModel::build();
                $ptylogsItemsModel->addLogs("ptyuser", "signIn", '', '', "토큰이 만료됨 #2 = " . print_r($d, true));
            }
            die ("토큰이 만료되었습니다. 새로고침을 진행해 주세요..");
        }

        $this->signedInItem = ptyuserItemsModel::build()->signInByApiKey($d['apiKey']);
        if (!$this->signedInItem) {
            echo "접근키가 없습니다. 자동으로 관리자에 알림이 전달되었으며, 곧 조치될 예정 입니다.";

            $text = urlencode("ptyboard.scriptA 접근 키 없음.\n" . print_r($this->request->req->_item, true));
            file_get_contents("https://api.telegram.org/bot1142526400:AAGjUWWxUk9dSKhCdGBgaxQqjfHF7HC9pIE/sendmessage?chat_id=589455612&text=$text");

            http_response_code(403);
            exit;
        }
        $this->setToFramework("signedInItem", $this->signedInItem);
        return true;

        return;


        global $platyFramework;

        // ptyDebug($this->request->req);
        if ($this->request->req->accessToken == "") {
            echo "accessToken is empty";
            http_response_code(403);
            exit;
        }

        $accessToken = $this->decryptA($_GET['accessToken'], "ptyBoard", "hello");
        if ($accessToken == "") {
            echo "wrong accessToken";
            return;
        }

        $userAccessToken = $this->decryptA($_GET['userAccessToken'], "ptyBoard", "hello");
        // $userAccessToken = "com.storyshare.goodforestword";

        // storyshare 전용 특별히 처리건
        $userAccessToken = str_replace("com.storyshare.", "", $userAccessToken);

        if ($userAccessToken != "") {
            $userItemsModel = ptyuserItemsModel::build();
            $this->signedInItem = $userItemsModel->signInForce($accessToken, $userAccessToken);
            if ($this->signedInItem == NULL) {
                http_response_code(403);
                echo "유효하지 않은 유저 토큰입니다";
                return;
            }

            // ptyDebug($this->signedInItem);

            $_SESSION['ptyuser_signedInId'] = $this->signedInItem->id;
            $_SESSION['ptyuser_signedInItem'] = serialize($this->signedInItem->_item);

            if (!$this->signedInItem || $this->signedInItem->userId == "") {
                http_response_code(403);
                exit;
            }

            $platyFramework->signedInItem = $this->signedInItem;
        }
    }

    public function setTmpSignKey($tmpSignKey)
    {
        $aes256 = new ptyAes256();
        $hashValue = $aes256->decrypt($tmpSignKey, "platyFramework_cpueblo_platyhouse");
        if (!strstr($hashValue, "pty|"))
            ptyThrow("잘못된 요청 입니다");

        $n = explode("|", $hashValue);
        $signTime = $n[1];
        $signServiceUserId = $n[2];
        $signUserId = $n[3];
        // $id = $n[4];

        if ($signTime + (60 * 60 * 24) < time()) {
            if (class_exists("platyFramework\\ptylogsItemsModel")) {
                $ptylogsItemsModel = ptylogsItemsModel::build();
                $ptylogsItemsModel->addLogs("ptyurlmonitor.dashboard.index", "", 0, "", "해당 링크는 24시간이 지나 만료되었습니다. hashValue = $hashValue");
            }

            ptyAlertGo("해당 링크는 24시간이 지나 만료되었습니다.", $this->request->appUrl);
        }

        // 로그인
        {
            $userItemsModel = new ptyuserItemsModel();
            $this->signedInItem = $userItemsModel->signInForce($signServiceUserId, $signServiceUserId);
            if (!$this->signedInItem) ptyThrow("로그인이 불가능한 아이디 입니다");
            $this->setToFramework("signedInItem", $this->signedInItem);

            $hashExpire = date("Y-m-d H:i:s", $signTime + (60 * 60 * 24));
            ptynotifitjsApiModel::add("임시 키로 로그인 되었습니다. 해당 키는 $hashExpire 에 만료됩니다.");
        }

        return true;
        // return $id;
    }


}

?>
