<?php
require_once "../lib/config.php";

class MonthlyCharge extends System {
    
    /**
     * 
     * @var integer
     */
    private $forTest;
    
    /**
     * 
     * @var integer
     */
    private $userAccount;
    
    /**
     * 
     * @var string
     */
    private $ipAddress;
    
    /**
     * 
     * @var string
     */
    private $contentType;
    
    /**
     * 
     * @var string
     */
    private $requestMethod;
    
    /**
     * 
     * @var array
     */
    private $collatedTransactions = [];
    
    /**
     * 
     * コンストラクタ
     * 
     */
    public function __construct(){
        parent::__construct();
        header("Content-type: text/plain");
        
        $this -> setParameter();
        $this -> validation();
    }
    
    /**
     * 
     * パラメータの設定
     * 
     */
    private function setParameter(){
        $this -> forTest        = $this -> getDataPost("test");
        $this -> userAccount    = $this -> getDataPost("userAccount");
        $this -> ipAddress      = $this -> getColumnData($_SERVER, "REMOTE_ADDR");
        $this -> contentType    = $this -> getColumnData($_SERVER, "CONTENT_TYPE");
        $this -> requestMethod  = $this -> getColumnData($_SERVER, "REQUEST_METHOD");
    }
    
    /**
     * 
     * 確認の機能
     * 
     */
    private function validation(){
        $validation = [];
        
        $chargeAPIConf = $this -> getSettingConfiguration("charge_api_conf");
        
        $ipAddresses = explode(",", $chargeAPIConf -> ip_address);
        
        if(strtoupper($this -> requestMethod) != "POST")
            $validation[] = "Invalid Request Method: {$this -> requestMethod}";
        
        if(!in_array($this -> ipAddress, $ipAddresses))
            $validation[] = "Invalid IP Address: {$this -> ipAddress}";
        
        if($this -> contentType != "application/x-www-form-urlencoded")
            $validation[] = "Invalid Content-type: {$this -> contentType}";
        
        if(!$this -> isLoopData($this -> getAccountCommon($this -> userAccount)))
            $validation[] = "Account doesn't exist: {$this -> userAccount}";
        
        if($this -> isLoopData($validation)){
            header("HTTP/1.1 403 Forbidden due to validation results");
            die(json_encode($validation));
        }
    }
    
    /**
     * 
     * @param integer $account
     * @param string $currency
     * @param double $amount
     */
    private function executeWithdraw($account, $currency, $amount){
        if($amount <= NO_COUNT)
            return;
        
        $params = $this -> transactionParams($account, $currency, $amount);
        
        if ($this -> forTest) {
            $params[] = "test-only";
        } else
            $this -> monthlyWithdraw($params);
        
        $params[VAL_INT_2] = $this -> intToCurrency($amount, $currency); 
        
        $this -> collatedTransactions[] = $params;
    }
    
    /**
     * 
     * @param integer $account
     * @param string $currency
     * @param double $amount
     */
    private function monthlyWithdraw($params) {    
        // データを登録する
        return $this -> accessModify('INSERT_WITHDRAW_FEE', $params);
    }
    
    /**
     * 
     * @param unknown $account
     * @param unknown $currency
     * @param unknown $amount
     * @return string[]
     */
    private function transactionParams($account, $currency, $amount){
        $params = [];
        $feeInt = $amount;
        
        // パラメータの作成
        $params[] = $account;
        $params[] = $currency;
        $params[] = $feeInt;
        $params[] = VAR_WITHDRAW_TYPE_FEE;
        $params[] = $this -> getTransactionNumberCommon(VAR_TRANSACTION_MONTHLY_FEE);
        $params[] = "Monthly Maintenance";
        $params[] = VAL_INT_2;
        
        return $params;
    }
    
    /**
     *
     * 毎月の保守料の活用
     * 
     */
    private function charge(){     
        // 維持費を取得する
        $fee = $this -> getFeeCommon(VAR_MONTHLY, NO_COUNT, USD, $this -> userAccount);
        
        // USD手数料
        $feeInt = $this -> currencyToInt($this -> getColumnData($fee, USD . VAL_INT_1), USD);
        
        // 手数料が無い人は、飛ばす
        if($feeInt == NO_COUNT) 
            return;
        
        // ユーザの残高を取得する
        $balances = $this -> getBalanceListCommon($this -> userAccount);
        
        if($this -> isLoopData($balances)) {
            // まずは、USD優先
            if(isset($balances[USD])) {
                // USD口座で賄えた場合
                if($feeInt <= $balances[USD]) {
                    // 出金処理
                    $this -> executeWithdraw($this -> userAccount, USD, $feeInt); 
                    return;
                } else {
                    // 出金処理
                    $this -> executeWithdraw($this -> userAccount, USD, $balances[USD]);
                    $feeInt -= $balances[USD];
                }
                
                unset($balances[USD]);
            }
            
            $zeroDecimalCurrencies = $this -> getZeroDecimalCurrenciesCommon();
            // Loop until maintenance costs are gone
            foreach($balances as $currency => $balance) {
                // Money exchange
                $exchange	= $this -> getExchangeCommon($balance, $currency, USD, true, false);
                
                if(in_array($currency, $zeroDecimalCurrencies))
                    $remaining	= floor($this -> getColumnData($exchange, PARAM_AMOUNT)*100);
                else
                    $remaining	= floor($this -> getColumnData($exchange, PARAM_AMOUNT));
                
                // 相殺できてるか
                if($feeInt <= $remaining) {
                    $exchange	= $this -> getExchangeCommon($feeInt, USD, $currency,true, true);
                    if(in_array($currency, $zeroDecimalCurrencies))
                        $feeval		= floor($this -> getColumnData($exchange, PARAM_AMOUNT)/100);
                    else
                        $feeval		= floor($this -> getColumnData($exchange, PARAM_AMOUNT));
                    
                    // 出金処理
                    $this -> executeWithdraw($this -> userAccount, $currency, $feeval);
                    break;
                } else {
                    // 出金処理
                    $this -> executeWithdraw($this -> userAccount, $currency, $balance);
                    $feeInt -= $remaining;
                }
                
                // 手数料が無くなったら終了
                if($feeInt <= NO_COUNT) 
                    break;
            }
        }
    }
    
    /**
     * 
     * 主な機能
     * 
     */
    public function listen(){
        $this -> charge();
        
        echo json_encode($this -> collatedTransactions);
    }
}

$charge = new MonthlyCharge();
$charge -> listen();