<?php

class DefaultController extends Controller
{

    /**
     * @var string the default layout for the views. Defaults to '//layouts/column2', meaning
     * using two-column layout. See 'protected/views/layouts/column2.php'.
     */
    public $layout = '//layouts/column2';

    const CHAIN_WHITELIST = 'whitelist';

    /**
     * @return array action filters
     */
    public function filters()
    {
        return array(
            'accessControl', // perform access control for CRUD operations
        );
    }

    /**
     * Specifies the access control rules.
     * This method is used by the 'accessControl' filter.
     * @return array access control rules
     */
    public function accessRules()
    {
        return array(
            array('allow', // allow all users to perform 'index' and 'view' actions
                'actions' => array(
                    'index',
                    'delete',
                    'admin',
                    'ajaxValidate',
                    'outputRules',
                    'changeFirewallStatus',
                    'bannedHosts',
                    'removeBanHost',
                    'whitelistRules',
                    'removeWhitelist',
                    'addToWhitelist'
                ),
                'expression' => AccessManager::checkSessionPermission($this->module->name),
            ),
            array('deny', // deny all users
                'users' => array('*'),
            ),
        );
    }

    public function actionOutputRules()
    {
        $this->actionIndex(FirewallRule::CHAIN_OUTPUT);
    }

    public function actionChangeFirewallStatus()
    {
        if (cfg('FIREWALL_ENABLED') == '1') {
            setCfg('FIREWALL_ENABLED', '0');
        } else {
            setCfg('FIREWALL_ENABLED', '1');
        }
        $this->writeFirewallDataToCtrld();
        echo cfg('FIREWALL_ENABLED');
    }

    public function actionIndex($chain = FirewallRule::CHAIN_INPUT)
    {
        $model = new FirewallRule();
        if (isset($_REQUEST['Firewall'])) {
            foreach ($_REQUEST['Firewall'] as $id => $post) {
                if ($this->skipFirewallRule($id, $post)) {
                    continue;
                }
                $this->updateFirewallRules($id, $post);
            }
            $this->writeFirewallDataToCtrld();
        }
        $firewallStatus = cfg('FIREWALL_ENABLED');
        $this->render('index', array('model' => $model, 'chain' => $chain, 'firewallStatus' => $firewallStatus));
    }

    public function updateFirewallRules($id, $post)
    {
        $model = FirewallRule::model()->findByPk($id);
        if (!$model) {
            $model = new FirewallRule();
        }
        $model->attributes = $this->getAttributeValues($post);

        if ($model->save()) {
            if (!app()->user->hasFlash('error')) {
                app()->user->setSuccessFlashMessage();
            }
        } else {
            app()->user->setErrorFlashMessage('CHANGES_NOT_SAVED_CAUSE_OF_AN_ERROR', $model->getFormatedErrors());
        }
    }

    public function getAttributeValues($attributes)
    {
        if (isset($attributes['sort']) && $attributes['sort'] == 'new' && isset($attributes['chain'])) {
            $attributes['sort'] = FirewallRule::model()->countByAttributes(array('chain' => $attributes['chain']));
        }
        return $attributes;
    }

    public function actionDelete($id)
    {
        if (Yii::app()->request->isPostRequest) {
            $this->loadModel($id)->delete();
            // if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
            if (!isset($_GET['ajax'])) {
                $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('index'));
            }
        } else {
            throw new CHttpException(400, 'Invalid request. Please do not repeat this request again.');
        }
    }

    /**
     * Returns the data model based on the primary key given in the GET variable.
     * If the data model is not found, an HTTP exception will be raised.
     * @param integer the ID of the model to be loaded
     */
    public function loadModel($id, $modelName = 'FirewallRule')
    {
        $model = $modelName::model()->findByPk($id);
        if ($model === null) {
            throw new CHttpException(404, 'The requested page does not exist.');
        }
        return $model;
    }

    public function renderActiveCell($data)
    {
        $this->renderPartial("_activeCell", array("data" => $data));
    }

    public function renderDropdownCell($data, $row, $column)
    {
        $listData = $this->getDropdownListData($data, $column->name);
        $this->renderPartial("_dropdownCell", array(
            "listData" => $listData,
            "data" => $data,
            'attribute' => $column->name
                )
        );
    }

    protected function getDropdownListData($model, $attribute)
    {
        $listData = array();
        if ($attribute == 'protocol') {
            $listData = $model->getProtocolDataArray();
        } else if ($attribute == 'action') {
            $listData = $model->getActionDataArray();
        }
        return $listData;
    }

    public function renderPortCell($data, $row, $column)
    {
        $this->renderPartial("_portCell", array("data" => $data, 'attribute' => $column->name));
    }

    public function renderTextCell($data, $row, $column)
    {
        $this->renderPartial("_textCell", array("data" => $data, 'attribute' => $column->name));
    }

    public function renderhiddenSortCell($data, $row, $column)
    {
        $this->renderPartial("_hiddenSortCell", array("data" => $data, 'attribute' => $column->name));
    }

    public function renderhiddenChainAttribute($data, $row, $column)
    {
        return CHtml::hiddenField("Firewall[chain]", self::CHAIN_WHITELIST, array(
                    'class' => 'hidenIndex',
                        )
        );
    }

    public function renderSourceCell($data, $row, $column)
    {
        return CHtml::activeTextField($data, $column->name, array(
                    'name' => 'Firewall[' . $data->id . '][' . $column->name . ']',
                    'placeholder' => '192.168.1.0/24')
        );
    }

    public function actionAjaxValidate()
    {
        if (isset($_REQUEST['Firewall']['chain']) && $_REQUEST['Firewall']['chain'] == self::CHAIN_WHITELIST) {
            return;
        }

        $model = new FirewallRule();
        $errors = array();
        foreach ($_REQUEST['Firewall'] as $modelId => $attributes) {

            if ($this->skipFirewallRule($modelId, $attributes)) {
                continue;
            }
            $model->attributes = $this->getAttributeValues($attributes);
            $validateOutput = CActiveForm::validate($model);
            $decodetOutput = (array) json_decode($validateOutput);

            foreach ($decodetOutput as $key => $value) {
                //overwrite inputField Id
                $newKey = '';
                foreach (explode('_', $key) as $index => $part) {
                    if ($index == 0) {
                        $newKey .= $part . '_' . $modelId;
                    } else {
                        $newKey .= '_' . $part;
                    }
                }
                $errors[$modelId][$newKey] = $value;
            }
        }

        if (isset($errors['new']) && empty($errors['new'])) {
            unset($errors['new']);
        }

        if (!empty($errors)) {
            echo json_encode($errors);
        }
        Yii::app()->end();
    }

    protected function skipFirewallRule($modelId, $attributes)
    {
        $skip = false;
        if ($modelId == 'new') {
            foreach ($attributes as $attribute) {
                if (!empty($attribute)) {
                    break;
                }
                $skip = true;
            }
        }
        return $skip;
    }

    protected function writeFirewallDataToCtrld()
    {
        $data = array();
        $data['enable'] = cfg('FIREWALL_ENABLED');
        $inputRules = FirewallRule::model()->findAllByAttributes(array('chain' => FirewallRule::CHAIN_INPUT));
        $outputRules = FirewallRule::model()->findAllByAttributes(array('chain' => FirewallRule::CHAIN_OUTPUT));
        $data['chains']['INPUT'] = $this->getChainsData($inputRules);
        $data['chains']['OUTPUT'] = $this->getChainsData($outputRules);

        $result = PhonalisaCtrldConnector::writeFirewallConfig($data);
        if (!isset($result->status)) {
            app()->user->getFlashes(); // remove flash-messages
            return app()->user->setErrorFlashMessage();
        }
        if ($result->status == 'error') {
            app()->user->getFlashes(); // remove flash-messages
            app()->user->setErrorFlashMessage(@$result->errorText);
        }
    }

    protected function getChainsData($models)
    {
        $sortedData = array();
        foreach ($models as $model) {
            if ($model->active == '1') {
                $sortedData[$model->sort]['action'] = $model->action;
                $sortedData[$model->sort]['protocol'] = $model->protocol;
                $sortedData[$model->sort]['dport'] = $model->dport;
                $sortedData[$model->sort]['sport'] = $model->sport;
                $sortedData[$model->sort]['source'] = $model->source;
                $sortedData[$model->sort]['destination'] = $model->destination;
            }
        }
        ksort($sortedData);

        $data = array();
        foreach ($sortedData as $item) {
            $data[] = $item;
        }
        return $data;
    }

    public function actionBannedHosts()
    {
        $model = FirewallBannedHost::model();
        PhonalisaCtrldConnector::hasConnection();
        $this->render('bannedHosts', array('model' => $model));
    }

    public function actionRemoveBanHost($id)
    {
        if (Yii::app()->request->isPostRequest) {
            $this->loadModel($id, 'FirewallBannedHost')->delete();
            // if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
            if (!isset($_GET['ajax'])) {
                $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('index'));
            }
        } else {
            throw new CHttpException(400, 'Invalid request. Please do not repeat this request again.');
        }
    }

    public function actionWhitelistRules()
    {
        $model = new FirewallWhitelist();
        if (isset($_REQUEST['Firewall'])) {

            foreach ($_REQUEST['Firewall'] as $id => $whitelistRule) {

                if ($id == 'new' && empty($whitelistRule['source'])) {
                    continue;
                }

                $oldModel = FirewallWhitelist::model()->findByPk($id);
                if ($oldModel) {
                    $newModel = $oldModel;
                } else {
                    $newModel = new FirewallWhitelist();
                }
                $newModel->attributes = $whitelistRule;
                $newModel->save();
            }
        }
        $this->render('whitelist', array(
            'model' => $model,
            'chain' => self::CHAIN_WHITELIST
        ));
    }

    public function getTabItems($chain = '')
    {
        $firewallStatus = cfg('FIREWALL_ENABLED');
        return array(
            array(
                'label' => __('NETWORK_FIREWALL_NAVBAR_INPUT_RULES'),
                'icon' => 'icon-indent-right',
                'url' => url('networkFirewall/default/index'),
                'active' => $chain == FirewallRule::CHAIN_INPUT ? true : false,
                'linkOptions' => array(
                    'data-translation-id' => 'NETWORK_FIREWALL_NAVBAR_INPUT_RULES',
                )
            ),
            array(
                'label' => __('NETWORK_FIREWALL_NAVBAR_OUTPUT_RULES'),
                'icon' => 'icon-indent-left',
                'url' => url('networkFirewall/default/outputRules'),
                'active' => $chain == FirewallRule::CHAIN_OUTPUT ? true : false,
                'linkOptions' => array(
                    'data-translation-id' => 'NETWORK_FIREWALL_NAVBAR_OUTPUT_RULES',
                )
            ),
            array(
                'label' => __('NETWORK_FIREWALL_NAVBAR_WHITELIST_RULES'),
                'icon' => 'icon-circle-blank',
                'url' => url('networkFirewall/default/whitelistRules'),
                'active' => $chain == self::CHAIN_WHITELIST ? true : false,
                'linkOptions' => array(
                    'data-translation-id' => 'NETWORK_FIREWALL_NAVBAR_WHITELIST_RULES',
                )
            ),
            array(
                'label' => __('NETWORK_FIREWALL_NAVBAR_BANNED_HOSTS'),
                'icon' => 'icon-ban-circle',
                'url' => url('networkFirewall/default/bannedHosts'),
                'active' => $chain == '' ? true : false,
                'linkOptions' => array(
                    'data-translation-id' => 'NETWORK_FIREWALL_NAVBAR_BANNED_HOSTS',
                ),
            ),
            array(
                'label' => $firewallStatus ? __('NETWORK_FIREWALL_NAVBAR_FIREWALL_STATUS_ENABLED') : __('NETWORK_FIREWALL_NAVBAR_FIREWALL_STATUS_DISABLED'),
                'url' => '#',
                'position' => 'right',
                'linkOptions' => array(
                    'id' => 'firewallSwitch',
                    'style' => 'color:#fff; text-shadow:none',
                    'class' => $firewallStatus ? 'btn-success' : 'btn-danger',
                    'onClick' => 'changeFirewallStatus(this)'
                )
            ),
        );
    }

    public function renderDatetime($data)
    {
        return PhonalisaDate::convertServerDateTo('Y-m-d H:i:s', $data->datetime, true);
    }

    public function renderReasonText($data)
    {
        return __($data->reason);
    }

    public function actionRemoveWhitelist($id)
    {
        if (Yii::app()->request->isPostRequest) {
            $this->loadModel($id, 'FirewallWhitelist')->delete();
            // if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
            if (!isset($_GET['ajax'])) {
                $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('index'));
            }
        } else {
            throw new CHttpException(400, 'Invalid request. Please do not repeat this request again.');
        }
    }

    public function actionAddToWhitelist($id)
    {
        $bannedHost = FirewallBannedHost::model()->findByPk($id);
        if ($bannedHost) {
            $firewallWhitelist = new FirewallWhitelist();
            $firewallWhitelist->source = $bannedHost->ip;
            if ($firewallWhitelist->save()) {
                $bannedHost->delete();
            }
        }
        return $this->actionBannedHosts();
    }
}
