<?php

namespace MGModule\DNSManager2\mgLibs\custom\dns\submodules;

use \MGModule\DNSManager2\mgLibs\custom\dns;
use \MGModule\DNSManager2\mgLibs\custom\dns\exceptions;
use \MGModule\DNSManager2\mgLibs\custom\dns\interfaces;
use \MGModule\DNSManager2\mgLibs\custom\dns\utils\Patterns;

class RRPproxy extends dns\SubmoduleAbstract 
    implements interfaces\SubmoduleTTLInterface, 
        interfaces\SubmoduleImportInterface, 
        interfaces\SubmoduleRDNSInterface,
        interfaces\SubmoduleCustomParseEditZoneInput,
        interfaces\SubmoduleCustomEditRecords
{  
    CONST URL = 'https://api.rrpproxy.net:8082/soap';
    
    public $configFields = array (
        'username' => array (
                'friendlyName'  =>  'Username',
                'validators' => array(
                    'required' => 'required',
                )
        ),
        'password' => array (
                'friendlyName'  => 'User Password',
                'type'=> 'password',
                'validators' => array(
                    'required' => 'required',
                )
        ),
        'default_ip' => array (
                'friendlyName'  =>  'Default IP',
                'validators' => array(
                    'pattern' => Patterns::IP4_OR_IP6,
                )
        ),
    );
    
    public $availableTypes = array('A', 'AAAA', 'NS', 'MX', 'CNAME', 'TXT', 'SRV', 'PTR','NAPTR','X-SMTP','X-HTTP');

    
    
    private function verifySoap( )
    {
        if(  !class_exists( 'SoapClient' ))
        {
            throw new exceptions\DNSSubmoduleException("SOAP Error: Soap not found" , dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM);
        }
    }




    private function get($command, $params = array()) {
        
        $this->verifySoap();
        
        $params = array(array_merge($params, array(
                "s_login" => $this->config['username'],
                "s_pw" => $this->config['password'],
                "command" => $command,
            ))
        );
        
        $client = new \SoapClient(NULL, array(
                "location" => self::URL,
                "uri" => "urn:Api",
                "style" => SOAP_RPC,
                "use" => SOAP_ENCODED,
                "exceptions" => 0
            )
        );
        
        $result = $client->__call("xcall", $params,
            array("uri" => "urn:Api", "soapaction" => "urn:Api#xcall")
        );
        
        if (is_soap_fault($result)) {
            throw new exceptions\DNSSubmoduleException("SOAP Error: " . $result->faultcode . " - " . $result->faultstring, dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM);
        }
        
        if($result->CODE != 200) {
            throw new exceptions\DNSSubmoduleException($result->DESCRIPTION?:"Unknown Error", dns\SubmoduleExceptionCodes::COMMAND_ERROR);
        }
        
        return $result;
    }
 
    public function testConnection() {
        $this->get('QueryDNSZoneList', array('limit' => 1));  
    }
    
    public function zoneExists() {
        try {
            $out = $this->get('QueryDNSZoneList', array('dnszone' => $this->domain, 'limit' => 1));
        } catch (exceptions\DNSSubmoduleException $e) {
            if($e->getCode() == dns\SubmoduleExceptionCodes::COMMAND_ERROR) {
                return false;
            }
            throw $e;
        }
        
        return !empty($out->PROPERTY->DNSZONE);
    }

    public function getRecords($recordType = false) {
        $result = $this->get('QueryDNSZoneRRList', array('dnszone' => $this->domain));
 
        $out = array();
        foreach($result->PROPERTY->RR as $line => $r) {
            $pad = array_pad(explode(' ',$r), 5, ''); //two line record parser ;)
            list($name, $ttl, $class, $type, $value) = array_merge(array_slice($pad,0, 4), array(implode(' ', array_slice($pad,4))));
            if(in_array($type, $recordType!==false ? array(strtoupper($recordType)) : $this->getAvailableRecordTypes())) {
                $record = new dns\record\Record();
                $record->line = $line;
                $record->name = $name;
                $record->type = $type;
                $record->ttl = $ttl;
                $record->createRDATAObject();
                $record->rdata->fromString($value);
                $out[] = $record;
            }
        }

        return $out;
    }

    private function recordToString($record) {
        $name = $record->nameToAbsolute($this->domain, true);
        return $name . " " . $record->ttl . " " . strtoupper($record->type) . " " . $record->rdata->toString();
    }
    
    public function addRecord(dns\record\Record $record) { 
        $params = array(
            'dnszone' => $this->domain,
            'addrr0' => $this->recordToString($record),
        );
        
        $this->get('ModifyDNSZone', $params);
    }

    public function editRecord(dns\record\Record $record) {
        $params = array(
            "dnszone" => $this->domain,
            'rr' . $record->line => $this->recordToString($record), //TODO: string czy do arraya line dac?
        );

        $this->get('ModifyDNSZone', $params);
    }

    public function deleteRecord(dns\record\Record $record) {
        $params = array(
            "dnszone" => $this->domain,
            'delrr' . $record->line => $this->recordToString($record),
        );

        $this->get('ModifyDNSZone', $params);
    }
    
    public function activateZone() {
        $params = array(
           'dnszone' => $this->domain
        );
       
        $out = $this->get('AddDNSZone', $params);
    }

    public function terminateZone() {
        $params = array(
           'dnszone' => $this->domain
        );
        $this->get('DeleteDNSZone', $params);        
    }

    public function getZones() {
        $ret = $this->get('QueryDNSZoneList');
        $out = array();
        $dnsZones = $ret->dnszone ? $ret->dnszone : $ret->PROPERTY->DNSZONE;
        foreach($dnsZones as $zone) {
            $out[$zone] = '';
        }
        return $out;
    }
    
    public function convertInputFormData(&$input)
    {
        if(count($input['edit_record']) > 0)
        {
            $input['edit_record'] = array_merge($input['edit_record'], $input['record']);
        }
    }
    
    public function customEditRecords($input)
    {
        if(count($input['edit_record']) == 0)
        {
            return true;
        }
        
        $records = array();
        foreach($input['edit_record'] as $record_data)
        {
            $records[] = $this->createRecordFromInput($record_data);
        }        
        
        
        $params = array(
            "dnszone" => $this->domain,
            //'rr' . $record->line => $this->recordToString($record), //TODO: string czy do arraya line dac?
        );
        
        foreach($records as $record)
        {
            $params['rr' . $record->line] = $this->recordToString($record);
        }

        $this->get('ModifyDNSZone', $params);     
        
        return true;
    }
    
    private function createRecordFromInput($input)
    {
        $record = dns\record\Record::tryToCreateFromArray($input);
        $record->rdata->setDataFromArray($input['field']);
        $record->decode();
        
        return $record;
    }    
}
