<?php
use Firebase\JWT\JWT;
use Defuse\Crypto\Crypto;

require_once(SITE_LOGICS . 'settlement/config.php');

class SettlementModelClass extends ModelClassEx {

	/*-------------------------------------------------------------------------
	* @ メンバ変数
	-------------------------------------------------------------------------*/
	private $rs							= null;			// ユーザデータ
	private $account					= null;			// 送金先口座情報
	private $params						= null;			// 任意パラメータ
	private $signature					= NO_STRING;	// シグネチャ
	private $userAccount				= NO_STRING;	// 口座番号
	private $fromAccount				= NO_STRING;	// from account
	private $currency					= NO_STRING;	// 通貨
	private $amount						= NO_STRING;	// 金額
	private $title						= NO_STRING;	// 商品名
	private $pNum						= NO_STRING;	// 番組コード
	private $userName					= NO_STRING;	// ユーザ名
	private $password					= NO_STRING;	// パスワード
	private $toAccount					= NO_STRING;	// 送金先口座
	private $msg						= NO_STRING;	// 送金メッセージ
	private $debitCurrency				= NO_STRING;	// 出金通貨
	private $debitAmount				= NO_STRING;	// 出金金額
	private $fromFee					= NO_STRING;	// 送金元手数料
	private $toFee						= NO_STRING;	// 送金先手数料
	private $successUrl					= NO_STRING;	// 成功時URL
	private $failUrl					= NO_STRING;	// 失敗URL
	private $cancelUrl					= NO_STRING;	// キャンセルURL
	private $returnUrl					= NO_STRING;	// 返却URL
	private $transactionNumber			= NO_STRING;	// 取引番号
	private $rate						= NO_STRING;	// 為替レート
	
	private $paymentToken              = NO_STRING;
	private $formName                  = NO_STRING;
	private $balance                   = NO_STRING;
	private $uniqueSubmission          = NO_STRING;
	private $validationResult          = NO_STRING;
	private $invalidFormParams         = [];
	private $midconf                   = null;
	private $settleForm                = null;
	private $paymentAPIConf            = null;
	
	private $ignoreParamNames = [
	    PARAM_SIGNATURE,
	    PARAM_P_NUM,
	    PARAM_CURRENCY,
	    PARAM_AMOUNT,
	    PARAM_AMOUNT,
	    PARAM_TITLE,
	    PARAM_SUCCESS_URL,
	    PARAM_FAIL_URL,
	    PARAM_CANCEL_URL,
	    PARAM_RETURN_URL,
	    PARAM_USER_NAME,
	    PARAM_PASSWORD,
	    PARAM_TYPE,
	    PARAM_USER_ACCOUNT,
	    PARAM_DEBIT_CURRENCY,
	    PARAM_FROM_ACCOUNT,
	    PARAM_MESSAGE,
	    PARAM_RATE,
	    PARAM_DEBIT_AMOUNT
	];
	
	/*-------------------------------------------------------------------------
	* @function_name: コントロールパネルシステムindexモデルクラスコンストラクタ
	* @parameter	: なし
	* @return		: なし
	-------------------------------------------------------------------------*/
	function __construct() {
		// スーパークラスコンストラクタ呼び出し
		parent::__construct();
	}

	/*-------------------------------------------------------------------------
	* @function_name: 初期設定関数
	* @parameter	: なし
	* @return		: 成功:success、失敗:error
	-------------------------------------------------------------------------*/
	public function init() {

		try {
		    $this -> initSettings();
		    
			// パラメータの設定
			$this -> setParameter();

			// チェック
			$this -> validate();

		} catch (Exception $e) {
			throw $e;
		}
	}

	/*-------------------------------------------------------------------------
	* @function_name: パラメータの設定
	* @parameter	: なし
	* @return		: なし
	-------------------------------------------------------------------------*/
	private function setParameter() {
	    // JWT
	    $this -> paymentToken         = $this -> getDataGet("ptoken");
	    
	    $this -> uniqueSubmission     = $this -> getDataPost("uniqueSubmission");
	    $this -> formName             = $this -> getDataPost("formName");	    
		$this -> signature		      = $this -> getDataPost(PARAM_SIGNATURE, true);		// シグネチャ
		$this -> pNum			      = $this -> getDataPost(PARAM_P_NUM, true);			// 番組コード
		$this -> userAccount	      = $this -> getDataPost(PARAM_USER_ACCOUNT, true);		// 口座番号
		$this -> fromAccount	      = $this -> getDataPost(PARAM_FROM_ACCOUNT, true);		// from account
		$this -> currency		      = $this -> getDataPost(PARAM_CURRENCY, true);			// 通貨
        $this -> amount			      = $this -> getDataPost(PARAM_AMOUNT, true);			// 金額
        $this -> title			      = $this -> getDataPost(PARAM_TITLE, true);			// 商品名
        $this -> userName		      = $this -> getDataPost(PARAM_USER_NAME, true);		// ユーザ名
        $this -> password		      = $this -> getDataPost(PARAM_PASSWORD);			    // パスワード
        $this -> toAccount		      = $this -> getDataPost(PARAM_USER_ACCOUNT, true);		// 送金先口座
        $this -> debitCurrency	      = $this -> getDataPost(PARAM_DEBIT_CURRENCY, true);	// 出金通貨
        $this -> debitAmount	      = $this -> getDataPost(PARAM_DEBIT_AMOUNT, true);		// 出金金額
        $this -> msg			      = $this -> getDataPost(PARAM_MESSAGE, true);			// 送金メッセージ
        $this -> successUrl		      = $this -> getDataPost(PARAM_SUCCESS_URL);		    // 成功時URL
        $this -> failUrl		      = $this -> getDataPost(PARAM_FAIL_URL);			    // 失敗URL
        $this -> cancelUrl		      = $this -> getDataPost(PARAM_CANCEL_URL);		        // キャンセルURL
        $this -> returnUrl		      = $this -> getDataPost(PARAM_RETURN_URL);		        // 返却URL
        $this -> rate			      = $this -> getDataPost(PARAM_RATE, true);				// 取引レート
		$this -> setRateEx($this -> rate);										            // 取引レート
		
		$this -> params = [];
	}

	private function initSettings(){
	    $this -> midconf           = $this -> getSettingConfiguration("middleware_conf");
	    $this -> paymentAPIConf    = $this -> getSettingConfiguration("payment_api_conf");
	    
	    if(isset($this -> paymentAPIConf -> middleware_sig_passphrase)){
	        $replacements = [
	            "{curdate_int}" => strtotime(date("Ymd")),
	            "{curdate_str}" => date("Ymd")
	        ];
	        
	        foreach($replacements as $search => $replace){
	            $this -> paymentAPIConf -> middleware_sig_passphrase = str_replace(
	                $search,
	                $replace,
	                $this -> paymentAPIConf -> middleware_sig_passphrase);
	        }
	    }
	    
	    if($this -> getType() == NO_STRING)
	        $this -> setType(TYPE_SETTLEMENT_EXPRESS_FORM);
	}
	
	/**
	 * 
	 * @param unknown $formName
	 * @return array|unknown|boolean
	 */
	private function getSettlementForm($formName){
	    $settleForm = $this -> getRowData($this -> accessSelect("SELECT_SETTLEMENT_FORM", [$formName]));
	    
	    if($this -> isLoopData($settleForm))
	        return $settleForm;
	    
	    return false;
	}
	
	/*-------------------------------------------------------------------------
	* @function_name: パラメータの再設定
	* @parameter	: なし
	* @return		: なし
	-------------------------------------------------------------------------*/
	public function restore() {
	    if($this -> settleForm == null)
	        return;
	    
	    $data = base64_decode($this -> getColumnData($this -> settleForm, "form_data"));
	    
	    if($this -> checkJSONString($data)){
	        $data = json_decode($data, true);
	        	        
	        $this -> signature     = $this -> getColumnData($data, PARAM_SIGNATURE);
	        $this -> pNum          = $this -> getColumnData($data, PARAM_P_NUM);
	        $this -> amount        = $this -> getColumnData($data, PARAM_AMOUNT);
	        $this -> currency      = $this -> getColumnData($data, PARAM_CURRENCY);
	        $this -> title         = $this -> getColumnData($data, PARAM_TITLE);
	        $this -> successUrl    = $this -> getColumnData($data, PARAM_SUCCESS_URL);
	        $this -> failUrl       = $this -> getColumnData($data, PARAM_FAIL_URL);
	        $this -> returnUrl     = $this -> getColumnData($data, PARAM_RETURN_URL);
	        
	        $apiSignature          = $this -> getRowData($this -> getAPISignatureCommon($this -> pNum));
	        $this -> userAccount   = $this -> getColumnData($apiSignature, PARAM_USER_ACCOUNT);
	        
	        if(isset($data[PARAM_SETTLEMENT_FREE_PARAMS])){
	            $freeParams = $data[PARAM_SETTLEMENT_FREE_PARAMS];
	            
	            if($this -> isLoopData($freeParams)){
	                foreach($freeParams as $paramName => $paramValue)
	                    $this -> params[$paramName] = $paramValue;
	            }
	        }
	    }
	}
	
	private function validateSubmission(){
	    $invalid   = [];
	    $return    = [];
	    
	    $this -> formName  = $this -> getDataPost("formName");
	    
	    $this -> settleForm    = $this -> getSettlementForm($this -> formName);
	    $requestMethod = $this -> getColumnData($_SERVER, "REQUEST_METHOD");
	    
	    if($requestMethod != "POST"){
	        $invalid["INTE1"] = "Invalid Request Method: {$requestMethod}";
	    }
	    
	    if($this -> settleForm){
	        $formData = json_decode(base64_decode($this -> getColumnData($this -> settleForm, "form_data")), true);
	        $rs = $this -> getRowData($this -> checkUser($this -> userName, $this -> password));
	        
	        if($this -> isLoopData($rs)){	            
	            $apiSignature              = $this -> getRowData($this -> getAPISignatureCommon($this -> pNum));
	            $displayTransactionDetails = true;
	            
	            if($this -> getColumnData($apiSignature, PARAM_USER_ACCOUNT) != 
	                $this -> getColumnData($rs, PARAM_USER_ACCOUNT)){
	                $this -> fromAccount = $this -> getColumnData($rs, PARAM_USER_ACCOUNT);
	                $this -> userAccount = $this -> getColumnData($apiSignature, PARAM_USER_ACCOUNT);
	                
    	            $this -> setData();
    	            
    	            if($this -> balance < ($this -> debitAmount + $this -> getFeeEx())) {
    	                $invalid["OE04"] = $this -> getMessage(ERROR, 'E_INSUFFICIENT_FUNDS', 
    	                    array($this -> debitCurrency, 
    	                        $this -> formatCurrency(($this -> debitAmount + $this -> getFeeEx()), $this -> debitCurrency)));
    	            }
    	            
    	            if($this -> getColumnData($this -> account, COLUMN_RISK_LEVEL) == VAL_INT_1){
    	                $invalid["OE03"] = $this -> getMessage(ERROR, 'E_ERROR_WITHDRAW_HIGH_RISK', array());
    	            }
    	            
    	            $freeParams = $this -> getColumnData($formData, PARAM_SETTLEMENT_FREE_PARAMS);
    	            if($this -> isLoopData($freeParams)){
    	                $found = NO_COUNT;
    	                foreach(array_keys($_POST) as $paramName){
    	                    if(isset($freeParams[$paramName]))
    	                        $found += VAL_INT_1;
    	                }
    	                
    	                if($found != count($freeParams))
    	                    $invalid["OE11"] = "The defined free-params cannot be modified"; 
    	            }
    	            
    	            if($this -> pNum != $this -> getColumnData($formData, PARAM_P_NUM)){
    	                $invalid["UN03"] = "Program code modified";
    	                $invalid["OE08"] = $this -> getMessage(ERROR, 'E_ERROR_SAME_DATA', array(VAL_STR_P_NUM));
    	            }
    	            
    	            $this -> currency = strtoupper($this -> currency);
    	            if($this -> checkCurrency($this -> currency)){
    	                if($this -> currency != $this -> getColumnData($formData, PARAM_CURRENCY)){
    	                    $invalid["UN02"] = "Not an integrated currency";
    	                    $invalid["OE06"] = $this -> getMessage(ERROR, 'E_ERROR_SAME_DATA', array(VAL_STR_CURRENCY));
    	                }else{
    	                    if($this -> checkStringNumber($this -> amount)) {
    	                        if($this -> amount != NO_COUNT){
    	                            $submittedAmount = $this -> currencyToInt($this -> amount, $this -> currency);
    	                            $storedAmount = $this -> currencyToInt($this -> getColumnData($formData, PARAM_AMOUNT), $this -> currency);
    	                                	                            
    	                            if($submittedAmount != $storedAmount){
    	                                $invalid["UN04"] = "Not an organic submitted amount.";
    	                                $invalid["OE09"] = $this -> getMessage(ERROR, 'E_ERROR_SAME_DATA', array(PARAM_AMOUNT));
    	                            }
    	                        } else
    	                            $invalid["OE08"] = $this -> getMessage(ERROR, 'E_MINIMUM', array(VAL_STR_AMOUNT, NO_COUNT));
    	                    }else
    	                        $invalid["OE07"] = $this -> getMessage(ERROR, 'E_ERROR_REGULAR_NUMBER', array(VAL_STR_AMOUNT));
    	                }
    	            }else
    	                $invalid["OE05"] = $this -> getMessage(ERROR, 'E_ERROR_SAME_DATA', array(VAL_STR_CURRENCY));
    	            
    	            foreach(array_keys($invalid) as $key){
    	                if($key != "OE04")
    	                    $displayTransactionDetails = false;
    	            }
    	            
    	            if($displayTransactionDetails){
    	                $fromUser = $this -> getRowData($this -> getAccountCommon($this -> fromAccount));
    	                
    	                $fullName = $this -> getColumnData($fromUser, COLUMN_FIRST_NAME)." ".
        	                $this -> getColumnData($fromUser, COLUMN_LAST_NAME);
    	                
    	                $return["transaction_details"] = [
    	                    PARAM_FROM_ACCOUNT => $this -> fromAccount,
    	                    "from_full_name" => $fullName,
    	                    PARAM_USER_ACCOUNT => $this -> userAccount,
    	                    PARAM_DEBIT_CURRENCY => $this -> debitCurrency,
    	                    PARAM_BALANCE => $this -> formatCurrency($this -> balance, $this -> debitCurrency),
    	                    PARAM_DEBIT_AMOUNT => $this -> formatCurrency($this -> debitAmount + $this -> getFeeEx(), $this -> debitCurrency),
    	                    PARAM_AMOUNT => $this -> formatCurrency($this -> amount, $this -> currency),
    	                    PARAM_CURRENCY => $this -> currency,
    	                    PARAM_RATE => $this -> getRateEx(),
    	                    "uniqueSubmission" => !$this -> isLoopData($invalid) ? 
    	                       $this -> formName.md5($this -> paymentAPIConf -> middleware_sig_passphrase) : NO_STRING,
    	                    PARAM_MESSAGE => $this -> msg
    	                ];
    	            }
	            }else
	                $invalid["OE02"] = $this -> getMessage(ERROR, 'E_CAN_NOT_REMIT_SELF', array());
	        }else
	            $invalid["OE01"] = $this -> getMessage(ERROR, 'E_CAN_NOT_LOGIN', array());
	    }else
	        $invalid["UN01"] = "Invalid Settlement Form Name";
	    
	    $result = [
	        "invalid" => $invalid,
	        "returns" => $return
	    ];
	    
	    $this -> validationResult = json_encode($result);
	}
	
	private function validatePaymentToken(){
	    if($this -> checkNull($this -> paymentToken)){
	        try{
	            $jwtTokenKey = $this -> midconf -> token_secretkey.strtotime(date("Ymd"));
	            $midPsignKey = $this -> paymentAPIConf -> middleware_sig_passphrase;
	            
	            $decoded = JWT::decode(
	                $this -> paymentToken,
	                $jwtTokenKey,
	                [$this -> midconf -> algorithm]);
	            
	            $midsign      = Crypto::decryptWithPassword($decoded -> midsign, $midPsignKey);
	            $settleData   = base64_decode($decoded -> data);
	            
	            if($this -> checkJSONString($midsign) && $this -> checkJSONString($settleData)){
	                $settleData            = json_decode($settleData);
	                $midsign               = json_decode($midsign);
	                $this -> settleForm    = $this -> getSettlementForm($midsign -> uniqueKey);
	                
	                $redirection = function($deleteForm = true) use ($midsign, $settleData) {
	                    if($deleteForm){
	                        $this -> accessModify("DELETE_SETTLEMENT_FORM", [$midsign -> uniqueKey], false);
	                        $this -> setType(TYPE_REQUEST_SESSION_EXPIRED);
	                    }else
	                        header("Location: /{$settleData -> language}");
	                };
	                
	                if($this -> settleForm){
	                    $this -> formName = $midsign -> uniqueKey;
	                    
	                    $now = strtotime(date("YmdHis"));
	                    $exp = strtotime($midsign -> expiration);
	                    
	                    if($now < $exp){
	                        if($this -> getColumnData($this -> settleForm, "is_paid"))
	                            $redirection();
	                        
	                        if($this -> getLangage() != $settleData -> language){
	                            $this -> invalidFormParams[] = $this -> getMessage(ERROR, 'E_ERROR_SAME_DATA', ["language"]);
	                            $this -> setType(TYPE_FAIL);
	                        }
	                    }else
	                        $redirection();
	                }else
	                    $redirection(false);
	            }
	            
	        }catch(Exception $e){
	            // the logic within the catch should be redirection back to main page.
	            // this should be also logged
	            echo $e -> getMessage();
	            header("Location: /{$this -> getLangage()}");
	        }
	    }else
	        header("Location: /{$this -> getLangage()}");
	}
	
	private function validateAccessForm(){
	    $datetime  = date("Y-m-d H:i:s");
	    $accessDir = SITE_ROOT."api/Logs/settlement/access";
	    
	    if(!@file_exists($accessDir))
	        mkdir($accessDir, 0777, true);
	    
	    $logFile = "{$accessDir}/Log_H".date("Y-m-d").".log";
	    $requestHeaders = [
	        "Program Code" => $this -> pNum,
	        "IP_Address" => $this -> getColumnData($_SERVER, "REMOTE_ADDR")
	    ];
	    $requestHeaders = print_r(array_merge($requestHeaders, apache_request_headers()), true);
	    error_log("\r\n[{$datetime}]: {$requestHeaders}\r\n", VAL_INT_3, $logFile);
	    	    
	    $requestMethod = strtoupper($this -> getColumnData($_SERVER, "REQUEST_METHOD"));
	    if($requestMethod != "POST"){
	        $this -> invalidFormParams[] = "Invalid Request Method [{$requestMethod}]";
	    }
	   
	    $settlementFields = [
	        VAL_STR_SIGNATURE => $this -> signature,
	        VAL_STR_P_NUM  => $this -> pNum,
	        VAL_STR_CURRENCY => $this -> currency,
	        VAL_STR_AMOUNT => $this -> amount
	    ];
	    	    	    
	    foreach($settlementFields as $paramName => $paramValue){
	        if($this -> checkNull($paramValue)){
	            switch($paramName){
	                case VAL_STR_AMOUNT:
	                    if(!$this -> checkStringNumber($paramValue))
	                        $this -> invalidFormParams[] = $this -> getMessage(ERROR, 'E_ERROR_REGULAR_NUMBER', [$paramName]);
	                    else if($paramValue <= NO_COUNT)
	                        $this -> invalidFormParams[] = $this -> getMessage(ERROR, 'E_MINIMUM', [$paramName, NO_COUNT]);
	                    break;
	                case VAL_STR_CURRENCY:
	                    if(!$this -> checkCurrency($this -> currency)) 
	                        $this -> invalidFormParams[] = $this -> getMessage(ERROR, 'E_ERROR_SAME_DATA', [$paramName]);
	                    break;
	                case VAL_STR_P_NUM:
	                    $apiSignature = $this -> getRowData($this -> getAPISignatureCommon($this -> pNum));
	                    if(!$this -> isLoopData($apiSignature))
	                        $this -> invalidFormParams[] = $this -> getMessage(ERROR, 'E_ERROR_NOT_EXIST', [$paramName]);
	                    break;
	                case VAL_STR_SIGNATURE:
	                    if(!$this -> checkSettlementSignature($this -> pNum, $this -> signature, $this -> userAccount)) 
	                        $this -> invalidFormParams[] = $this -> getMessage(ERROR, 'E_ERROR_VALUE', [$paramName]);
	                    break;
	            }
	        }else
	            $this -> invalidFormParams[] = $this -> getMessage(ERROR, 'E_REQUIRED_VALUE', array($paramName));
	    }
	    
	    $domWhitelistedDisabled = false;
	    // APIの確認
	    if(!$this -> checkSettlementDomain($this -> pNum, "allow_domain_in_payment", $domWhitelistedDisabled)){
	        if(!$domWhitelistedDisabled)
	            $this -> invalidFormParams[] = $this -> getMessage(ERROR, 'E_ERROR_DOMAIN', array());
	    }
	    
	    $ipWhitelistDisabled = false;
	    // APIの確認
	    if(!$this -> checkSettlementIpAddress($this -> pNum, "allow_ip_in_payment", $ipWhitelistDisabled)) {
	        if(!$ipWhitelistDisabled)
	            $this -> invalidFormParams[] = $this -> getMessage(ERROR, 'E_ERROR_IP_ADDRESS', array());
	    }
	    
	    if(!$this -> isLoopData($this -> invalidFormParams)){
	        // generate form link here
	        $this -> arrangeFormLink();
	    } else
	        $this -> setType(TYPE_FAIL);
	}
	
	private function validateProcessing(){	
	    try{
	        $midPsignKey = $this -> paymentAPIConf -> middleware_sig_passphrase;
	        $jwtTokenKey = $this -> midconf -> token_secretkey.strtotime(date("Ymd"));
	        
	        // throwable
	        $decoded = JWT::decode(
	            $this -> paymentToken,
	            $jwtTokenKey,
	            [$this -> midconf -> algorithm]);
	        
	        // throwable
	        $midsign      = Crypto::decryptWithPassword($decoded -> midsign, $midPsignKey);
	        
	        if($this -> checkJSONString($midsign)){
	            $midsign = json_decode($midsign);
	            
	            $expire    = strtotime($midsign -> expiration);
	            $now       = strtotime(date("YmdHis"));   
	             
	            if($now > $expire)
	                throw new Exception("Session Expired");
	        }else
	            throw new Exception("Not a JSON String");
	        
	        if($this -> uniqueSubmission == $this -> formName.md5($this -> paymentAPIConf -> middleware_sig_passphrase)){
	            $this -> setData();
	            $this -> arrangeFreeParams();
	            
	            if($this -> balance < ($this -> debitAmount + $this -> getFeeEx())) {
	                $this -> invalidFormParams[] = $this -> getMessage(ERROR, 'E_INSUFFICIENT_FUNDS',
	                       array($this -> debitCurrency,
	                       $this -> formatCurrency(($this -> debitAmount + $this -> getFeeEx()), $this -> debitCurrency)));
	            }
	        }else
	            $this -> invalidFormParams[] = "Invalid Submission Identifier!";
	            
	        if($this -> isLoopData($this -> invalidFormParams))
	           $this -> setType(TYPE_FAIL);
	        
	    }catch(Exception $e){
	        $this -> accessModify("DELETE_SETTLEMENT_FORM", [$this -> formName], false);
	        $this -> setType(TYPE_REQUEST_SESSION_EXPIRED);
	    }
	}
	
	private function arrangeFormLink(){
	    $freeParams = [];
	    	    
	    foreach($_POST as $paramName => $paramValue){
	        if(!in_array($paramName, $this -> ignoreParamNames))
	            $freeParams[$paramName] = $paramValue;
	    }
	    
	    $settlementPayload = [
	        PARAM_P_NUM => $this -> pNum,
	        PARAM_SIGNATURE => $this -> signature,
	        PARAM_TITLE => $this -> title,
	        PARAM_LANGUAGE => $this -> getLangage(),
	        PARAM_AMOUNT => $this -> amount,
	        PARAM_CURRENCY => $this -> currency,
	        PARAM_SUCCESS_URL => $this -> successUrl,
	        PARAM_FAIL_URL => $this -> failUrl,
	        PARAM_RETURN_URL => $this -> returnUrl,
	        PARAM_SETTLEMENT_ORIGIN => "standard_form",
	        PARAM_SETTLEMENT_FREE_PARAMS => $freeParams
	    ];
	    	    
	    $jwtPayload = [
	        "purpose" => "PaymentAPI",
	        "created" => date("Y-m-d H:i:s"),
	        "expiration" => date("Y-m-d H:i:s", strtotime($this -> paymentAPIConf -> link_duration)),
	        "data" => base64_encode(json_encode($settlementPayload))
	    ];
	    
	    $jwtToken = JWT::encode($jwtPayload,
	        $this -> midconf -> token_secretkey,
	        $this -> midconf -> algorithm);
	    
	    $baseUrl = SITE_PROTOCOL."://".SITE_DOMAIN_FULL;
	    $tokenUrl = "{$baseUrl}/{$this -> getLangage()}/middleware?token={$jwtToken}";
	    
	    header("Location: {$tokenUrl}");
	}
	
	private function arrangeFreeParams(){
	    $this -> settleForm = $this -> getSettlementForm($this -> formName);
	    $formData = json_decode(base64_decode($this -> getColumnData($this -> settleForm, "form_data")), true);
	    
	    $freeParams   = $this -> getColumnData($formData, PARAM_SETTLEMENT_FREE_PARAMS);
	    foreach(array_keys($freeParams) as $optParamName){
	        if(isset($_POST[$optParamName])){
	            $value = NO_STRING;
	            
	            switch($optParamName){
	                case PARAM_TO_FEE:
	                    $value = $this -> toFee;
	                    break;
	                case PARAM_FROM_FEE:
	                    $value = $this -> fromFee;
	                    break;
	                default:
	                    $value = $this -> getDataPost($optParamName);
	                    break;
	            }
	            
	            $this -> params[$optParamName] = $value;
	        }
	    }
	}
	
	/*-------------------------------------------------------------------------
	* @function_name: サーバ側データチェック
	* @parameter	: なし
	* @return		: TRUE:成功、FALSE:失敗
	-------------------------------------------------------------------------*/
	public function validate() {
	    switch($this -> getType()){
	        case TYPE_SETTLEMENT_EXPRESS_API:
	            $this -> validatePaymentToken();
	            break;
	        case TYPE_SETTLEMENT_EXPRESS_CHECK:
	            $this -> validateSubmission();
	            break;
	        case TYPE_SETTLEMENT_EXPRESS_SUBMIT:
	            $this -> validateProcessing();
	            break;
	        case TYPE_SETTLEMENT_EXPRESS_FORM:
	            $this -> validateAccessForm();
	            break;
	    }
	}

	/*-------------------------------------------------------------------------
	* @function_name: パラメータを設定し直す
	* @parameter	: なし
	* @return		: なし
	-------------------------------------------------------------------------*/
	public function setData() {
		// 変数宣言部
		$exchange	= null;
		$fee		= null;

		// バランスの取得
		$this -> balance = $this -> getBalanceCommon($this -> fromAccount, $this -> debitCurrency);

		// デビット額の計算
		// タイプによって変更パラメータ
		if($this -> currency == $this -> debitCurrency) {	// 通貨が一緒だった場合
			$this -> debitAmount	= $this -> amount;
			$this -> toAmount		= $this -> amount;
			$this -> setRateEx(VAL_INT_1);

		} else {											// 送金通貨指定

			// 出金額の両替
			$exchange = $this -> getExchangeCommon($this -> amount
													, $this -> currency
													, $this -> debitCurrency
													, false
													, true
													, NO_STRING
													, $this -> fromAccount);


			$this -> debitAmount	= $this -> getColumnData($exchange, PARAM_AMOUNT);
			$this -> toAmount		= $this -> amount;
			$this -> setRateEx($this -> getColumnData($exchange, PARAM_RATE));
		}

		// 手数料の取得
		$fee		= $this -> getFeeCommon(VAR_TRANSFER
											, $this -> debitAmount
											, $this -> debitCurrency
											, $this -> fromAccount
											, $this -> userAccount
											, $this -> currency
											, $this -> amount);

		$fee2 = $fee[$this -> currency . VAL_INT_2];

		$this -> setFeeEx($this -> getColumnData($fee, $this -> debitCurrency . VAL_INT_1));
		$this -> setFee2Ex($fee2);

		$this -> toFee    = (($this -> setFee2Ex($fee2))==NULL) ? NO_COUNT : $this -> setFee2Ex($fee2);
		$this -> fromFee  = (($this -> setFeeEx($this -> getColumnData($fee, $this -> debitCurrency . VAL_INT_1))) == NULL) ?
		                          NO_COUNT : $this -> setFeeEx($this -> getColumnData($fee, $this -> debitCurrency . VAL_INT_1));
	}

	public function getAgentCodeURL(){
		$baseUrl = SITE_PROTOCOL.'://'.SITE_DOMAIN_FULL."/{$this -> getLangage()}/register";
		
		if($this -> pNum != NO_STRING){
			$rowData = $this -> getRowData($this -> accessSelect('SELECT_AGENT_CODE_BY_AID', array($this -> pNum)));
			$agentCode = $this -> getColumnData($rowData, COLUMN_AGENT_CODE);
		}
		
		$result = isset($agentCode) ? "{$baseUrl}?reference={$agentCode}" : $baseUrl;
		return $result;
	}
	
	public function echoValidationResult(){
	    header("Content-type: text/json");
	    echo $this -> validationResult;
	}
	
	public function echoInvalidFormParams(){
	    foreach($this -> invalidFormParams as $invalidFormParam){
	        echo "<p class=\"red\"><span class=\"fa fa-times-circle fa-lg\"></span> {$invalidFormParam}</p>";
	    }
	}

	/*-------------------------------------------------------------------------
	* @function_name: 口座番号の取得
	* @parameter	: なし
	* @return		: 口座番号
	-------------------------------------------------------------------------*/
	function echoUserAccount() {
		echo $this -> getUserData(PARAM_USER_ACCOUNT);
	}

	/*-------------------------------------------------------------------------
	* @function_name: 出金通貨の取得
	* @parameter	: なし
	* @return		: 出金通貨
	-------------------------------------------------------------------------*/
	function echoDebitCurrency() {
		echo $this -> debitCurrency;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 出金通貨の取得
	* @parameter	: なし
	* @return		: 出金通貨
	-------------------------------------------------------------------------*/
	function getDebitCurrency() {
		return $this -> debitCurrency;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 出金金額の取得
	* @parameter	: なし
	* @return		: 出金金額
	-------------------------------------------------------------------------*/
	function getDebitAmount() {
		return $this -> debitAmount;
	}

	/*-------------------------------------------------------------------------
	 * @function_name: 出金金額の取得
	* @parameter	: なし
	* @return		: 出金金額
	-------------------------------------------------------------------------*/
	function echoDebitAmount() {
		echo $this -> debitAmount;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 出金金額の取得
	* @parameter	: なし
	* @return		: 出金金額
	-------------------------------------------------------------------------*/
	function dispDebitAmount() {
		echo $this -> formatCurrency($this -> debitAmount, $this -> debitCurrency);
	}

	/*-------------------------------------------------------------------------
	* @function_name: 出金金額合計の取得
	* @parameter	: なし
	* @return		: 出金金額合計
	-------------------------------------------------------------------------*/
	function echoTotalDebitAmount() {
		echo $this -> debitAmount + $this -> getFeeEx();
	}

	/*-------------------------------------------------------------------------
	* @function_name: 出金金額合計の取得
	* @parameter	: なし
	* @return		: 出金金額合計
	-------------------------------------------------------------------------*/
	function dispTotalDebitAmount() {
		echo $this -> formatCurrency($this -> debitAmount + $this -> getFeeEx(), $this -> debitCurrency);
	}

	/*-------------------------------------------------------------------------
	* @function_name: 換金レートの取得
	* @parameter	: なし
	* @return		: 換金レート
	-------------------------------------------------------------------------*/
	function echoRate() {
		echo $this -> getRateEx();
	}
	
	function echoFormName() {
	    echo $this -> formName;
	}
	
	function getFormName(){
	    return $this -> formName;
	}


	/*-------------------------------------------------------------------------
	* @function_name: 手数料金額の取得
	* @parameter	: なし
	* @return		: 手数料金額
	-------------------------------------------------------------------------*/
	function dispFeeAmount() {
		echo $this -> formatCurrency($this -> getFeeEx(), $this -> debitCurrency);
	}

	/*-------------------------------------------------------------------------
	* @function_name: シグネチャの取得
	* @parameter	: なし
	* @return		: シグネチャ
	-------------------------------------------------------------------------*/
	function echoSignature() {
		echo $this -> signature;
	}

	function getFromAccount(){
	    return $this -> fromAccount;
	}
	
	/*-------------------------------------------------------------------------
	* @function_name: 口座番号の取得
	* @parameter	: なし
	* @return		: 口座番号
	-------------------------------------------------------------------------*/
	function echoToAccount() {
		echo $this -> userAccount;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 口座番号の取得
	* @parameter	: なし
	* @return		: 口座番号
	-------------------------------------------------------------------------*/
	function getToAccount() {
		return $this -> userAccount;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 通貨の取得
	* @parameter	: なし
	* @return		: 通貨
	-------------------------------------------------------------------------*/
	function echoCurrency() {
		echo $this -> currency;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 通貨の取得
	* @parameter	: なし
	* @return		: 通貨
	-------------------------------------------------------------------------*/
	function getCurrency() {
		return $this -> currency;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 商品名の取得
	* @parameter	: なし
	* @return		: 商品名
	-------------------------------------------------------------------------*/
	function echoTitle() {
		echo $this -> title;
	}

	/*-------------------------------------------------------------------------
	* @function_name: ユーザの入力額の取得
	* @parameter	: なし
	* @return		: ユーザの入力額
	-------------------------------------------------------------------------*/
	function dispAmount() {
		echo $this -> formatCurrency($this -> amount, $this -> currency);
	}

	/*-------------------------------------------------------------------------
	* @function_name: ユーザの入力額の取得
	* @parameter	: なし
	* @return		: ユーザの入力額
	-------------------------------------------------------------------------*/
	function getAmount() {
		return $this -> amount;
	}

	/*-------------------------------------------------------------------------
	 * @function_name: ユーザの入力額の取得
	* @parameter	: なし
	* @return		: ユーザの入力額
	-------------------------------------------------------------------------*/
	function echoAmount() {
		echo $this -> amount;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 送金メッセージの取得
	* @parameter	: なし
	* @return		: 送金メッセージ
	-------------------------------------------------------------------------*/
	function dispMsg() {
		echo nl2br($this -> msg);
	}

	/*-------------------------------------------------------------------------
	* @function_name: 通貨リストの取得
	* @parameter	: なし
	* @return		: 表示用HTML文字列
	-------------------------------------------------------------------------*/
	function dispCurrency() {
		echo $this -> dispListOption($this -> getCurrencyList(), $this -> debitCurrency) ;
	}

	/*-------------------------------------------------------------------------
	 * @function_name: 通貨リストの取得
	* @parameter	: なし
	* @return		: 表示用HTML文字列
	-------------------------------------------------------------------------*/
	function echoSuccessUrl() {
		echo $this -> successUrl;
	}

	/*-------------------------------------------------------------------------
	 * @function_name: 通貨リストの取得
	* @parameter	: なし
	* @return		: 表示用HTML文字列
	-------------------------------------------------------------------------*/
	function echoFailUrl() {
		echo $this -> failUrl;
	}

	/*-------------------------------------------------------------------------
	 * @function_name: 通貨リストの取得
	* @parameter	: なし
	* @return		: 表示用HTML文字列
	-------------------------------------------------------------------------*/
	function echoCancelUrl() {
		echo $this -> cancelUrl;
	}

	/*-------------------------------------------------------------------------
	 * @function_name: 通貨リストの取得
	* @parameter	: なし
	* @return		: 表示用HTML文字列
	-------------------------------------------------------------------------*/
	function echoReturnUrl() {
		echo $this -> returnUrl;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 任意パラメータの取得
	* @parameter	: なし
	* @return		: HiddenHTML文字列
	-------------------------------------------------------------------------*/
	function echoParams() {
		// 変数宣言部
		$rtn = NO_STRING;

		if($this -> isLoopData($this -> params)) {
			foreach($this -> params as $key => $val) 
				$rtn .= '<input type="hidden" value="' . $val . '" name="' . $key . '" />';
		}

		echo $rtn;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 転送先URLの取得
	* @parameter	: なし
	* @return		: 転送先URL
	-------------------------------------------------------------------------*/
	function getUrl() {
		return $this -> successUrl;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 転送先URLの取得
	* @parameter	: なし
	* @return		: 転送先URL
	-------------------------------------------------------------------------*/
	function getFailUrl() {
		return $this -> failUrl;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 転送先URLの取得
	* @parameter	: なし
	* @return		: 転送先URL
	-------------------------------------------------------------------------*/
	function getCallBackUrl() {
		return $this -> returnUrl;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 転送先URLの取得
	* @parameter	: なし
	* @return		: 転送先URL
	-------------------------------------------------------------------------*/
	function echoPNum() {
		echo $this -> pNum;
	}
	
	/*-------------------------------------------------------------------------
	 * @function_name: 番組コードの取得
	 * @parameter	: なし
	 * @return		: 転送先URL
	 -------------------------------------------------------------------------*/
	function getProgramCode() {
	    return $this -> pNum;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 送金元手数料の取得
	* @parameter	: なし
	* @return		: 送金元手数料
	-------------------------------------------------------------------------*/
	function getFromFee() {
		return $this -> fromFee;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 送金先手数料の取得
	* @parameter	: なし
	* @return		: 送金先手数料
	-------------------------------------------------------------------------*/
	function getToFee() {
		return $this -> toFee;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 任意パラメータの取得
	* @parameter	: なし
	* @return		: HiddenHTML文字列
	-------------------------------------------------------------------------*/
	function getForwardParams($result) {

		// 変数宣言部
		$rtn = array();

		// 固定パラメータ
		$rtn[PARAM_AMOUNT]				= $this -> amount;
		$rtn[PARAM_CURRENCY]			= $this -> currency;
		$rtn[PARAM_P_NUM]				= $this -> pNum;
		$rtn[PARAM_TRANSACTION_NUMBER]	= $this -> transactionNumber;
		$rtn[PARAM_RESULT]				= $result;

		// 任意パラメータがある場合
		if($this -> isLoopData($this -> params)) {

			foreach($this -> params as $key => $val) {
				$rtn[$key] = $val;
			}
		}

		return $rtn;
	}

	/*-------------------------------------------------------------------------
	* @function_name: 表示名の取得
	* @parameter	: なし
	* @return		: サイト名・屋号または会社名
	-------------------------------------------------------------------------*/
	function dispSiteName() {

		if($this -> getColumnData($this -> account, COLUMN_SITE_NAME) != NO_STRING) {	// サイト名がある場合
			echo $this -> getColumnData($this -> account, COLUMN_SITE_NAME);
		} else {																		// 氏名を表示
			echo $this -> getColumnData($this -> account, COLUMN_FIRST_NAME)
					. DELIMIT_SPACE . $this -> getColumnData($this -> account, COLUMN_LAST_NAME);
		}
	}

	/*-------------------------------------------------------------------------
	* @function_name: 受取人口座情報の取得
	* @parameter	: なし
	* @return		: 登録用データ
	-------------------------------------------------------------------------*/
	public function setAccount($rs) {
		$this -> account = $this -> getRowData($rs);
	}

	/*-------------------------------------------------------------------------
	* @function_name: 登録用のデータを取得
	* @parameter	: なし
	* @return		: 登録用データ
	-------------------------------------------------------------------------*/
	public function getRegistData() {

		// 変数宣言部
		$rtn = array();

		// 取引番号の取得
		$this -> transactionNumber = $this -> getTransactionNumberCommon(VAR_TRANSACTION_TRANSFER_DEPOSIT);
		
		// will include account # within API callback - anton
		$this -> params[PARAM_FROM_ACCOUNT]   = $this -> fromAccount;
		$this -> params[PARAM_TO_ACCOUNT]     = $this -> userAccount;
		
		$rtn[] = $this -> fromAccount;										// 送金元口座番号
		$rtn[] = $this -> fromAccount;										// 送金元口座番号
		$rtn[] = $this -> debitCurrency;														// 送金通貨
		$rtn[] = $this -> currencyToInt($this -> fromFee, $this -> debitCurrency);				// 口座元手数料
		$rtn[] = $this -> userAccount;															// 送金先口座番号
		$rtn[] = $this -> currency;																// 送金元通貨
		$rtn[] = $this -> currencyToInt($this -> toFee, $this -> currency);						// 送金先手数料
		$rtn[] = $this -> amount;																// 入力金額
		$rtn[] = VAL_INT_1;																		// 送金方法
		$rtn[] = addslashes($this-> getExtraMessage($this -> userAccount, $this -> params, getSpecialClientList()) . $this -> msg);														// メッセージ
		$rtn[] = $this -> debitCurrency;														// 出金通貨
		$rtn[] = $this -> currencyToInt($this -> debitAmount, $this -> debitCurrency);			// 出金金額
		$rtn[] = $this -> currency;																// 送金通貨
		$rtn[] = $this -> currencyToInt($this -> amount, $this -> currency);					// 送金金額
		$rtn[] = $this -> getRateEx();															// レート
		$rtn[] = NO_COUNT;																		// 処理種別
		$rtn[] = NO_STRING;																		// 管理者ID
		$rtn[] = VAL_INT_2;																		// 処理ステータス（API）
		$rtn[] = $this -> transactionNumber;													// トランザクションナンバー
		$rtn[] = json_encode($this -> params);													// トランザクションナンバー

		return $rtn;
	}

	/*-------------------------------------------------------------------------
	 * @function_name: メール送信用のデータを取得（送金元ユーザ）
	* @parameter	: なし
	* @return		: メール送信用データ
	-------------------------------------------------------------------------*/
	public function getSendDataFrom() {

		// 変数宣言部
		$rtn	= array();
		$data	= $this -> getAccountCommon($this -> fromAccount);
		$row	= $this -> getRowData($data);
		$data2	= $this -> getAccountCommon($this -> userAccount);
		$row2	= $this -> getRowData($data2);

		$rtn[] = $this -> fromAccount;										// ユーザ口座番号
		$rtn[] = $this -> getColumnData($row, COLUMN_FIRST_NAME)
				. DELIMIT_SPACE . $this -> getColumnData($row, COLUMN_LAST_NAME);				// ユーザ名
		$rtn[] = $this -> userAccount;															// 送金先口座番号
		$rtn[] = $this -> getColumnData($row2, COLUMN_FIRST_NAME)
				. DELIMIT_SPACE . $this -> getColumnData($row2, COLUMN_LAST_NAME);				// ユーザ名（送金先）
		$rtn[] = $this -> getCurrentTimeCommon();												// 現在時刻
		$rtn[] = $this -> debitCurrency;														// 通貨
		$rtn[] = $this -> formatCurrency($this -> debitAmount, $this -> debitCurrency);			// 金額
		$rtn[] = $this -> debitCurrency;														// 手数料通貨
		$rtn[] = $this -> formatCurrency($this -> fromFee, $this -> debitCurrency);				// 手数料
		$rtn[] = $this -> msg;																	// メッセージ
		$rtn[] = $this -> transactionNumber;													// 取引番号
		$rtn[] = $this -> getColumnData($row, COLUMN_MAIL);										// メールアドレス

		return $rtn;
	}

	/*-------------------------------------------------------------------------
	 * @function_name: メール送信用のデータを取得（送金先ユーザ）
	* @parameter	: なし
	* @return		: メール送信用データ
	-------------------------------------------------------------------------*/
	public function getSendDataTo() {

		// 変数宣言部
		$rtn	= array();
		$data	= $this -> getAccountCommon($this -> fromAccount);
		$row	= $this -> getRowData($data);
		$data2	= $this -> getAccountCommon($this -> userAccount);
		$row2	= $this -> getRowData($data2);

		$rtn[] = $this -> userAccount;															// ユーザ口座番号
		$rtn[] = $this -> getColumnData($row2, COLUMN_FIRST_NAME)
					. DELIMIT_SPACE . $this -> getColumnData($row2, COLUMN_LAST_NAME);			// ユーザ名
		$rtn[] = $this -> fromAccount;										// 送金先口座番号
		$rtn[] = $this -> getColumnData($row, COLUMN_FIRST_NAME)
					. DELIMIT_SPACE . $this -> getColumnData($row, COLUMN_LAST_NAME);			// ユーザ名（送金元）
		$rtn[] = $this -> getCurrentTimeCommon();												// 現在時刻
		$rtn[] = $this -> currency;																// 通貨
		$rtn[] = $this -> formatCurrency($this -> amount, $this -> currency);					// 金額
		$rtn[] = $this -> debitCurrency;														// 手数料通貨
		$rtn[] = $this -> formatCurrency($this -> toFee, $this -> currency);					// 手数料
		$rtn[] = $this -> msg;																	// メッセージ
		$rtn[] = $this -> transactionNumber;													// 取引番号
		$rtn[] = $this -> getColumnData($row2, COLUMN_MAIL);									// メールアドレス

		return $rtn;
	}


	/*-------------------------------------------------------------------------
	* @function_name: HTML表示用のデータ取得関数
	* @parameter	: なし
	* @return		: HTML表示用データ配列
	-------------------------------------------------------------------------*/
	public function dispHTML() {
		return array();
	}

	public function getExtraMessage($client, $params, $specialClientArray){
		$rtn = '';

			if(array_key_exists($client, $specialClientArray)){

				foreach($specialClientArray[$client] as $val) {
					if(array_key_exists($val,$params)){
						$rtn .= $val . ' : ' . $params[$val].'<br>';
					}
				}
			}
		return $rtn;
	}
}
?>
