<?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;

class Rage4 extends dns\SubmoduleAbstract implements
interfaces\SubmoduleRDNSInterface, interfaces\SubmoduleTTLInterface, interfaces\SubmoduleImportInterface
{

    public $configFields   = array(
        'username' => array(
            'friendlyName' => 'Username',
            'validators'   => array(
                'required' => 'required',
            )
        ),
        'apikey'   => array(
            'friendlyName' => 'API Key',
            'validators'   => array(
                'required' => 'required',
            )
        ),
        'priority' => array(
            'friendlyName' => 'Default Priority',
            'validators'   => array(
                'required' => 'required',
            )
        ),
    );
    public $availableTypes = array(0 => 'SOA', 1 => 'NS', 2 => 'A', 3 => 'AAAA', 4 => 'CNAME', 5 => 'MX', 6 => 'TXT', 7 => 'SRV', 8 => 'PTR', 9 => 'SPF');
    private $domainID      = false;

    private function get($params)
    {
        $url = 'https://secure.rage4.com/rapi/' . $params[ 'action' ];
        unset($params[ 'action' ]);
        if (!empty($params))
        {
            $url .= '/' . (!empty($params[ 'line_id' ]) ? $params[ 'line_id' ] : '') . '?';
            unset($params[ 'line_id' ]);
            foreach ($params as $k => $v)
            {
                $url .= $k . '=' . urlencode($v) . '&';
            }
        }
        $url = trim($url, '&');

        $ch     = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_USERPWD, $this->config[ 'username' ] . ":" . $this->config[ 'apikey' ]);
        $result = curl_exec($ch);

        if (curl_errno($ch) != 0)
        {
            throw new exceptions\DNSSubmoduleException('cURL error: ' . (curl_error($ch) ?: 'Unknown Error'), dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM);
        }

        if (empty($result) || strpos($result, 'Object moved'))
        {
            throw new exceptions\DNSSubmoduleException('Invalid username or Password', dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM);
        }

        curl_close($ch);
        $result = json_decode($result, true);

        if ($result === false || !is_array($result))
        {
            throw new exceptions\DNSSubmoduleException('Cannot parse response', dns\SubmoduleExceptionCodes::INVALID_RESPONSE);
        }

        if (!empty($result[ 'error' ]))
        {
            throw new exceptions\DNSSubmoduleException($result[ 'error' ], dns\SubmoduleExceptionCodes::COMMAND_ERROR);
        }

        return $result;
    }

    public function testConnection()
    {
        $params = array(
            'action' => 'GetDomains',
        );

        $this->get($params);
        return true;
    }

    public function zoneExists()
    {
        try
        {
            $this->domain_id();
            return true;
        }
        catch (exceptions\DNSSubmoduleException $e)
        {
            if ($e->getCode() == dns\SubmoduleExceptionCodes::COMMAND_ERROR)
            {
                return false;
            }
            throw $e;
        }
    }

    public function activateZone()
    {
        $is_ipv6 = preg_match('/.ip6.arpa$/', $this->domain);
        $ex      = explode('.', $this->domain);
        if (end($ex) == 'arpa')
        {
            $params = array(
                'action' => $is_ipv6 ? 'CreateReverseDomain6' : 'CreateReverseDomain4',
                'name'   => $is_ipv6 ? '0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.' . $this->domain : $this->domain,
                'subnet' => $is_ipv6 ? 64 : 8,
                'email'  => $this->config[ 'username' ]
            );
        }
        else
        {
            $params = array(
                'action' => 'CreateRegularDomain',
                'name'   => $this->domain,
                'email'  => $this->config[ 'username' ]
            );
        }

        $result = $this->get($params, true);


//            $current_records = $this->getRecords(); 
//            foreach($current_records as $r)
//                if($r['type'] == 'NS')
//                    $this->delete(array($r));
    }

    public function terminateZone()
    {
        $params = array(
            'id'     => $this->domain_id(),
            'action' => 'DeleteDomain'
        );
        $this->get($params);
    }

    public function getRecords($recordType = false)
    {

        $params = array(
            'action' => 'GetRecords',
            'id'     => $this->domain_id(),
            'name'   => $this->domain
        );
        $result = $this->get($params);

        $out = array();
        foreach ($result as $k => $r)
        {
            if (in_array((string) $r[ 'type' ], $recordType !== false ? array(strtoupper($recordType)) : $this->getAvailableRecordTypes()))
            {
                $record       = new dns\record\Record();
                $record->line = $r[ 'id' ];
                $record->name = $r[ 'name' ];
                $record->type = (string) $r[ 'type' ];
                $record->ttl  = intval((string) $r[ 'ttl' ]);
                $record->createRDATAObject();

                switch ($record[ 'type' ])
                {
                    case 'MX':
                        $record->rdata->exchange   = (string) $r[ 'content' ];
                        $record->rdata->preference = (string) $r[ 'priority' ];
                        break;
                    case 'SRV':
                        $r[ 'content' ]              = $r[ 'priority' ] . ' ' . (string) $r[ 'content' ];
                        $record->rdata->fromString((string) $r[ 'content' ]);
                        break;
                    default:
                        $record->rdata->fromString((string) $r[ 'content' ]);
                        break;
                }

                $out[] = $record;
            }
        }
        
        return $out;
    }

    private function recordToParamsArray(dns\record\Record $record)
    {

        $type_int = array_flip($this->availableTypes);

        $params = array(
            'line_id'  => $this->domain_id(),
            'name'     => $record->nameToAbsolute($this->domain, false),
            'type'     => $type_int[ $record->type ],
            'content'  => $record->value,
            'ttl'      => $record->ttl,
            'priority' => empty($record->priority) ? $this->config[ 'priority' ] : $record->priority,
            'failover' => 'false',
        );

        switch ($record->type)
        {
            case 'MX':
                $prio  = $record->rdata->preference;
                $value = $record->rdata->exchange;
                break;
            default:
                $prio  = $this->config[ 'priority' ];
                $value = $record->rdata->toString();
                break;
        }

        $params[ 'priority' ] = $prio;
        $params[ 'content' ]  = $value;
        return $params;
    }

    private function setSRVData(&$record)
    {
        if ($record->type == 'SRV')
        {
            #quick fix
            $priority = $record->rdata->priority;
            unset($record->rdata->priority);
            return $priority;
        }
    }

    public function addRecord(dns\record\Record $record)
    {
        $priority                  = $this->setSRVData($record);
        $params                    = $this->recordToParamsArray($record);
        $params[ 'failovercontent' ] = '';
        if (!is_null($priority))
        {
            $params[ 'priority' ] = $priority;
        }
        $params[ 'action' ] = 'CreateRecord';
        $this->get($params);
    }

    public function editRecord(dns\record\Record $record)
    {
        $priority          = $this->setSRVData($record);
        $params            = $this->recordToParamsArray($record);
        $params[ 'action' ]  = 'UpdateRecord';
        $params[ 'line_id' ] = $params[ 'id' ]      = $record->line;
        if (!is_null($priority))
        {
            $params[ 'priority' ] = $priority;
        }
        $this->get($params);
    }

    public function deleteRecord(dns\record\Record $record)
    {
        $params = array('id' => $record->line, 'action' => 'DeleteRecord');
        $this->get($params);
    }

    private function domain_id()
    {
        if ($this->domainID !== FALSE)
        {
            return $this->domainID;
        }

        $ret = $this->get(array('action' => 'getdomainbyname', 'name' => $this->domain));
        if (isset($ret[ 'id' ]))
        {
            $this->domainID = $ret[ 'id' ];
            return $this->domainID;
        }

        throw new exceptions\DNSSubmoduleException("Zone does not exist", dns\SubmoduleExceptionCodes::COMMAND_ERROR);
    }

    public function getZones()
    {
        $params = array(
            'action' => 'GetDomains',
        );

        $ret = $this->get($params);
        $out = array();
        foreach ($ret as $domain)
        {
            $out[ (string) $domain[ 'name' ] ] = '';
        }

        return $out;
    }

}
