<?php
include_once "../lib/FrameworkTest.php";

class ConnectSite extends FrameworkTest {
    
    /**
     * 
     * @var string
     */
    private $requestMethod             = NO_STRING;
    
    /**
     * 
     * @var string
     */
    private $contentType               = NO_STRING;
    
    /**
     * 
     * @var string
     */
    private $payload                   = NO_STRING;
    
    /**
     * 
     * @var string
     */
    private $connectURL                = NO_STRING;
    
    /**
     * 
     * @var string
     */
    private $connectRequestParams      = NO_STRING;
    
    /**
     * 
     * @var string
     */
    private $connectRequestMethod      = NO_STRING;
    
    /**
     * 
     * @var boolean
     */
    private $showResponseHeaders       = false;
    
    /**
     * 
     * @var array
     */
    private $connectRequestHeader      = [];
    
    public function __construct(){
        parent::__construct();
        
        $this -> setParameter();
        $this -> validation();
    }
    
    private function setParameter(){
        $this -> requestMethod  = $this -> getColumnData($_SERVER, "REQUEST_METHOD");
        $this -> contentType    = $this -> getColumnData($_SERVER, "CONTENT_TYPE");
        
        $this -> payload        = file_get_contents("php://input");
    }
    
    private function validation(){
        $validationRemarks = [];
                
        if(strcasecmp($this -> requestMethod, "POST") !== 0){
            $validationRemarks[] = json_encode([
                "code" => "001",
                "message" => "Invalid Request Type {$this -> requestMethod}"
            ]);
        }
        
        if(!$this -> checkJSONString($this -> payload)){
            $validationRemarks[] = json_encode([
                "code" => "002",
                "message" => "Payload is not a JSON String"
            ]);
        }else
            $this -> authenticatePayload();
        
        if($this -> connectURL == NO_STRING){
            $validationRemarks[] = json_encode([
                "code" => "003",
                "message" => "No Callback URL Specified"
            ]);
        }
        
        if($this -> contentType != "application/json"){
            $validationRemarks[] = json_encode([
                "code" => "004",
                "message" => "Invalid Content Type: {$this -> contentType}"
            ]);
        }
        
        if(!$this -> checkRemoteAddress()){
            $validationRemarks[] = json_encode([
                "code" => "005",
                "message" => "Invalid IP Address: {$this -> getColumnData($_SERVER, "REMOTE_ADDR")}"
            ]);
        }
        
        if($this -> isLoopData($validationRemarks)){
            echo "<pre>";
            die(print_r($validationRemarks, true));
        }
    }
    
    private function authenticatePayload(){
        $this -> payload = json_decode($this -> payload);
        
        if(isset($this -> payload -> connectUrl)){
            $this -> connectURL = $this -> payload -> connectUrl;
        }
        
        if(isset($this -> payload -> requestMethod)){
            $this -> requestMethod = $this -> payload -> requestMethod;
        }
        
        if(isset($this -> payload -> requestParams)){
            $tempRequestParam = $this -> payload -> requestParams;
            
            if(is_object($tempRequestParam))
                $this -> connectRequestParams = http_build_query($tempRequestParam);
            else if(is_string($tempRequestParam))
                $this -> connectRequestParams = $tempRequestParam;
        }
        
        if(isset($this -> payload -> requestHeaders)){
            if(is_array($this -> payload -> requestHeaders))
                $this -> connectRequestHeader = $this -> payload -> requestHeaders;
        }
        
        if(isset($this -> payload -> responseHeaders)){
            $this -> showResponseHeaders = $this -> payload -> responseHeaders;
        }
    }
    
    private function processRequest(&$statusCode = NO_STRING){
        $handle = curl_init($this -> connectURL);
        
        curl_setopt($handle, CURLOPT_CUSTOMREQUEST, $this -> requestMethod);    
        curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($handle, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($handle, CURLOPT_ENCODING, "utf8");
        curl_setopt($handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
        curl_setopt($handle, CURLOPT_HEADER, $this -> showResponseHeaders);
        
        if($this -> isLoopData($this -> connectRequestHeader)){
            curl_setopt($handle, CURLOPT_HTTPHEADER, $this -> connectRequestHeader);
        }
        
        if($this -> connectRequestParams != NO_STRING){
            curl_setopt($handle, CURLOPT_POSTFIELDS, $this -> connectRequestParams);
        }
        
        if($this -> showResponseHeaders){
            $output = curl_exec($handle);
            
            $headerSize = curl_getinfo($handle, CURLINFO_HEADER_SIZE);
            
            $responseHeaders    = substr($output, 0, $headerSize);
            $responseBody       = substr($output, $headerSize);
            
            $output = "[Headers]\n\n{$responseHeaders}[Body]\n\n{$responseBody}";
        }else
            $output = curl_exec($handle);
        
        $statusCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
        
        if($err = curl_error($handle)){
            $output = $err;
        }
        
        curl_close($handle);
        
        return $output;
    }
    
    public function listen(){        
        $serverName = $this -> getColumnData($_SERVER, "SERVER_NAME");
        
        $requestee = $this -> getColumnData(parse_url($this -> connectURL), "host");
        
        $processingDetails = [
            "Requester_Name" => $serverName,
            "Requester_IP" => gethostbyname($serverName),
            "Requestee_Name" => $requestee,
            "Requestee_IP" => gethostbyname($requestee),
            "Requestee_URL" => $this -> connectURL,
            "Request_Headers" => $this -> connectRequestHeader,
            "Request_Params" => $this -> connectRequestParams,
        ];
        
        print_r($processingDetails);
        
        
        $statusCode = NO_STRING;
        $result = $this -> processRequest($statusCode);
        
        echo "\n\nResult:\n";
        echo "Response Code: {$statusCode}\n\n";
        echo $result;
    }
}

$connect = new ConnectSite();
$connect -> listen();