<?php

namespace MGModule\DNSManager2\controllers\addon\clientarea;

use Exception;
use MGModule\DNSManager2 as main;
use MGModule\DNSManager2\helpers\custom\ClientFilesManage;
use MGModule\DNSManager2\mgLibs\custom;
use MGModule\DNSManager2\mgLibs\custom\AjaxResponse;
use MGModule\DNSManager2\mgLibs\custom\dns\record\Record;
use MGModule\DNSManager2\mgLibs\custom\dns\utils\IP;
use MGModule\DNSManager2\mgLibs\custom\dns\utils\ReverseDNSHelper;
use MGModule\DNSManager2\mgLibs\custom\helpers\RecordSetHelper;
use MGModule\DNSManager2\mgLibs\custom\helpers\ZoneLogger\Manager as ZoneLoggerManager;
use MGModule\DNSManager2\mgLibs\custom\manager\BlockerHelper;
use MGModule\DNSManager2\mgLibs\custom\manager\ClientHelper;
use MGModule\DNSManager2\mgLibs\custom\manager\GlobalSettingHelper;
use MGModule\DNSManager2\mgLibs\custom\manager\LogHelper;
use MGModule\DNSManager2\mgLibs\custom\manager\ZoneCreator;
use MGModule\DNSManager2\mgLibs\custom\manager\ZoneRemover;
use MGModule\DNSManager2\mgLibs\custom\relateditem\RelatedItem;
use MGModule\DNSManager2\mgLibs\custom\reverse\IPHelper;
use MGModule\DNSManager2\mgLibs\lang;
use MGModule\DNSManager2\mgLibs\MySQL\query;
use MGModule\DNSManager2\models\custom\globalsetting\GlobalSettingEnum;
use MGModule\DNSManager2\models\custom\package\setting\PackageSettingEnum;
use MGModule\DNSManager2\models\custom\reverse;
use MGModule\DNSManager2\models\custom\server\setting\ServerSettingEnum;
use MGModule\DNSManager2\models\custom\set;
use MGModule\DNSManager2\models\custom\status;
use MGModule\DNSManager2\models\custom\task;
use MGModule\DNSManager2\models\custom\zone\Zone;
use WHMCS\Database\Capsule as DB;
//TODO: (nie miałem gdzie dodać) Synchronizacja rdnsów (w obie strony, porównywac rekordy z serverem)
//TODO: edit zone -> records encode itp
//TODO: ogarnąć ten bajzel w kontrolerach
class dashboard extends main\mgLibs\process\abstractController
{
    private $set_form = array(
         'edit' => false,
         'name' => '',
         'count' => 0,
    );

    public function __construct($input)
    {
        parent::__construct($input);

        if($_REQUEST['mg-action'] == 'manageRDNS' && GlobalSettingHelper::getSetting(GlobalSettingEnum::RDNS_IN_CLIENTAREA) == GlobalSettingEnum::CLIENTAREA_RNDS_BLOCK)
        {
            redir('m=DNSManager2');
        }
    }

    function indexHTML($input, $vars = array())
    {
        $this->redirectIfIsOnlyRDNSforCA();

        $helper = new ClientHelper($_SESSION['uid']);

        $groups = $helper->getGroups();

        $groups_info = array();

        foreach($groups as $key => $group)
        {
            $sum = array();
            $zones_count = 0;


            foreach($group as $key2 => $zone)
            {
                if($zone['zone_id'])
                {
                    $check = $helper::getServerStatusByZoneId($zone['zone_id']);
                    $group[$key2]['server_status'] = $check['status'];
                    $zones_count++;
                }
                $sum[$zone['type'] .'::'.$zone['relid']] = $zone['zones_available'];
            }

            $groups_info[$key]['zones_available']   = array_sum($sum);
            $groups_info[$key]['zones_count']       = $zones_count;
            $groups_info[$key]['type']              = $zone['type'];
            $groups_info[$key]['relid']             = $zone['relid'];
            $groups_info[$key]['full']              = $groups_info[$key]['zones_available'] <= $groups_info[$key]['zones_count'];

            $obGroup = new \stdClass();
            $obGroup->group = $group;
            $obGroup->product_group_name = $zone['product_group_name'];
            $obGroup->product_name = $zone['product_name'];
            $obGroup->product_id = $zone['product_id'];
            $obGroup->domain = $zone['domain'];
            $obGroup->groupKey = $key;

            $groups[$key] = $obGroup;
        }
        unset($key);

        usort($groups, $this->arraySortByValue('domain'));
        if($groups[0]->groupKey === 'Other')
        {
            $groups[] = $groups[0];
            unset($groups[0]);
        }

        $vars['groups'] = $groups;
        $vars['groups_info'] = $groups_info;

        $vars['manage_rdns']              = $this->getRDNSStatus();
        $vars['manageRecordsSets']        = GlobalSettingHelper::getSetting(GlobalSettingEnum::LINK_TO_DNS_SETS_MANAGER, true);
        $vars['clientarea_import_export'] = GlobalSettingHelper::getSetting(GlobalSettingEnum::LINK_TO_CLIENTAREA_IMPORT_EXPORT, true);
        $vars['showProductName']          = GlobalSettingHelper::getSetting(GlobalSettingEnum::SHOW_PRODUCT_NAME, false);

        return [
            'tpl'  => 'dashboard',
            'vars' => $vars
        ];
    }

    /**
     * @return bool
     */
    private function getRDNSStatus()
    {
        if( GlobalSettingHelper::getSetting(GlobalSettingEnum::RDNS_IN_CLIENTAREA, true) !== 'clientarea_rdns_allow' )
        {
            return false;
        }
        $rdnsPossibleToAdd  = (bool)count($this->getUserPackageItems($_SESSION['uid']));
        $rdnsAlreadyCreated = (bool)query::query("SELECT COUNT(`id`) 
                FROM `dns_manager2_reverse`
                WHERE `clientid` = :clientid", ['clientid' => $_SESSION['uid']])->fetchColumn();

        if(!$rdnsAlreadyCreated && !$rdnsPossibleToAdd)
        {
            return false;
        }

        return true;
    }

    public function addZoneJSON($input, $vars = array())
    {
        //TODO: sytuacje gdy ip nie jest konieczne w module + default ip
        $vars = IPHelper::getIPsArray($_SESSION['uid'], $input['type'], $input['relid']);

        $vars['ipmanager'] = !empty($vars['pools']);

        $vars['type']   = $input['type'];
        $vars['relid']  = $input['relid'];

        $vars['custom_ip'] = IPHelper::isCustomIPEnabledForZoneCreate();

	    $helper = new ClientHelper($_SESSION['uid']);
	    $allowed_ips = $helper->getPackageAllowedIps(intval($vars['relid']), intval($vars['type']));
	    $vars['allowed_ips'] = IP::getAvailableIpList(json_decode($allowed_ips['allowed_ips']));
	    $vars['allowed_ips_flag'] = is_array($vars['allowed_ips']) && !empty($vars['allowed_ips']) && $vars['allowed_ips'][0] != null;

        $ip_blacklist = $helper->getPackageIpBlacklist(intval($vars['relid']), intval($vars['type']));
        $vars['ip_blacklist'] = IP::getAvailableIpList(json_decode($ip_blacklist['ip_blacklist']));
        $vars['ip_blacklist_flag'] = is_array($vars['ip_blacklist']) && !empty($vars['ip_blacklist']) && $vars['allowed_ips'][0] != null;

	    if($input['type'] != main\models\custom\zone\ZoneTypeEnum::DOMAIN)
        {
            $vars['is_not_domain'] = true;
        }

        if($input['type'] == '0' && $input['relid'] == '0')
        {
            $vars['custom_ip'] = 1;
            $creator = new ZoneCreator('',  $input['type'], $input['relid'], false, $_SESSION['uid']);
        }
        else
        {
            $creator = new ZoneCreator('',  $input['type'], $input['relid']);
        }

        $vars['is_ip_required'] = true;
        if ($creator->server) {
            $vars['is_ip_required'] = $creator->server->getModule()->isIPRequired();
        }
        
        $defaultSets = $creator->getPackage()->getAdminSets();
        $adminSets   = set\Repository::factory()->adminOnly()->get();

        foreach ($adminSets as $key => $value) {
            if(  !in_array( $value->id, $defaultSets))
            {
                unset($adminSets[$key]);
            }
        }
        $vars['zoneDomainItems'] = custom\helpers\ZoneSettings::getProperlyItems($_SESSION['uid'], $vars['relid'], $vars['type']);


        $vars['adminSets'] = $adminSets;
        $vars['allowManageRecordsSets'] = GlobalSettingHelper::getSetting(GlobalSettingEnum::LINK_TO_DNS_SETS_MANAGER, true);
        $vars['recordSets'] = set\Repository::factory()->byUserId((int)$_SESSION['uid'])->get();
        $vars['allowManageRecordsSets'] = (count($vars['recordSets']) > 0 ||  count($vars['adminSets']) > 0)  ? $vars['allowManageRecordsSets'] : false;

        return AjaxResponse::I()->modal('add-zone', $vars)->toArray();
    }

    public function addZoneSaveJSON($input, $vars = array())
    {
        $helper = new ClientHelper($_SESSION['uid']);
        if(!$helper->canUserCreatesNewZonesIn($input['type'], $input['relid'])) {
            return AjaxResponse::I()->addError('you_cant_add_new_zones_within_this_group')->toArray();
        }

        if(GlobalSettingHelper::getSetting(GlobalSettingEnum::OWNED_DOMAINS_ONLY) == 'on' && !in_array($input['zone_name'], $helper->getClientDomains())) {
            return AjaxResponse::I()->addError('you_cant_use_domain_that_does_not_belong_to_you')->toArray();
        }

        $zoneName = $input['zone_name'];
        $blockerHelper = new BlockerHelper();
        $isBlocked = false;

        $allowedIps = json_decode($helper->getPackageAllowedIps($input['relid'],$input['type'])['allowed_ips']);
        $ipBlacklist = json_decode($helper->getPackageIpBlacklist($input['relid'],$input['type'])['ip_blacklist']);

        if($input['is_ip_required']) {
            if (is_array($allowedIps) && !empty($allowedIps)) {
                if (!in_array($input['zone_ip'], $allowedIps)) return AjaxResponse::I()->addError('not_allowed_ip')->toArray();
            }
            if (in_array($input['zone_ip'], $ipBlacklist))
                return AjaxResponse::I()->addError('ip_on_blacklist')->toArray();
        }

        if(!$blockerHelper->isLoggedUserExcluded()) {
            $rules = $blockerHelper->getRules();

            foreach($rules as $rule) {
                $rule = trim($rule);

                if($blockerHelper->isRecordBlocked($rule, $zoneName)) {
                    $isBlocked = true;
                    break;
                }
            }
        }

        if($isBlocked) {
            return AjaxResponse::I()->addError('value_is_blocked')->toArray();
        }

        if(strpos($input['zone_ip'], 'block') !== false) {
            list($str,$pool,$mask) = explode('|',$input['zone_ip']);

            $ip = new IP($input['zone_ip_from_block']);
            if(!$ip->isInNetwork($pool, $mask)) {
                return AjaxResponse::I()->addError('ip_is_not_belongs_to_selected_block')->toArray();
            }

            $input['zone_ip'] = $input['zone_ip_from_block'];
        }

//        $ip_array = IPHelper::getIPsArray($_SESSION['uid'], $input['type'], $input['relid']);
//        if(!in_array($input['zone_ip'], $ip_array['all_ips']) && !empty($input['zone_ip'])) {
//            return AjaxResponse::I()->addError('you_cant_use_ip_that_not_belongs_to_you')->toArray();
//        }

        if(!custom\helpers\ZoneSettings::isDomainClient($input['zone_name'], $input['type'], $input['relid'], $_SESSION['uid']))
        {
            return AjaxResponse::I()->addError('zone_does_not_belongToYou')->toArray();
        }

        try
        {
            $ip = new IP($input['zone_ip']);
            if(!empty($input['zone_ip']) && (!$ip->isValid() || $input['type'] != '0' || $input['relid'] != '0'))
            {
                IPHelper::validateIfClientCanUseIP($_SESSION['uid'], $input['type'], $input['relid'], $input['zone_ip'], true);
            }

            $creator    = new ZoneCreator($input['zone_name'], $input['type'], $input['relid'], $input['zone_ip'], $_SESSION['uid']);
            $creator->setZoneLoggerManager(new ZoneLoggerManager($_SESSION['uid']));
            $packageID  = $creator->getPackage()->id;
            $limitCheck = main\mgLibs\custom\helpers\RecordSetHelper::checkAllowedRecordsLimits($packageID, $input['recordSet']);

            if(!$limitCheck)
            {
                return AjaxResponse::I()->addError('you_have_exceeded_limit')->toArray();
            }

            $ret = $creator->create($input['recordSet']);

            if(is_string($ret))
            {
                return AjaxResponse::I()->addRawError($ret)->toArray();
            }

            AjaxResponse::I()->addInfo('zone_created_successfully');

        }
        catch(Exception $exc)
        {
            AjaxResponse::I()->addRawError($exc->getMessage());
        }

        return AjaxResponse::I()->refreshPage($this->indexHTML($input))->toArray();
    }

    public function removeZoneJSON($input, $vars = array()) {
        $helper = new ClientHelper($_SESSION['uid']);
        $zone = new Zone($input['zone_id']);

        if(!$helper->isZoneOwnedByClient($zone)) {
            return AjaxResponse::I()->addError('you_cant_remove_this_zone_because_it_is_not_belongs_to_you')->toArray();
        }
        if($zone->is_locked){
            return AjaxResponse::I()->addError('you_cannot_edit_zone_that_is_not_your_own_zone')->toArray();
        }
        $checkServer = $helper::getServerStatusByZoneId($zone->id);
        if(!$checkServer['status'])
        {
            return AjaxResponse::I()->addError('you_cannot_remove_this_zone_because_server_is_not_active')->toArray();
        }

        try {
            ZoneRemover::removeZone($zone);
            main\mgLibs\custom\helpers\StatusHelper::removeZoneStatus($input['id']);

            $zoneLoggerManager = new ZoneLoggerManager($_SESSION['uid']);
            $zoneLoggerManager->logTerminateZoneAction($zone);

//            LogHelper::addSuccessLogUsingZone('Remove Zone', '', $zone);
        } catch (Exception $exc) {
             LogHelper::addFailLogUsingZone('Remove Zone', $exc->getMessage(), $zone);
             throw $exc;
        }

        AjaxResponse::I()->refreshPage($this->indexHTML($input));
        AjaxResponse::I()->addInfo('zone_removed_successfully');
        return AjaxResponse::I()->toArray();
    }

    public function createZoneJSON($input, $vars = array())
    {
        $helper = new ClientHelper($_SESSION['uid']);
        $zone = new Zone($input['zone_id']);

        if(!$helper->isZoneOwnedByClient($zone))
        {
            return AjaxResponse::I()->addError('you_cant_create_this_zone_because_it_is_not_belongs_to_you')->toArray();
        }

        $checkServer = $helper::getServerStatusByZoneId($zone->id);
        if(!$checkServer['status'])
        {
            return AjaxResponse::I()->addError('you_cannot_create_this_zone_because_server_is_not_active')->toArray();
        }

        try
        {
            $zoneLogger = new main\mgLibs\custom\helpers\ZoneLogger\Manager($_SESSION['uid']);
            $module = $zone->getModule();
            if(!$module->zoneExists())
            {
                $module->activateZone();
                $zoneLogger->logCreateZoneAction($zone);
            }

            $setHelper = new main\mgLibs\custom\helpers\RecordSetHelper($zone, $zoneLogger);
            $setHelper->addRecordSet();

            $zone->setThatExist();
//            LogHelper::addSuccessLogUsingZone('Add Zone', '', $zone);
        }
        catch(Exception $exc)
        {
            LogHelper::addFailLogUsingZone('Add Zone', $exc->getMessage(), $zone);

            throw $exc;
        }

        AjaxResponse::I()->refreshPage($this->indexHTML($input));
        AjaxResponse::I()->addInfo('zone_created_successfully');

        return AjaxResponse::I()->toArray();
    }

    private function checkWhmcsProductStatus($type, $relid)
    {
        switch($type)
        {
            case 1:
                $status = main\mgLibs\MySQL\query::select(array('status'), 'tbldomains', array('id' => $relid))->fetchAll();
                $status = $status[0]['status'];
                break;
            case 2:
                $status = main\mgLibs\MySQL\query::select(array('domainstatus'), 'tblhosting', array('id' => $relid))->fetchAll();
                $status = $status[0]['domainstatus'];
                break;
            case 3:
                $status = main\mgLibs\MySQL\query::select(array('status'), 'tblhostingaddons', array('id' => $relid))->fetchAll();
                $status = $status[0]['status'];
                break;
            default:
                $status = 'Active';
                break;
        }

        return strtolower($status);
    }

    public function editZoneHTML($input, $vars = array())
    {
        $this->redirectIfIsOnlyRDNSforCA();

        $helper = new ClientHelper($_SESSION['uid']);
        $zone = new Zone($input['zone_id']);

        $whmcsOrderStatus = $this->checkWhmcsProductStatus($zone->type, $zone->relid) == 'active' ? false : true;

        if($this->isTransferAndShouldBeAbleToEdit($zone))
        {
            $whmcsOrderStatus = false;
        }

        $checkServer = $helper::getServerStatusByZoneId($zone->id);

        if(!$helper->isZoneOwnedByClient($zone))
        {
            $vars['error'] = lang::T('you_cannot_edit_this_zone_because_it_is_not_belongs_to_you');
        }
        elseif(!$checkServer['status'])
        {
            $vars['error'] = lang::T('you_cannot_edit_this_zone_because_server_is_not_active');
        }elseif ($zone->is_locked){
	        $vars['error'] = lang::T('You cannot edit this zone because it\'s locked');
        }elseif ($whmcsOrderStatus)
        {
            $vars['error'] = lang::T('you_cannot_edit_this_zone_because_order_is_not_active');
        }
        else
        {

            $module = $zone->getModule();


            if(!$module->zoneExists())
            {
                $vars['error'] = lang::T('you_cannot_edit_this_zone_because_it_is_terminated_on_server');
                $zone->setThatNotExist();
            }
            else
            {

                $vars['zone_name']  = $zone->name;
                $vars['zoneid']     = $zone->id;
                $vars['ttl_disabled'] = !$module->isTTLEnabled();

                $vars['records'] = $module->getRecords();
                $vars['records'] = array_merge($vars['records'], $this->getPTRRecords($zone));
                $soaList = array();
                $limits = $this->getPackageRecordsLimits($zone);

                foreach($vars['records'] as $key => &$record)
                {
                    if(!isset($limits[$record->type]) ){
                        unset($vars['records'][$key]);
                    }

                    $record->encode();
                    if($record->type === 'SOA' && array_key_exists('SOA', $limits))
                    {
                        $soaList[] = $record;
                        unset($vars['records'][$key]);
                    }
                }
                usort($vars['records'], $this->arraySortByValue('type'));
                foreach($soaList as $soaRecord)
                {
                    array_unshift($vars['records'] , $soaRecord);
                }


                $rep  = status\Repository::factory()->setFilter('relid', $zone->id)->get();

                if(!$rep)
                {
                    $status = 'pending';
                }
                else
                {
                    $status = $rep[0]->status;
                }

                $status = main\mgLibs\custom\helpers\StatusHelper::parseStatus($status);

                $soaAlert               = GlobalSettingHelper::getSetting(GlobalSettingEnum::SOA_IS_NOT_NS_STATUS);
                $domainAvailableAlert   = GlobalSettingHelper::getSetting(GlobalSettingEnum::WHOIS_MISSING_STATUS);
                $activeAlert            = GlobalSettingHelper::getSetting(GlobalSettingEnum::IS_OK_STATUS);
                $pendingAlert           = GlobalSettingHelper::getSetting(GlobalSettingEnum::IS_PENDING_STATUS);


                if($status == 'pending' && $pendingAlert == 'on')
                {
                   $vars['tpl']     = 'pending';
                }
                elseif($status == 'notRegistered' && $domainAvailableAlert == 'on')
                {
                    $vars['tpl'] = 'notRegistered';
                }
                elseif($status == 'soaWarning' && $soaAlert == 'on')
                {
                    $vars['tpl'] = 'soaWarning';
                }
                elseif($status == 'active' && $activeAlert == 'on')
                {
                    $vars['tpl'] = 'active';
                }
                else
                {
                    $vars['tpl'] = 'standard';
                }

                $content        = main\mgLibs\custom\helpers\StatusHelper::loadStatusContent($vars['tpl']);
                $recordLimits   = $this->getPackageRecordsLimits($zone);
                array_walk($recordLimits, function (&$limit) use ($recordLimits){
                    if ((int)$limit === -1 && isset($recordLimits['total']))
                    {
                        $limit = $recordLimits['total'];
                    }
                });

                $vars['available_record_types'] = $module->getAvailableRecordTypes();
                $vars['content']    = html_entity_decode(str_replace('{$domain}', $zone->name, $content));
                $vars['counter']    = 0;
                $vars['zone_name']  = $zone->name;
                $vars['id']         = $zone->id;
                $vars['records_count']  = $this->countRecords($vars['records']);
                $vars['limits']         = $recordLimits;
                $vars['enable_dnssec']  = $zone->getServer()->getSettings(ServerSettingEnum::ENABLE_DNSSEC) == 'on' && $module->isDNSSECSupported();

                $showNameservers           = GlobalSettingHelper::getSetting(GlobalSettingEnum::SHOW_NAMESERVERS);
                $vars['nameservers'] = $showNameservers == 'on' ? $module->getNameServers(false) : [];
            }

        }
        $vars['show_full_record_name'] = GlobalSettingHelper::getSetting(GlobalSettingEnum::SHOW_FULL_RECORD_NAME);

        return array(
            'tpl'   => 'edit',
            'vars' => $vars
        );
    }

    private function getPTRRecords($zone) {
        $out = array();
        foreach(reverse\Repository::factory()->from($zone->getServer()->id, $zone->name)->byClientID($zone->clientid)->get() as $data) {
            $ptr = new main\mgLibs\custom\dns\record\Record();
            $ptr->name  = ReverseDNSHelper::reverseRecordName($data->ip) . '.' . $data->name;
            $ptr->type  = 'PTR';
            $ptr->ttl   = $data->ttl;
            $ptr->ip    = $data->ip;
            $ptr->createRDATAObject('PTR');
            $ptr->rdata->setFirstProperty(empty($data->sub)?$data->from:$data->sub . '.' . $data->from);
            $out[] = $ptr;
        }
        return $out;
    }

    private function getPackageRecordsLimits(Zone $zone) {
        $package = $zone->getPackage();
        if($package == false) {
            return array('total' => 0);
        }

        $out     = unserialize($package->getSettings(PackageSettingEnum::ALLOWED_RECORD_TYPES))?:array();
        $out['total'] = $this->getTotalRecordsLimit($zone);

        if(isset($out['PTR'])) {
            if($zone->getServer()->getSettings(ServerSettingEnum::ALLOW_RDNS) == 'on') {
                if($out['PTR'] > 1 && !($zone->getServer()->getSettings(ServerSettingEnum::ALLOW_MULTIPLE_PTR) == 'on')) {
                    $out['PTR'] = 1;
                }
            } else {
                unset($out['PTR']);
            }
        }

        return $out;
    }

    private function countRecords($records) {
        $records_count = array();
        foreach($records as $record) {
            $records_count[$record->type]++;
        }
        $records_count['total'] = array_sum($records_count);
        return $records_count;
    }

    private function getTotalRecordsLimit(Zone $zone) {
        return $zone->getPackageItem()->limit;
    }

    public function editZoneJSON($input, $vars = array()) {
        return AjaxResponse::I()->refreshPage($this->editZoneHTML($input))->toArray();
    }

    public function removeRecordJSON($input, $vars = array()) {

        $helper = new ClientHelper($_SESSION['uid']);
        $zone   = new Zone($input['zone_id']);

        if(!$helper->isZoneOwnedByClient($zone)) {
            return AjaxResponse::I()->addError('you_cant_remove_this_record_because_it_is_not_belongs_to_one_of_your_zones')->toArray();
        }

        $checkServer = $helper::getServerStatusByZoneId($zone->id);
        if(!$checkServer['status'])
        {
            return AjaxResponse::I()->addError('you_cannot_edit_this_zone_because_server_is_not_active')->toArray();
        }

        try {
            $record_data = array_pop($input['record']);

            if(empty($record_data))
            {
                $record_data = array_pop($input['edit_record']);
            }

            $module = $zone->getModule();


            if (strtoupper($record_data['type']) == 'PTR') { // REVERSE RECORD
                $ip = $record_data['ip'];
                $record = reverse\Repository::factory()->fromIP($zone->getServer()->id, $ip)->one();


                if ($record === FALSE || $record->from != $zone->name) {
                    return AjaxResponse::I()->addError('you_cannot_remove_record_that_is_not_belongs_to_you')->toArray();
                }


                $module->removeRDNS($ip);
                $record->delete();


            } else {
                $record = $this->createRecordFromInputData($record_data);
                $module->deleteRecord($record);
            }

            $zoneLoggerManager = new ZoneLoggerManager($_SESSION['uid']);
            $zoneLoggerManager->logRemoveRecordFromZone($zone, $record);
        } catch (Exception $exc) {
            LogHelper::addFailLogUsingZone('Edit Zone', $exc->getMessage(), $zone);
            throw $exc;
        }

        AjaxResponse::I()->addInfo('record_removed_successfully');
        AjaxResponse::I()->refreshPage($this->editZoneHTML($input));
        return AjaxResponse::I()->toArray();
    }

    private function createRecordFromInputData($input) {
        $record = Record::tryToCreateFromArray($input);
        $record->rdata->setDataFromArray($input['field']);
        $record->decode();
        return $record;
    }

    public function addRecordJSON($input, $vars = array()) {
        $helper = new ClientHelper($_SESSION['uid']);
        $zone   = new Zone($input['zone_id']);
        $vars = IPHelper::getIPsArray($_SESSION['uid'], $zone->type, $zone->relid);
        $vars['ipmanager'] = !empty($vars['pools']);

        $vars['zone_id'] = $zone->id;
        $vars['available_record_types'] = $zone->getModule()->getAvailableRecordTypes();

        $vars['custom_ip'] = IPHelper::isCustomIPEnabled();
        $vars['ttl_enabled'] = $zone->getModule()->isTTLEnabled();

        $helper = new ClientHelper($_SESSION['uid']);

        if($vars['recordsAllowedIp']) {
            $allowedIps = $helper->getPackageAllowedIps(intval($zone->relid), intval($zone->type));
            $allowedIps = IP::getAvailableIpList(json_decode($allowedIps['allowed_ips']));

            $vars['allowed_ipv4'] = IP::getOnlyIpv4($allowedIps);
            $vars['allowed_ipv4_flag'] = is_array($vars['allowed_ipv4']) && !empty($vars['allowed_ipv4']) && $vars['allowed_ipv4'][0] != null;
            $vars['allowed_ipv6'] = IP::getOnlyIpv6($allowedIps);
            $vars['allowed_ipv6_flag'] = is_array($vars['allowed_ipv6']) && !empty($vars['allowed_ipv6']) && $vars['allowed_ipv6'][0] != null;
        }

        if($vars['recordsBlacklist']) {
            $ipBlacklist = $helper->getPackageIpBlacklist(intval($zone->relid), intval($zone->type));
            $ipBlacklist = IP::getAvailableIpList(json_decode($ipBlacklist['ip_blacklist']));

            $vars['ipv4_blacklist'] = IP::getOnlyIpv4($ipBlacklist);
            $vars['ipv4_blacklist_flag'] = is_array($vars['ipv4_blacklist']) && !empty($vars['ipv4_blacklist']) && $vars['ipv4_blacklist'][0] != null;
            $vars['ipv6_blacklist'] = IP::getOnlyIpv6($ipBlacklist);
            $vars['ipv6_blacklist_flag'] = is_array($vars['ipv6_blacklist']) && !empty($vars['ipv6_blacklist']) && $vars['ipv6_blacklist'][0] != null;
        }

        $limits = $this->getPackageRecordsLimits($zone);
        foreach($vars['available_record_types'] as $k => $record) {
            if(!isset($limits[$record]) || $input['records'][$record] >= $limits[$record] && (int)$limits[$record] !== -1)
                unset($vars['available_record_types'][$k]);
        }

        return AjaxResponse::I()->modal('add-record', $vars)->toArray();
    }

    public function addRecordSaveJSON($input, $vars = array()) {
        if(empty($input['type'])) {
            return AjaxResponse::I()->addError('choose_record_type')->toArray();
        }

        $helper = new ClientHelper($_SESSION['uid']);
        $zone   = new Zone($input['zone_id']);

        if(!$helper->isZoneOwnedByClient($zone)) {
            return AjaxResponse::I()->addError('you_cannot_add_record_to_zone_that_is_not_yours')->toArray();
        }

        $checkServer = $helper::getServerStatusByZoneId($zone->id);
        if(!$checkServer['status'])
        {
            return AjaxResponse::I()->addError('you_cannot_edit_this_zone_because_server_is_not_active')->toArray();
        }

        $ipBlacklist = IP::getAvailableIpList(json_decode($helper->getPackageIpBlacklist(intval($zone->relid), intval($zone->type))['ip_blacklist']));
        if($input['type'] === 'PTR')
            $ip = $input['ip'];
        else
            $ip = $input['field']['address'];

        if($ip && !empty($ipBlacklist) && in_array($ip, $ipBlacklist) && $ipBlacklist[0] != null)
            return AjaxResponse::I()->addError('ip_on_blacklist')->toArray();


        $blockerHelper = new BlockerHelper();
        $isBlocked = false;

        if(!$blockerHelper->isLoggedUserExcluded()) {

            $rules = $blockerHelper->getRules();
            foreach($rules as $rule) {
                $rule = trim($rule);

                if($blockerHelper->isRecordBlocked($rule, $input['name'])) {
                    $isBlocked = true;
                    break;
                }
            }
        }

        if($isBlocked) {
            return AjaxResponse::I()->addError('value_is_blocked')->toArray();
        }
        $module = $zone->getModule();

        try {
            $limits = $this->getPackageRecordsLimits($zone);
            $count  = $this->countRecords($module->getRecords());
            if((isset($limits[$input['type']])
                    && (int)$limits[$input['type']] !== -1
                    && $count[$input['type']] >= $limits[$input['type']])
                    || $limits['total'] <= $count['total'] ) {
                return AjaxResponse::I()->addError('you_cant_add_this_record_because_you_reach_limit')->toArray();
            }

            if(strtoupper($input['type']) == 'PTR') {

                if(strpos($input['ip'], 'block') !== false) {
                    list($str,$pool,$mask) = explode('|',$input['ip']);

                    $ip = new IP($input['ip_from_block']);
                    if(!$ip->isInNetwork($pool, $mask)) {
                        return AjaxResponse::I()->addError('ip_is_not_belongs_to_selected_block')->toArray();
                    }

                    $input['ip'] = $input['ip_from_block'];
                }

                $ip = $input['ip'];

//                if(empty($ip)) {
//                    return AjaxResponse::I()->addError('ip_cannot_be_empty')->toArray();
//                }
//
//                $ip_array = IPHelper::getIPsArray($_SESSION['uid'], $zone->type, $zone->relid);
//                if(!in_array($ip, $ip_array['all_ips'])) {
//                    return AjaxResponse::I()->addError('you_cant_use_ip_that_not_belongs_to_you')->toArray();
//                }

                IPHelper::validateIfClientCanUseIP($_SESSION['uid'], $zone->type, $zone->relid, $ip);

                $input['subdomain'] = trim($input['subdomain']);
                $name = !empty($input['subdomain'])?$input['subdomain'].'.'.$zone->name: $zone->name;

                $record = new main\mgLibs\custom\reverse\ReverseDNS($zone);
                $record->setDomain($name);
                $record->setIP($ip);
                $record->setTTL($input['ttl']);
                $record->create();

            } else {
                $record = $this->createRecordFromInputData($input);
                $record->encode();
                $module->validateRecord($record);

                $record->nameToAbsolute($zone->name);
                $module->addRecord($record);
            }


            $zoneLoggerManager = new ZoneLoggerManager($_SESSION['uid']);
            $zoneLoggerManager->logAddRecordToZone($zone, $record);
//            LogHelper::addSuccessLogUsingZone('Edit Zone', '', $zone);
            AjaxResponse::I()->addInfo('new_record_added_to_zone');
            return $this->editZoneJSON($input, $vars);
        }
        catch (custom\dns\exceptions\DNSSubmoduleHiddenException $exc )
        {
            LogHelper::addFailLogUsingZone('Edit Zone', $exc->getMessage(), $zone);
            return AjaxResponse::I()->addRawError('Problem while validating zone by bind. Please contact administrator')->toArray();
        }
        catch (Exception $exc) {
            LogHelper::addFailLogUsingZone('Edit Zone', $exc->getMessage(), $zone);
            return AjaxResponse::I()->addRawError($exc->getMessage())->toArray();
        }
    }

    private function createReverseIP(Zone $zone, $ip, $ttl, $sub = '') {
        $reverse    = new reverse\Reverse();
        $reverse->serverid  = $zone->getServer()->id;
        $reverse->from      = $zone->name;
        $reverse->sub       = $sub;
        $reverse->name      = ReverseDNSHelper::reverseZoneName($ip);
        $reverse->created_at= date('Y-m-d H:i:s');
        $reverse->ip        = $ip;
        $reverse->ttl       = $ttl;
        $reverse->clientid  = $zone->clientid;
        $reverse->save();
    }

    public function getRecordRdataJSON($input, $vars = array()) {
        $zone = new Zone($input['zone_id']);

        $class = '\MGModule\DNSManager2\mgLibs\custom\dns\record\type\\' . $input['type'];
        if(class_exists($class)) {
            $obj = new $class();

            $vars['record_fields']  = get_object_vars($obj);
            $vars['record_type']    = $input['type'];

            $packageSettings = $zone->getPackage()->getSettings('default_ttl');
            $packageSettings = unserialize($packageSettings);

            $vars['ttl_default_value'] = $packageSettings[$input['type']];
            if(empty($vars['ttl_default_value']))
                $vars['ttl_default_value'] = 14440;

            if($input['type'] == 'PTR') {
                $vars['value'] = $zone->name;
            }

            $settingRepo = new main\models\custom\package\setting\Repository();
            $vars['recordsAllowedIp'] = $settingRepo->byKey('records_allowed_ip')->get()[0] == 'on';
            $vars['recordsBlacklist'] = $settingRepo->byKey('records_blacklist')->get()[0] == 'on';
            $helper = new ClientHelper($_SESSION['uid']);

            if($vars['recordsAllowedIp']) {
                $allowedIps = $helper->getPackageAllowedIps(intval($zone->relid), intval($zone->type));
                $allowedIps = IP::getAvailableIpList(json_decode($allowedIps['allowed_ips']));

                $vars['allowed_ipv4'] = IP::getOnlyIpv4($allowedIps);
                $vars['allowed_ipv4_flag'] = is_array($vars['allowed_ipv4']) && !empty($vars['allowed_ipv4']) && $vars['allowed_ipv4'][0] != null;
                $vars['allowed_ipv6'] = IP::getOnlyIpv6($allowedIps);
                $vars['allowed_ipv6_flag'] = is_array($vars['allowed_ipv6']) && !empty($vars['allowed_ipv6']) && $vars['allowed_ipv6'][0] != null;
            }

            if($vars['recordsBlacklist']) {
                $ipBlacklist = $helper->getPackageIpBlacklist(intval($zone->relid), intval($zone->type));
                $ipBlacklist = IP::getAvailableIpList(json_decode($ipBlacklist['ip_blacklist']));

                $vars['ipv4_blacklist'] = IP::getOnlyIpv4($ipBlacklist);
                $vars['ipv4_blacklist_flag'] = is_array($vars['ipv4_blacklist']) && !empty($vars['ipv4_blacklist']) && $vars['ipv4_blacklist'][0] != null;
                $vars['ipv6_blacklist'] = IP::getOnlyIpv6($ipBlacklist);
                $vars['ipv6_blacklist_flag'] = is_array($vars['ipv6_blacklist']) && !empty($vars['ipv6_blacklist']) && $vars['ipv6_blacklist'][0] != null;
            }

            AjaxResponse::I()->html = main\mgLibs\smarty::I()->view('record-rdata',
                $vars,
                main\addon::getModuleTemplatesDir().DS.'pages' . DS . main\addon::I()->page);
            AjaxResponse::I()->ttl =  $vars['ttl_default_value'];
        } else {
            AjaxResponse::I()->addRawError(main\mgLibs\lang::T('cannot_find_class'). ' ' .$class);
        }

        return AjaxResponse::I()->toArray();
    }

    public function editZoneSaveJSON($input, $vars = array())
    {
        $helper = new ClientHelper($_SESSION['uid']);
        $zone   = new Zone($input['zone_id']);


        if(!$helper->isZoneOwnedByClient($zone))
        {
            return AjaxResponse::I()->addError('you_cannot_edit_zone_that_is_not_your_own_zone')->toArray();
        }
        if($zone->is_locked) return AjaxResponse::I()->addError('you_cannot_edit_zone_that_is_not_your_own_zone')->toArray();
        $checkServer = $helper::getServerStatusByZoneId($zone->id);
        if(!$checkServer['status'])
        {
            return AjaxResponse::I()->addError('you_cannot_edit_this_zone_because_server_is_not_active')->toArray();
        }

        try
        {
            $blockerHelper = new BlockerHelper();
            $isBlocked = false;

            if(!$blockerHelper->isLoggedUserExcluded()) {

                $rules = $blockerHelper->getRules();

                foreach($input['edit_record'] as $singleRecord){
                    foreach($rules as $rule) {
                        $rule = trim($rule);


                        if($blockerHelper->isRecordBlocked($rule, $singleRecord['name'])) {
                            $isBlocked = true;
                            break;
                        }
                    }
                }
            }

            if($isBlocked) {
                return AjaxResponse::I()->addError('value_is_blocked')->toArray();
            }
            $module = $zone->getModule();

            $module->moduleConvertInputFormData($input);

            $oldRecords = RecordSetHelper::formatRecordsToIndexById($module->getRecords());

            if(!$module->customEditRecords($input))
            {
                foreach ($input['edit_record'] as $counter => $record_data)
                {

                    $record = $this->createRecordFromInputData($record_data);
                    $record->encode();
                    $record->nameToAbsolute($zone->name);
                    $module->editRecord($record);


                    $editRecordHelper  = new custom\helpers\ZoneLogger\Actions\EditRecord($record, $oldRecords[$record->line]);
                    $zoneLoggerManager = new ZoneLoggerManager($_SESSION['uid']);
                    $zoneLoggerManager->logEditRecordsInZone($zone, $editRecordHelper);
                }
            }
        }
        catch(Exception $exc)
        {
            LogHelper::addFailLogUsingZone('Edit Zone', $exc->getMessage(), $zone);
            throw $exc;
        }

        AjaxResponse::I()->addInfo('changes_saved');
        AjaxResponse::I()->refreshPage($this->editZoneHTML($input));
        return AjaxResponse::I()->toArray();
    }

    private function formatRecordsToIndexById($records = [])
    {
        $out = [];
        foreach ($records as $record)
        {
            $out[$record->line] = $record;
        }
        return $out;
    }

    private function getPTRLimits() {
        $helper = new ClientHelper($_SESSION['uid']);
        $groups = $helper->getGroups();

        $limit = 0;
        foreach($groups as $item) {

            $ptr = $this->getPTRLimitForGroup($item);
            if($ptr)
            {
                $limit += (int)$ptr * (int)$item[0]['zones_available'];
            }
        }

        return $limit;
    }



    private function getPTRLimitForGroup($group)
    {
            $relateditem = new RelatedItem($group[0]['type'], $group[0]['relid'], $_SESSION['uid']);

            $package = $relateditem->getPackage();
            if($package == false) {
                return FALSE;
            }
            $package_setting = unserialize($package->getSettings(PackageSettingEnum::ALLOWED_RECORD_TYPES));

            return $package_setting['PTR'];
    }






    private function countPTR() {
        return query::query("SELECT COUNT(*)
              FROM dns_manager2_reverse
              WHERE clientid = :userid",
                array('userid' => $_SESSION['uid']))->fetchColumn();

//        return query::query("SELECT COUNT(*)
//            FROM tblhosting
//            INNER JOIN dns_manager2_reverse ON dns_manager2_reverse.ip = tblhosting.dedicatedip OR tblhosting.assignedips LIKE CONCAT('%', dns_manager2_reverse.ip, '%')
//            WHERE userid = :userid AND domainstatus IN ('Active')
//            GROUP BY dns_manager2_reverse.id",
//                array('userid' => $_SESSION['uid']))->fetchColumn();
    }

    private function getUserPackageItems($userid) {
        $helper = new ClientHelper($userid);
        $groups = $helper->getGroups();

        $out = array();
        foreach($groups as $name => $group) {

            $ptr = $this->getPTRLimitForGroup($group);
            if(!$ptr)
            {
                continue;
            }

            $item = current($group);
            $out[] = array(
                'name' => $name,
                'type' => $item['type'],
                'relid' => $item['relid']
            );

        }

        foreach($out as $k => $item) {
            $ip_array = IPHelper::getIPsArray($userid, $item['type'], $item['relid']);

            if(!IPHelper::isCustomIPEnabled()) {
                if((IPHelper::isSubnetCustomIPEnabled() && empty($ip_array['pools']) && empty($ip_array['all_ips']))
                        || (!IPHelper::isSubnetCustomIPEnabled() && empty($ip_array['all_ips']))) {
                    unset($out[$k]);
                }
            }
        }

        return $out;
    }

    public function generateLinks( $vars, $page, $limit )
    {
        $page++;
        $recordsCount = query::query("SELECT COUNT(id) AS recordsCount
                FROM dns_manager2_reverse
                WHERE clientid = :clientid",
            ['clientid' => $_SESSION['uid']])->fetch()['recordsCount'];

        $pages = ceil($recordsCount / $limit);

        if ( !$recordsCount || ceil($recordsCount / $limit) === 1 )
        {
            $vars['prev']  = 1;
            $vars['page']  = 1;
            $vars['next']  = 1;
            $vars['links'] = [];
        }
        else
        {
            $vars['prev'] = ($page - 1 > 0) ? $page - 1 : 1;
            $vars['page'] = $page;
            $vars['next'] = $page + 1 <= ceil($recordsCount / $limit) ? $page + 1 : ceil($recordsCount / $limit);

            $linksToBeDisplayed = 3;

            $rangeMin = $page - $linksToBeDisplayed > 0 ? $page - $linksToBeDisplayed : 0;
            $rangeMax = $page + $linksToBeDisplayed < $pages ? $page + $linksToBeDisplayed : $pages;

            $linksCount = 0;

            $start = floor($linksToBeDisplayed / 2);

            $start = ($page - $start) >= 1 ? $page-$start : 1 ;

            for ( $i = $start; $i <= $pages; $i++ )
            {
                if ( ($linksCount < $linksToBeDisplayed) && $i >= $rangeMin && $i <= $rangeMax )
                {
                    $vars['links'][] = $i;
                    $linksCount++;
                }
            }
        }

        return $vars;
    }

    public function manageRDNSHTML($input, $vars = array()) {
        $page = isset( $_GET['page']) && ((int)$_GET['page'] - 1) >= 0 ? (int)$_GET['page'] - 1 : 0;
        $limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 15;
        $offset = $page * $limit;
        $vars = $this->generateLinks($vars, $page, $limit);

        $data = query::query("SELECT * 
                FROM dns_manager2_reverse
                WHERE clientid = :clientid
                LIMIT :offset,:limit", ['clientid' => $_SESSION['uid'], 'offset' => $offset, 'limit' => $limit])->fetchAll();

        $vars['ptrs'] = $data;
        $vars['limit'] = $this->getPTRLimits();
        $vars['counter'] = 1;

        $query = htmlspecialchars_decode($_SERVER['QUERY_STRING']);
        $vars['query'] = 'index.php?'.preg_replace('/&page=\w+/', '', $query);

        return array(
            'tpl'   => 'manage-rdns'
            ,'vars' => $vars
        );
    }


    public function manageRDNSJSON($input, $vars = array()) {
        return AjaxResponse::I()->refreshPage($this->manageRDNSHTML($input))->toArray();
    }

    public function addRDNSJSON($input, $vars = array()) {
        $vars['items'] = $this->getUserPackageItems($_SESSION['uid']);
        return AjaxResponse::I()->modal('add-rdns', $vars)->toArray();
    }

    public function getRDNSDataJSON($input, $vars = array()) {
        $vars = IPHelper::getIPsArray($_SESSION['uid'], $input['type'], $input['relid']);
        foreach($vars['ips'] as $ip) {
            try {
                $relateditem = new RelatedItem($input['type'], $input['relid'], $_SESSION['uid']);

                $package = $relateditem->getPackage();
                if($package == false) {
                    throw new Exception('No package found');
                }

                $server = $package->getFirstActiveServer();
                if($server == false) {
                    throw new Exception('No active server related to this item');
                }

                if(reverse\Reverse::byServerIDAndIP($server->id, (string) $ip) !== false) {
                    throw new Exception('IP already taken', 103);
                }
            }
            catch(Exception $e) {
                $vars['blocked_ips'][$ip] = $ip;
            }
        }

        $vars['any_pool'] = !empty($vars['pools']);
        $vars['custom_ip'] = IPHelper::isCustomIPEnabled();
        AjaxResponse::I()->html = main\mgLibs\smarty::I()->view('rdns-data',
                $vars,
                main\addon::getModuleTemplatesDir().DS.'pages' . DS . main\addon::I()->page);
        return AjaxResponse::I()->toArray();
    }

    public function addRDNSSaveJSON($input, $vars = array()) {



        $helper = new ClientHelper($_SESSION['uid']);

        list($type, $relid) = explode('::', $input['item']);

        $relateditem = new RelatedItem($type, $relid, $_SESSION['uid']);

        $package = $relateditem->getPackage();
        if($package == false) {
            return AjaxResponse::I()->addRawError('No package found')->toArray();
        }

        $server = $package->getFirstActiveServer();
        if($server == FALSE) {
            return AjaxResponse::I()->addError('no_active_server_related_to_this_item')->toArray();
        }

        $module = $server->getModule();


        if($server->getSettings(ServerSettingEnum::ALLOW_RDNS) != 'on' || !$module->isRDNSSupported()) {
            return AjaxResponse::I()->addError('rnds_disabled')->toArray();
        }

        try {

            $package_settings = unserialize($package->getSettings(PackageSettingEnum::ALLOWED_RECORD_TYPES));
            $ptrLimit = $package_settings['PTR'];
            $count  = $this->countPTR();

            if($count >= $ptrLimit) {
                return AjaxResponse::I()->addError('you_cant_add_this_record_because_you_reach_limit')->toArray();
            }

            if(strpos($input['ip'], 'block') !== false) {
                list($str,$pool,$mask) = explode('|',$input['ip']);

                $ip = new IP($input['ip_from_block']);
                if(!$ip->isInNetwork($pool, $mask)) {
                    return AjaxResponse::I()->addError('ip_is_not_belongs_to_selected_block')->toArray();
                }

                $input['ip'] = $input['ip_from_block'];
            }

            $ip = $input['ip'];

            $field = $input['field'];
            $rdata = isset($field['ptrdname']) ? $field['ptrdname'] : reset($field);

            $blockerHelper = new BlockerHelper();
            $isBlocked = false;

            if(!$blockerHelper->isLoggedUserExcluded()) {
                $rules = $blockerHelper->getRules(true);

                foreach($rules as $rule) {
                    $rule = trim($rule);

                    if($blockerHelper->isRecordBlocked($rule, $rdata)) {
                        $isBlocked = true;
                        break;
                    }
                }
            }

            if($isBlocked) {
                return AjaxResponse::I()->addError('value_is_blocked')->toArray();
            }

//            $ip_array = IPHelper::getIPsArray($_SESSION['uid'], $type, $relid);
//            if(!in_array($ip, $ip_array['all_ips'])) {
//                return AjaxResponse::I()->addError('you_cant_use_ip_that_not_belongs_to_you')->toArray();
//            }

            IPHelper::validateIfClientCanUseIP($_SESSION['uid'], $type, $relid, $ip);

            $reverse = new main\mgLibs\custom\reverse\ReverseDNS();
            $reverse->setServer($server);
            $reverse->setClientID($_SESSION['uid']);
            $reverse->setIP($ip);
            $reverse->setTTL($input['ttl']);
            $reverse->setDomain($input['field']['ptrdname']);
            $reverse->setType($type);
            $reverse->setRelId($relid);
            $reverse->create();

            $zoneLogger = new ZoneLoggerManager($_SESSION['uid']);
            $zoneLogger->logAddRdns($reverse);
            AjaxResponse::I()->addInfo('new_record_added_to_zone');
            return $this->manageRDNSJSON($input, $vars);
        } catch (Exception $exc) {
            return AjaxResponse::I()->addRawError($exc->getMessage())->toArray();
        }
    }

    public function removeRDNSJSON($input, $vars = array()) {

        $reverse = new reverse\Reverse($input['rid']);
        if ($reverse->clientid != $_SESSION['uid']) {
            return AjaxResponse::I()->addError('you_cannot_remove_record_that_is_not_belongs_to_you')->toArray();
        }
        try {
            $helper = new main\mgLibs\custom\reverse\ReverseDNS($reverse);
            $helper->remove();
        } catch (Exception $e) {
            return AjaxResponse::I()->addRawError($e->getMessage())->toArray();
        }

        AjaxResponse::I()->addInfo('record_removed_successfully');
        AjaxResponse::I()->refreshPage($this->manageRDNSHTML($input));
        return AjaxResponse::I()->toArray();
    }

    public function editRDNSJSON($input, $vars = array()) {
        $reverse = new reverse\Reverse($input['rid']);
        $vars['rdata'] = $reverse->getFullDomain();
        $vars['rid'] = $input['rid'];
        $vars['ee'] = isset($input['ee']);
        return AjaxResponse::I()->modal('edit-rdns', $vars)->toArray();
    }

    public function editRDNSSaveJSON($input, $vars = array()) {
        $reverse = new reverse\Reverse($input['rid']);
        if ($reverse->clientid != $_SESSION['uid']) {
            return AjaxResponse::I()->addRawError('...')->toArray();
        }
        try {
            $rdata = $input['rdata'];
            $blockerHelper = new BlockerHelper();
            $isBlocked = false;

            if(!$blockerHelper->isLoggedUserExcluded()) {

                $rules = $blockerHelper->getRules(true);

                foreach($rules as $rule) {
                    $rule = trim($rule);

                    if($blockerHelper->isRecordBlocked($rule, $rdata)) {
                        $isBlocked = true;
                        break;
                    }
                }
            }

            if($isBlocked) {
                return AjaxResponse::I()->addError('value_is_blocked')->toArray();
            }

            $helper = new main\mgLibs\custom\reverse\ReverseDNS($reverse);
            $helper->setDomain($input['rdata']);
            $helper->update();
        } catch (Exception $e) {
            return AjaxResponse::I()->addRawError($e->getMessage())->toArray();
        }

        return AjaxResponse::I()->refreshPage($this->manageRDNSHTML($input))->addInfo('RDNSchanged')->toArray();
    }

    public function dnsSecHTML($input, $vars = array())
    {
        $this->redirectIfIsOnlyRDNSforCA();

        $helper = new ClientHelper($_SESSION['uid']);
        $zone = new Zone($input['zone_id']);
        $module = $zone->getModule();

        $checkServer = $helper::getServerStatusByZoneId($zone->id);

        if(!$helper->isZoneOwnedByClient($zone))
        {
            $vars['error'] = lang::T('you_cannot_edit_this_zone_because_it_is_not_belongs_to_you');
        }
        elseif(!$checkServer['status'])
        {
            $vars['error'] = lang::T('you_cannot_edit_this_zone_because_server_is_not_active');
        }
        elseif(! ($zone->getServer()->getSettings(ServerSettingEnum::ENABLE_DNSSEC) == 'on' && $module->isDNSSECSupported()))
        {
            $vars['error'] = lang::T('dnssec_is_disabled');
        }
        else
        {
            if(!$module->zoneExists())
            {
                $vars['error'] = lang::T('you_cannot_edit_this_zone_because_it_is_terminated_on_server');
            }
            else
            {
                $vars['is_signed']  =   $module->isSigned();
                $vars['keys']       =   array();
                $keys               =   $module->getSignKeys();

                if(method_exists($keys, 'hasKeys') && $keys->hasKeys())
                {
                    $vars['keys']['keys']   =   array_merge($keys->getKsk(), $keys->getCsk(), $keys->getZsk());
                    $vars['keys']['ds']     =   $keys->getDs();
                }
            }
        }

        $vars['zone_name']  =   $zone->name;
        $vars['zoneid']     =   $zone->id;

        return array
        (
            'tpl'   => 'dnssec',
            'vars' => $vars
        );
    }

    public function disableDnssecJSON($input, $vars = array())
    {
        $helper = new ClientHelper($_SESSION['uid']);
        $zone = new Zone($input['zone_id']);
        $module = $zone->getModule();

        if(!$helper->isZoneOwnedByClient($zone))
        {
            return AjaxResponse::I()->addRawError(lang::T('you_cannot_edit_this_zone_because_it_is_not_belongs_to_you'))->toArray();
        }

        $checkServer = $helper::getServerStatusByZoneId($zone->id);
        if(!$checkServer['status'])
        {
            return AjaxResponse::I()->addRawError(lang::T('you_cannot_edit_this_zone_because_server_is_not_active'))->toArray();
        }

        if(! ($zone->getServer()->getSettings(ServerSettingEnum::ENABLE_DNSSEC) == 'on' && $module->isDNSSECSupported()))
        {
            return AjaxResponse::I()->addRawError(lang::T('dnssec_is_disabled'));
        }

        try
        {

            $module->unsign();
        }
        catch(Exception $e)
        {
            return AjaxResponse::I()->addRawError($e->getMessage())->toArray();
        }

        return AjaxResponse::I()->refreshPage($this->dnsSecHTML($input))->addInfo('DNSSECDisabledSuccess')->toArray();
    }

    public function enableDnssecJSON($input, $vars = array())
    {
        $helper = new ClientHelper($_SESSION['uid']);
        $zone = new Zone($input['zone_id']);
        $module = $zone->getModule();

        if(!$helper->isZoneOwnedByClient($zone))
        {
            return AjaxResponse::I()->addRawError(lang::T('you_cannot_edit_this_zone_because_it_is_not_belongs_to_you'))->toArray();
        }

        $checkServer = $helper::getServerStatusByZoneId($zone->id);
        if(!$checkServer['status'])
        {
            return AjaxResponse::I()->addRawError(lang::T('you_cannot_edit_this_zone_because_server_is_not_active'))->toArray();
        }

        if(! ($zone->getServer()->getSettings(ServerSettingEnum::ENABLE_DNSSEC) == 'on' && $module->isDNSSECSupported()))
        {
            return AjaxResponse::I()->addRawError(lang::T('dnssec_is_disabled'));
        }

        try
        {
            $module->sign();
        }
        catch(Exception $e)
        {
            return AjaxResponse::I()->addRawError($e->getMessage())->toArray();
        }

        return AjaxResponse::I()->refreshPage($this->dnsSecHTML($input))->addInfo('DNSSECEnableSuccess')->toArray();
    }

    public function rectifyDnssecJSON($input, $vars = array())
    {
        $helper = new ClientHelper($_SESSION['uid']);
        $zone = new Zone($input['zone_id']);
        $module = $zone->getModule();

        if(!$helper->isZoneOwnedByClient($zone))
        {
            return AjaxResponse::I()->addRawError(lang::T('you_cannot_edit_this_zone_because_it_is_not_belongs_to_you'))->toArray();
        }

        $checkServer = $helper::getServerStatusByZoneId($zone->id);
        if(!$checkServer['status'])
        {
            return AjaxResponse::I()->addRawError(lang::T('you_cannot_edit_this_zone_because_server_is_not_active'))->toArray();
        }

        if(! ($zone->getServer()->getSettings(ServerSettingEnum::ENABLE_DNSSEC) == 'on' && $module->isDNSSECSupported()))
        {
            return AjaxResponse::I()->addRawError(lang::T('dnssec_is_disabled'));
        }

        try
        {
            $module->rectify();
        }
        catch(Exception $e)
        {
            return AjaxResponse::I()->addRawError($e->getMessage())->toArray();
        }

        return AjaxResponse::I()->refreshPage($this->dnsSecHTML($input))->addInfo('DNSSECRectifySuccess')->toArray();
    }

    public function arraySortByValue($key)
    {
        return function ($obA, $obB) use ($key)
        {
            return strnatcmp($obA->$key, $obB->$key);
        };
    }

    /* DNS Sets */
    public function listJSON($input, $vars = array())
    {
        $query = "SELECT dns_manager2_set.id AS id, dns_manager2_set.default AS def, dns_manager2_set.idu AS idu, dns_manager2_set.name AS name, COUNT(DISTINCT(dns_manager2_setrecord.id)) AS dnsrecords
                    FROM dns_manager2_set
                    LEFT JOIN dns_manager2_setrecord ON dns_manager2_setrecord.setid = dns_manager2_set.id
                    LEFT JOIN dns_manager2_packageset ON dns_manager2_packageset.setid = dns_manager2_set.id
                    LEFT JOIN dns_manager2_package ON dns_manager2_package.defaultset = dns_manager2_set.id
                    WHERE idu = ".$_SESSION['uid']."
                    GROUP BY dns_manager2_set.id";

        $columns = array('name','dnsrecords','idu','def');
        $helper = new main\mgLibs\custom\RawQueryTableHelper($query, $input, $columns);
        $vars = $helper->getDataTableArray();

        foreach($helper->get() as $set)
        {
            $vars['data'][] = $this->dataTablesParseRow('set-row', array('set' => $set));
        }

        return $vars;
    }

    public function addSetJSON($input, $vars = array())
    {
        $vars['set'] = $this->set_form;
        $vars['available_record_types'] = main\mgLibs\custom\dns\Core::getAvailableRecordTypesByActiveServers();

        return AjaxResponse::I()->modal('set-edit', $vars)->toArray();
    }

    public function addNewRecordJSON($input, $vars = array())
    {
        $class = 'MGModule\DNSManager2\mgLibs\custom\dns\record\type\\' . $input['new_record_type'];
        if(class_exists($class))
        {
            $vars['counter'] = $input['records_counter'];
            $vars['record_type'] = $input['new_record_type'];
            $vars['record_obj'] = new $class();
            $vars['record_fields'] = get_object_vars($vars['record_obj']);

            AjaxResponse::I()->new_record = main\mgLibs\smarty::I()->view('new-record',
                $vars,
                main\addon::getModuleTemplatesDir().DS.'pages' . DS . main\addon::I()->page);
        }
        else
        {
            AjaxResponse::I()->addError('cannot_find_class', array('class' => $class));
        }

        return AjaxResponse::I()->toArray();
    }

    public function duplicateSetJSON($input, $vars = array()) {
        $set = new set\Set($input['id']);

        $vars['set']['id'] = $set->id;
        $vars['set']['name'] = $set->name.' Duplication';

        return AjaxResponse::I()->modal('set-duplicate', $vars)->toArray();
    }

    public function setDuplicateJSON($input, $vars = array()) {
        $duplicatedSet = new set\Set($input['id']);
        $newSet = new set\Set(false);

        $newSet->name = $input['name'];
        $newSet->idu = $duplicatedSet->idu;
        $newSet->save();

        foreach($duplicatedSet->getRecords() as $record_data) {
            $newSet->setRecord($record_data->name, $record_data->type, $record_data->ttl, $record_data->rdata, false);
        }

        AjaxResponse::I()->addInfo('changes_saved');
        return AjaxResponse::I()->toArray();
    }

    public function editSetJSON($input, $vars = array())
    {
        $set = new main\models\custom\set\Set($input['id']);

        $vars['set'] = $this->set_form;
        $vars['set']['edit'] = true;
        $vars['set']['id'] = $set->id;
        $vars['set']['name'] = $set->name;
        $vars['set']['default'] = $set->default;
        $vars['set']['records'] = $set->getRecords();
        $vars['set']['count'] = count($vars['set']['records']);

        $vars['counter'] = 0;
        $vars['available_record_types'] = main\mgLibs\custom\dns\Core::getAvailableRecordTypesByActiveServers();

        return AjaxResponse::I()->modal('set-edit', $vars)->toArray();
    }

    public function setSaveJSON($input, $vars = array())
    {
        if($input['default'] == '1')
        {
            $user_sets = main\mgLibs\MySQL\query::select(array('id','name','idu','default'), 'dns_manager2_set', array('idu' => $_SESSION['uid']))->fetchAll();
            foreach($user_sets as $u)
            {
                main\mgLibs\MySQL\query::update('dns_manager2_set', array('default' => ''), array('idu' => $_SESSION['uid']));
            }
        }

       $blockerHelper = new BlockerHelper();
        $isBlocked = false;

        if(!$blockerHelper->isLoggedUserExcluded()) {

            $rules = $blockerHelper->getRules();

            foreach($input['record'] as $singleRecord){
                foreach($rules as $rule) {
                    $rule = trim($rule);


                    if($blockerHelper->isRecordBlocked($rule, $singleRecord['name'])) {
                        $isBlocked = true;
                        break;
                    }
                }
            }
        }

        if($isBlocked) {
            return AjaxResponse::I()->addError('value_is_blocked')->toArray();
        }

        $set = new main\models\custom\set\Set($input['id']?:false);
        $set->name = $input['name'];
        $set->idu = $_SESSION['uid'];
        $set->default = $input['default'];
        $set->save();

        foreach($input['record'] as $record_data)
        {
            $set->setRecord($record_data['name'], $record_data['type'], $record_data['ttl'], $record_data['field'], $record_data['id']?:false);
        }

        foreach($input['remove_record'] as $id)
        {
            $record = new main\models\custom\set\record\SetRecord($id);
            $record->delete();
        }



        AjaxResponse::I()->addInfo('dns_record_added_successfully');

        return AjaxResponse::I()->toArray();
    }

    public function removeSetJSON($input, $vars = array())
    {
        main\models\custom\set\Set::factory($input['id'])->delete();

        return AjaxResponse::I()->addInfo('set_removed')->toArray();
    }

    private function getClientSets()
    {
        $clientSets = set\Repository::factory()->byUserId((int)$_SESSION['uid'])->get();
        return $clientSets;
    }

    private function getDefaultSet()
    {
        $default = set\Repository::factory()->byUserId((int)$_SESSION['uid'])->setFilter('default',1)->get();
        return $default[0]->id;
    }

    public function setRecordsJSON($input, $vars = array())
    {
        if(!array_filter($input['zone']['checked']))
        {
            return AjaxResponse::I()->addError('select_one_at_least')->toArray();
        }
        $vars['sets'] = $this->getClientSets();

        return AjaxResponse::I()->modal('set-records', $vars)->toArray();
    }

    public function exportFromFileJSON($input, $vars = array())
    {
        $vars['exportId'] = $input['id'];

        AjaxResponse::I()->refreshPage(array('tpl' => 'export-list', 'vars' => $vars));
        return AjaxResponse::I()->toArray();
    }

    public function exportZonesJSON($input, $vars = array())
    {

        $add = false;
        $exported = false;

        foreach($input['zone'] as $result_id => $data)
        {
            if($data['export'] != 'on' && !isset($input['justOne']))
            {
                continue;
            }
            $exported = true;

            $result = new task\result\TaskResult($result_id);

            $task = custom\TaskManager::getTaskObjectByID($result->taskid);
            $main_task = $task->getParent(); //TODO: można zmniejszyć ilość danych poprzez odwołanie się do resulta
            $result->data['resultid'] = $result_id;

            $child = $main_task->addChild('export', $result->data);

            $result->data['status'] = 'exporting';
            $result->data['taskid'] = $child->obj()->id;
            $result->save();
            if(isset($input['runNow']))
            {
                $child->run();
                if($child->getStatus() !== 'finished')
                {
                    AjaxResponse::I()->addError('something_went_wrong_during_import');
                }
                else
                {
                    AjaxResponse::I()->addInfo('zone_imported');
                }
            }
            else
            {
                if($add === false)
                {
                    AjaxResponse::I()->addInfo('new_task_added');
                    $add = true;
                }
            }

        }

        if(!$exported)
        {
            AjaxResponse::I()->addError('no_zone_selected_for_import_export');
        }

        return AjaxResponse::I()->toArray();
    }

    function refreshExportTableJSON($input, $vars = array())
    {
        $pRep = task\Repository::factory()->byParentID($input['id'])->one();
        $pRepName = explode(':', $pRep->name);

        $task = custom\TaskManager::getXTasks(1, $pRepName[0].':fetchZonesList', $input['id'], false);
        $task = end($task);


        $rep = task\result\Repository::factory()->byTaskID($task->id);

        $helper = new main\mgLibs\custom\RepoTableHelper($rep, $input, array('data'));

        $vars = $helper->getDataTableArray();
        $whmcsZones = query::query('SELECT name, id FROM dns_manager2_zone')->fetchGroup();


        foreach($helper->get() as $task)
        {
            if(!isset($whmcsZones[$task->data['domain']]))
            {
                $task->data['status'] = 'notExistInWhmcs';
            }

            $vars['data'][] = $this->dataTablesParseRow('export-row',
                array(
                    'item' => $task,
                    'exportId' => $input['id'],
                )
            );
        }

        return $vars;
    }

    public function backupsHTML($input, $vars = array())
    {
        if(GlobalSettingHelper::getSetting(GlobalSettingEnum::LINK_TO_CLIENTAREA_IMPORT_EXPORT, true) != 'on')
        {
            redir('m=DNSManager2');
        }
        $this->redirectIfIsOnlyRDNSforCA();

        $vars['backupsTasks'] = $this->getImportToFileClientTasks();

        $newImportsToFile = custom\TaskManager::getXTasksObjects(0, 'ExportFromFileWHMCS:main', 0, task\TaskStatusEnum::START, $_SESSION['uid']);

        $this->parseNewImportTaskList($newImportsToFile, $vars['backupsTasks']);

        $toFileImports = custom\TaskManager::getXTasksObjects(0, 'ExportFromFileWHMCS:main', 0, task\TaskStatusEnum::IN_PROGRESS, $_SESSION['uid']);

        $this->parseInProgresImportTaskList($toFileImports, $vars['backupsTasks'], 'ExportFromFileWHMCS', $_SESSION['uid']);

        $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.'bulkZones');
        $filesList = main\mgLibs\custom\helpers\ImportExportFileHelper::listFilesForBulkExport($fileManager, false);
        $manualFilesList = ClientFilesManage::getManualBackups($_SESSION['uid'], $filesList, ClientFilesManage::BACKUP);
        $cronFilesList = ClientFilesManage::getCronBackups($_SESSION['uid'], $filesList, ClientFilesManage::BACKUP);

        $amountOfManualBackups = count($manualFilesList);
        $amountOfCronBackups = count($cronFilesList);
        $manualBackupsLimit = GlobalSettingHelper::getSetting(GlobalSettingEnum::CLIENTAREA_IMPORT_EXPORT_LIMIT);
        $cronBackupsLimit = GlobalSettingHelper::getSetting(GlobalSettingEnum::CRON_BACKUP_LIMIT);

        $manualBackupsLimit = $manualBackupsLimit != -1 ? $manualBackupsLimit : '∞';
        $cronBackupsLimit = $cronBackupsLimit != -1 ? $cronBackupsLimit : '∞';

        if($manualBackupsLimit != 0)
        {
            $vars['manualBackupLimitDisplay'] = "({$amountOfManualBackups}/{$manualBackupsLimit})";
        }

        if($cronBackupsLimit != 0)
        {
            $vars['cronBackupLimitDisplay'] = "({$amountOfCronBackups}/{$cronBackupsLimit})";
        }

        $vars['caCanAddBackup'] = $this->canAddBackup();




        return array(
            'tpl' => 'backups',
            'vars' => $vars
        );
    }

    private function getImportToFileClientTasks()
    {
        $vars = array();

        $waitingImportsToFile = custom\TaskManager::getXTasksObjects(0, 'ImportToFileWHMCS:main', 0, task\TaskStatusEnum::WAITING, $_SESSION['uid']);

        $this->parseNewImportTaskList($waitingImportsToFile, $vars);

        $newImportsToFile = custom\TaskManager::getXTasksObjects(0, 'ImportToFileWHMCS:main', 0, task\TaskStatusEnum::START, $_SESSION['uid']);

        $this->parseNewImportTaskList($newImportsToFile, $vars);

        $toFileImports = custom\TaskManager::getXTasksObjects(0, 'ImportToFileWHMCS:main', 0, task\TaskStatusEnum::IN_PROGRESS, $_SESSION['uid']);

        $this->parseInProgresImportTaskList($toFileImports, $vars, 'ImportToFileWHMCS', $_SESSION['uid']);

        return $vars;
    }

    private function canAddBackup()
    {
        $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.'bulkZones');
        $filesList = main\mgLibs\custom\helpers\ImportExportFileHelper::listFilesForBulkExport($fileManager, false);
        $filesList = ClientFilesManage::getFilesForClient($_SESSION['uid'], $filesList, ClientFilesManage::BACKUP);
        $taskImport = $this->getImportToFileClientTasks();

        $amountOfBackups = count($filesList) + count($taskImport);
        $limit = GlobalSettingHelper::getSetting(GlobalSettingEnum::CLIENTAREA_IMPORT_EXPORT_LIMIT);


        if($limit <= $amountOfBackups && $limit != -1)
        {
            return false;
        }
        return true;
    }

    public function uploadBackupFileJSON($input, $vars = array())
    {
        if(!$this->canAddBackup())
        {
            AjaxResponse::I()->addError('backups_limit_reached');
            return AjaxResponse::I()->toArray();
        }

        $fileName = main\mgLibs\custom\FileManager::removeFakePath($input['fileName']);

        if(!main\mgLibs\custom\FileManager::checkIfFileWasSent($fileName))
        {
            AjaxResponse::I()-> addError('sendingFailed', array('file' => $fileName));
            return AjaxResponse::I()->toArray();
        }

        $type = main\mgLibs\custom\FileManager::checkTypeByContent($fileName);

        if($type !== 'single' && $type !== 'bulk')
        {
            AjaxResponse::I()->addError('invalidContent', array('file' => $fileName));
            return AjaxResponse::I()->toArray();
        }

        $explodedFileName = explode('_', $fileName);
        $clientId = $explodedFileName[count($explodedFileName)-1];
        if($clientId != $_SESSION['uid'])
        {
            $newfileName = custom\helpers\ImportExportFileHelper::generateClientFileName($_SESSION['uid']);
            foreach ($_FILES as &$file)
            {
                if($file['name'] == $fileName)
                {
                    $file['name'] = $newfileName;
                    $fileName = $newfileName;
                }
            }
        }

        $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.$type.'Zones');

        if(!$fileManager->isStorageReadable() || !$fileManager->isStorageWritable())
        {
            AjaxResponse::I()-> addError('directoryPermissionWritableReadable', array('storageDir' => $fileManager->getStoragePath()));
            return AjaxResponse::I()->toArray();
        }

        if($fileManager->fileExists($fileName))
        {
            AjaxResponse::I()->addError('fileAlreadyExist', array('file' => $fileName));
            return AjaxResponse::I()->toArray();
        }

        if($fileManager->uploadFile($fileName))
        {
            ClientFilesManage::save($fileName, $_SESSION['uid'], ClientFilesManage::BACKUP, 'client');
            AjaxResponse::I()->refreshPage($this->backupsHTML($input, $vars));
            AjaxResponse::I()->addInfo('uploadSuccesfull');


            return AjaxResponse::I()->toArray();
        }




        if(!main\mgLibs\custom\FileManager::checkIfFileWasSent($fileName))
        {
            AjaxResponse::I()-> addError('sendingFailed', array('file' => $fileName));
            return AjaxResponse::I()->toArray();
        }

    }

    private function sortBackupFiles(&$filesList, $order)
    {
        if($order)
        {
            rsort($filesList);
            return;
        }
        sort($filesList);
    }

    private function sortBackupFilesByZonesNumber(&$filesList, $order)
    {
        if($order)
        {
            arsort($filesList);
            return;
        }
        asort($filesList);
    }

    public function refreshBackupsTableJSON($input, $vars = array())
    {
        $vars['data'] = array();
        $vars['recordsTotal'] = 0;
        $vars['recordsFiltered'] = 0;

        $order = $input['order']['dir'] == 'desc' ? 1 : 0;
        $columnName = $input['order']['column'];

        $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.'bulkZones');
        $filesList = main\mgLibs\custom\helpers\ImportExportFileHelper::listFilesForBulkExport($fileManager, false, $order);

        $filesList = ClientFilesManage::getManualBackups($_SESSION['uid'], $filesList, ClientFilesManage::BACKUP);
        if($columnName == 'name')
        {
            $this->sortBackupFiles($filesList, $order);
        } elseif($columnName == 'type')
        {
            $newFilesList = [];
            foreach($filesList as $fileName)
            {
                $backupZone = main\mgLibs\custom\helpers\ImportExportFileHelper::loadFileContent('zonesFilesStorage'.DIRECTORY_SEPARATOR.'bulkZones', $fileName.'_'.$_SESSION['uid']);
                $newFilesList[$fileName] = count((array)$backupZone);
            }
            $this->sortBackupFilesByZonesNumber($newFilesList, $order);
            $filesList = array_keys($newFilesList);
        }

        foreach($filesList as $fileName)
        {
            $backupZone = main\mgLibs\custom\helpers\ImportExportFileHelper::loadFileContent('zonesFilesStorage'.DIRECTORY_SEPARATOR.'bulkZones', $fileName.'_'.$_SESSION['uid']);

            $vars['recordsTotal']++;
            if($input['search'] && $this->isFilenameMatch($fileName, $input['search']))
            {
                $vars['data'][] = $this->dataTablesParseRow('backup-row', array('fileName' => $fileName, 'type' => 'bulk', 'zonesAmount' => count((array)$backupZone)));
                $vars['recordsFiltered']++;
            }
            elseif(!$input['search'])
            {
                $vars['data'][] = $this->dataTablesParseRow('backup-row', array('fileName' => $fileName, 'type' => 'bulk', 'zonesAmount' => count((array)$backupZone)));
            }
        }
        $vars['recordsFiltered'] = $input['search'] ? $vars['recordsFiltered'] : $vars['recordsTotal'];

        $limit = $input['limit'];
        $offset = $input['offset'];
        $vars['data'] = array_slice($vars['data'], $offset, $limit);

        return $vars;
    }

    public function refreshCronBackupsTableJSON($input, $vars = array())
    {
        $vars['data'] = array();
        $vars['recordsTotal'] = 0;
        $vars['recordsFiltered'] = 0;

        $order = $input['order']['dir'] == 'desc' ? 1 : 0;
        $columnName = $input['order']['column'];

        $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.'bulkZones');
        $filesList = main\mgLibs\custom\helpers\ImportExportFileHelper::listFilesForBulkExport($fileManager, false, $order);

        $filesList = ClientFilesManage::getCronBackups($_SESSION['uid'], $filesList, ClientFilesManage::BACKUP);
        if($columnName == 'name')
        {
            $this->sortBackupFiles($filesList, $order);
        } elseif($columnName == 'type')
        {
            $newFilesList = [];
            foreach($filesList as $fileName)
            {
                $backupZone = main\mgLibs\custom\helpers\ImportExportFileHelper::loadFileContent('zonesFilesStorage'.DIRECTORY_SEPARATOR.'bulkZones', $fileName.'_'.$_SESSION['uid']);
                $newFilesList[$fileName] = count((array)$backupZone);
            }
            $this->sortBackupFilesByZonesNumber($newFilesList, $order);
            $filesList = array_keys($newFilesList);
        }

        foreach($filesList as $fileName)
        {
            $backupZone = main\mgLibs\custom\helpers\ImportExportFileHelper::loadFileContent('zonesFilesStorage'.DIRECTORY_SEPARATOR.'bulkZones', $fileName.'_'.$_SESSION['uid']);

            $vars['recordsTotal']++;
            if($input['search'] && $this->isFilenameMatch($fileName, $input['search']))
            {
                $vars['data'][] = $this->dataTablesParseRow('cron-backup-row', array('fileName' => $fileName, 'type' => 'bulk', 'zonesAmount' => count((array)$backupZone)));
                $vars['recordsFiltered']++;
            }
            elseif(!$input['search'])
            {
                $vars['data'][] = $this->dataTablesParseRow('cron-backup-row', array('fileName' => $fileName, 'type' => 'bulk', 'zonesAmount' => count((array)$backupZone)));
            }
        }
        $vars['recordsFiltered'] = $input['search'] ? $vars['recordsFiltered'] : $vars['recordsTotal'];

        $limit = $input['limit'];
        $offset = $input['offset'];
        $vars['data'] = array_slice($vars['data'], $offset, $limit);

        return $vars;
    }


    private function isFilenameMatch($fileName, $search)
    {
        if(strpos($fileName, $search) || strpos($fileName, $search) === 0)
        {
            return true;
        }

        return false;
    }

    public function removeBackupFileJSON($input, $vars = array())
    {
        $type = $input['type'];
        $fileName = $input['id'] . '_' . $_SESSION['uid'];
        $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.$type.'Zones');
        $exist = true;
        if(!$fileManager->fileExists($fileName))
        {
            $exist = false;
//            AjaxResponse::I()-> addError('fileDoesNotExist', array('file' => $fileName));
//            return AjaxResponse::I()->toArray();
        }

        if(!$exist)
        {
            ClientFilesManage::delete($_SESSION['uid'], $fileName, ClientFilesManage::BACKUP);
            AjaxResponse::I()->refreshPage($this->backupsHTML($input, $vars));
            AjaxResponse::I()->addInfo('fileRemoved');

            return AjaxResponse::I()->toArray();
        }

        if($fileManager->deleteFile($fileName) && $exist)
        {
            ClientFilesManage::delete($_SESSION['uid'], $fileName, ClientFilesManage::BACKUP);
            AjaxResponse::I()->refreshPage($this->backupsHTML($input, $vars));
            AjaxResponse::I()->addInfo('fileRemoved');

            return AjaxResponse::I()->toArray();
        }

        AjaxResponse::I()-> addError('fileDeleteFailed', array('file' => $fileName));
        return AjaxResponse::I()->toArray();
    }

    public function backupScheduleImportJSON($input, $vars = array())
    {
        custom\TaskManager::getTaskObjectByID($input['id'])->run(true);
        AjaxResponse::I()->addInfo('import_scheduled');
        AjaxResponse::I()->refreshPage($this->backupsHTML($input, $vars));
        return AjaxResponse::I()->toArray();
    }

    public function backupRemoveTaskJSON($input, $vars = array())
    {

        custom\TaskManager::removeTask($input['id']);

        ClientFilesManage::delete($_SESSION['uid'], $input['file'], ClientFilesManage::FROM_FILE_TO_WHMCS);
        AjaxResponse::I()->refreshPage($this->backupsHTML($input, $vars));
        AjaxResponse::I()->addInfo('taskRemoved');

        return AjaxResponse::I()->toArray();
    }

    public function downloandBackupFileHTML($input, $vars = array())
    {
        $this->redirectIfIsOnlyRDNSforCA();

        $filePatch = $_GET['path'];

        if(!strpos($filePatch, 'DNSManager2'.DIRECTORY_SEPARATOR.'storage'.DIRECTORY_SEPARATOR.'zonesFilesStorage'))
        {
            $filePatch = false;
        }

        ob_clean();
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="'.basename($filePatch).'"');
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header('Content-Length: '.filesize($filePatch));
        readfile($filePatch);
        die();
    }

    public function showBackupZonesJSON($input, $vars = array())
    {
        $fileName = $input['id'];
        $backupZone = main\mgLibs\custom\helpers\ImportExportFileHelper::loadFileContent('zonesFilesStorage'.DIRECTORY_SEPARATOR.'bulkZones', $fileName.'_'.$_SESSION['uid']);

        AjaxResponse::I()->result = $backupZone;

        return AjaxResponse::I()->toArray();
    }

    public function showCronBackupZonesJSON($input, $vars = array())
    {
        $fileName = $input['id'];
        $backupZone = main\mgLibs\custom\helpers\ImportExportFileHelper::loadFileContent('zonesFilesStorage'.DIRECTORY_SEPARATOR.'bulkZones', $fileName.'_'.$_SESSION['uid']);

        AjaxResponse::I()->result = $backupZone;

        return AjaxResponse::I()->toArray();
    }

    public function downloandBackupFileJSON($input, $vars = array())
    {
        $type = $input['type'];
        $fileName = $input['id'] . '_' . $_SESSION['uid'];

        $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.$type.'Zones');
        if(!$fileManager->fileExists($fileName))
        {
            AjaxResponse::I()-> addError('fileDoesNotExist', array('file' => $fileName));
            return AjaxResponse::I()->toArray();
        }

        $filePatch = $fileManager->getStoragePath().$fileName;

        $url = html_entity_decode(str_replace('mg-action=backups', 'mg-action=downloandBackupFile', $_SERVER['HTTP_REFERER']));

        return array('seturlto' => $url.'&path='.$filePatch);
    }

    public function addExportSaveJSON($input, $vars = array())
    {
        $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.'bulkZones');
        $fileName = $input['id'] . '_' . $_SESSION['uid'];
        $vars['isReadable'] = $fileManager->isStorageReadable();
        if(!$vars['isReadable'])
        {
            AjaxResponse::I()->addError('pathInNotReadAble');
            return AjaxResponse::I()->toArray();
        }
        $vars['storagePath'] = $fileManager->getStoragePath();
        if(!$vars['storagePath'])
        {
            AjaxResponse::I()->addError('storageNotExists');
            return AjaxResponse::I()->toArray();
        }

        $res = ClientFilesManage::saveIfNotExists($fileName, $_SESSION['uid'], ClientFilesManage::FROM_FILE_TO_WHMCS, 'client');
        if(!$res)
        {
            AjaxResponse::I()->addError('exportFromThisFileExist');
            return AjaxResponse::I()->toArray();
        }

        $task = custom\TaskManager::addTask('ExportFromFileWHMCS:main', array('fromFile' => $fileName), 0, $_SESSION['uid']);
        custom\TaskManager::getTaskObjectByID($task->id)->run(true);



        AjaxResponse::I()->refreshPage($this->backupsHTML($input, $vars));
        AjaxResponse::I()->addInfo('new_task_added');

        return AjaxResponse::I()->toArray();
    }

    public function importZonesJSON($input, $vars = array())
    {
        $add = false;
        $imported = false;
        foreach($input['zone'] as $resultId => $data)
        {
            if($data['import'] != 'on' && !isset($input['justOne']))
            {
                continue;
            }
            $imported = true;

            $task = new task\Task($input['id']);
            $task->status = task\TaskStatusEnum::IN_PROGRESS;
            $task->save();


            $result = new task\result\TaskResult($resultId);
            $task = custom\TaskManager::getTaskObjectByID($result->taskid);

            $main_task = $task->getParent();
            $result->data['resultid'] = $resultId;
            $result->data['domain']   = custom\helpers\IdnaHelper::idnaDecode($result->data['name']);
            $child = $main_task->addChild('import', $result->data);
            $result->data['status'] = 'importing';
            $result->data['taskid'] = $child->obj()->id;

            $result->save();
            if(isset($input['runNow']))
            {
                $child->run();
                if($child->getStatus() !== 'finished')
                {
                    AjaxResponse::I()->addError('something_went_wrong_during_import');
                }
                else
                {
                    AjaxResponse::I()->addInfo('zone_imported');
                }
            }
            else
            {
                if($add === false)
                {
                    AjaxResponse::I()->addInfo('zonesUpdated');
                    $add = true;
                }
            }
        }
        if(!$imported)
        {
            AjaxResponse::I()->addError('no_zone_selected_for_import_export');
        }
        return AjaxResponse::I()->toArray();
    }

    public function importJSON($input, $vars = array()) {
        return AjaxResponse::I()->refreshPage($this->importHTML($input, $vars))->toArray();
    }

    function refreshImportTableJSON($input, $vars = array())
    {

        $pRep = task\Repository::factory()->byParentID($input['id'])->one();
        $pRepName = explode(':', $pRep->name);

        $task = custom\TaskManager::getXTasks(1, $pRepName[0].':fetchZonesList', $input['id'], false);

        $task = end($task);

        $rep = task\result\Repository::factory()->byTaskID($task->id);

        $input['limit'] = $rep->count();

        $helper = new main\mgLibs\custom\RepoTableHelper($rep, $input, array('data'));

        $vars = $helper->getDataTableArray();

        foreach($helper->get() as $task)
        {
            $relid = $task->data['relid'];
            if($relid != '0')
            {
                try
                {
                    switch($task->data['type']) {
                        case '1':
                            $status = new main\models\whmcs\domains\domain($relid);
                            break;
                        case '2':
                            $status = new main\models\whmcs\service\service($relid);
                            break;
                    }
                }
                catch (\Exception $e)
                {
                    continue;
                }
                if(!$status || $status->status() != 'Active')
                    continue;
            }

            $vars['data'][] = $this->dataTablesParseRow('import-row',
                array(
                    'item' => $task,
                    'importid' => $input['id'],
                )
            );
        }

        return $vars;
    }

    public function showListImportToFileJSON($input, $vars = array())
    {
        $vars['importid'] = $input['id'];

        AjaxResponse::I()->refreshPage(array('tpl' => 'import-list-to-file', 'vars' => $vars));

        return AjaxResponse::I()->toArray();
    }

    public function addBackupImportZonesJSON($input, $vars = array())
    {
        if(!$this->canAddBackup())
        {
            AjaxResponse::I()->addError('backups_limit_reached');
            return AjaxResponse::I()->toArray();
        }

        $fileName = custom\helpers\ImportExportFileHelper::generateClientFileName($_SESSION['uid']);

        $task = custom\TaskManager::addTask('ImportToFileWHMCS:main', array('from' => 'WHMCS', 'toFile' => $fileName, 'createdBy' => 'client'), 0, $_SESSION['uid']);

        custom\TaskManager::getTaskObjectByID($task->id)->run(true);

        AjaxResponse::I()->refreshPage($this->backupsHTML($input, $vars));
        AjaxResponse::I()->addInfo('new_task_added');

        $input['id'] = $task->id;
        return $this->showListImportToFileJSON($input);
    }

    public function addBackupFileJSON($input, $vars = array())
    {
        return AjaxResponse::I()->modal('add-backupFile', $vars)->toArray();
    }

    public function addExportShowZonesJSON($input, $vars = array())
    {
        return AjaxResponse::I()->modal('add-backupFile', $vars)->toArray();
    }


    public function setRecordsSaveJSON($input, $vars = array())
    {
        $zones = $input['zone']['checked'];
        $wipe  = $input['wipe'];

        if(!$input['setRecord'])
        {
            $input['setRecord'] = $this->getDefaultSet();
            if(!$input['setRecord'])
            {
                return AjaxResponse::I()->addError('no_default_set_defined')->toArray();
            }
        }
        if($wipe == 'on')
        {
            $wipe = true;
        }
        else
        {
            $wipe = false;
        }

        $tasks = main\models\custom\task\Repository::factory()->setFilter('name', 'DnsRecord:main')->setFilter('status', 'start')->get();

        foreach($tasks as $task)
        {
            foreach($task->params['zones']  as $id => $zone)
            {
                if(array_key_exists($id, $zones) && $zones[$id] == 'on' && $zone == 'on')
                {
                    return AjaxResponse::I()->addError('zone_already_in_task')->toArray();
                }
            }
        }

        foreach($zones as $id => $v)
        {
            if(!$v)
            {
                continue;
            }

            $zone       = new Zone($id);
            $packageId  = $zone->getPackage()->id;
            if($wipe == false)
            {
                $currentRecords = $zone->getModule()->getRecords();
                $limitCheck     = custom\helpers\RecordSetHelper::checkAllowedRecordsLimits($packageId, $input['setRecord'],$currentRecords);
            }
            elseif($wipe == true)
            {
                $limitCheck = custom\helpers\RecordSetHelper::checkAllowedRecordsLimits($packageId, $input['setRecord']);
            }

            if(!$limitCheck)
            {
                return AjaxResponse::I()->addError('you_have_exceeded_limit')->toArray();
            }
        }

        $mainTask   = custom\TaskManager::addTask('DnsRecord:main',array('recordId' => $input['setRecord'] , 'zones' => $zones, 'wipe' => $wipe));

        AjaxResponse::I()->addInfo('set_added_successfully');

        return AjaxResponse::I()->refreshPage($this->indexHTML($input))->toArray();
    }

    public function parseNewImportTaskList($list, &$vars)
    {

        foreach($list as $import)
        {
            $type = explode(':', $import->obj()->name);



            if($type[0] == 'ImportToFileWHMCS') //Panie rilis //TODO na langa to
            {

                $desc = str_replace('Import', 'Backup', $import->description());
                $desc = $this->praseTaskDescription($desc);
            }
            else
            {
                $desc = str_replace('Export', 'Restore', $import->description());
                $desc = $this->praseTaskExportDescription($desc);
            }
            $desc = str_replace('WHMCS', lang::T('backup', 'system'), $desc); // TODO przerobić to na next bo mess

            $vars[] = array(
                'id' => $import->obj()->id,
                'desc' => $import->description(),
                'parsedDesc' => $desc,
                'zones_imported' => '-',
                'zones_total' => '-',
                'progress' => -1,
                'type' => $import->getTaskTypeCode()
            );
        }
    }



    private function praseTaskDescription($desc)
    {

        $parts = explode(' from: ', $desc);

        $parts[0] .= ' from: ';
        $tmpParts = explode(' to: ', $parts[1]);
        if(count($tmpParts) > 1)
        {
            $parts[1] = $tmpParts[0];
            $parts[2] = ' to: ';
            $parts[3] = ClientFilesManage::getFileNameWithoutClientId($tmpParts[1]);
        }
        return $parts;
    }

    private function praseTaskExportDescription($desc)
    {

        $parts = explode(' from: ', $desc);

        $parts[0] .= ' from: ';

        $tmpParts = explode(' to: ', $parts[1]);

        if(count($tmpParts) > 1)
        {
            $parts[1] = ClientFilesManage::getFileNameWithoutClientId($tmpParts[0]);
            $parts[2] = ' to: ';
            $parts[3] = $tmpParts[1];
        }

        return $parts;
    }



    private function getTaskError($task) {
        $erorr = false;

        if($task->getStatus() == task\TaskStatusEnum::ERROR) {
            $erorr = 'Error';
            $results = $task->getResults();
            $result = end($results);
            if(isset($result->data['error'])) {
                $erorr .= ' (' . $result->data['error'] . ')';
            }
        }

        return $erorr;
    }

    public function parseInProgresImportTaskList($list, &$vars, $type = 'Import', $clientId = false)
    {

        foreach($list as $import)
        {
            $rep = new task\Repository();

            $childTaskType = strpos($type, 'Export') === 0 ? 'export' : 'import';
            $rep->byParentID($import->obj()->id)->byName($type.':'.$childTaskType);

            $zones_total = $rep->count();

            $rep->byStatus(task\TaskStatusEnum::FINISHED);
            $zones_imported = $rep->count();


            if(is_array($type))
            {
                $type = $type[0];
            }

            $task = custom\TaskManager::getXTasksObjects(1, $type.':fetchZonesList', $import->obj()->id, false, $clientId);


            $error = $this->getTaskError(end($task));

            $type = explode(':', $import->obj()->name);

            if($type[0] == 'ImportToFileWHMCS') //Panie rilis //TODO na langa to
            {

                $desc = str_replace('Import', 'Backup', $import->description());
                $desc = $this->praseTaskDescription($desc);
            }
            else
            {
                $desc = str_replace('Export', 'Restore', $import->description());
                $desc = $this->praseTaskExportDescription($desc);
            }
            $desc = str_replace('WHMCS', lang::T('backup', 'system'), $desc); // TODO przerobić to na next bo mess

            $vars[] = array(
                'id' => $import->obj()->id,
                'desc' => $import->description(),
                'zones_imported' => $zones_imported,
                'zones_total' => $zones_total,
                'progress' => $zones_total == 0 ? 0 : ceil($zones_imported * 100 / $zones_total),
                'error' => $error,
                'parsedDesc' => $desc,
                'type' => $import->getTaskTypeCode(),//strpos($import->description(), 'Import') === 0 ? 'Import' : 'Export'
                'status' => $import->obj()->status
            );
        }
    }

    private function redirectIfIsOnlyRDNSforCA()
    {
        if(GlobalSettingHelper::getSetting(GlobalSettingEnum::RDNS_IN_CLIENTAREA) == GlobalSettingEnum::CLIENTAREA_RNDS_ONLY)
        {
            header('Location: index.php?m=DNSManager2&mg-action=manageRDNS');
            die;
        }
    }

    /**
     * @param Zone $zone
     *
     * @return bool
     */
    private function isTransferAndShouldBeAbleToEdit( Zone $zone )
    {
        return $this->checkWhmcsProductStatus($zone->type, $zone->relid) === 'pending transfer';
    }
}
