<?php

class DefaultController extends Controller
{

    public $layout = '//layouts/column2';

    /**
     * @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',
                    'provisioning',
                    'siemens',
                    'ergophoneHttpRequest',
                    'phonebook',
                    'config',
                    'registerErgophone',
                    'voicemail',
                    'login',
                    'langSettings',
                    'getLanguage',
                    'dial',
                    'getBootFile'
                ),
                'users' => array('*'),
            //'expression'=>AccessManager::checkSessionPermission($this->module->name),
            ),
            array('allow', // allow authenticated user to perform 'create' and 'update' actions
                'actions' => array('create', 'view', 'update', 'copy', 'trigger', 'extensionMap'),
                'users' => array('@'),
            //'expression'=>AccessManager::checkSessionPermission($this->module->name),
            ),
            array('allow',
                'actions' => array("networkScan", "startNetworkScan", "addToProvisioning", "cancelNetworkScan"),
                'users' => array('@'),
            //'expression'=>AccessManager::checkSessionPermission($this->module->name),
            ),
            array('allow', // allow admin user to perform 'admin' and 'delete' actions
                'actions' => array('admin', 'delete'),
                'users' => array('@'),
            //'expression'=>AccessManager::checkSessionPermission($this->module->name),
            ),
            array('deny', // deny all users
                'users' => array('*'),
            ),
        );
    }

    public function actionRegisterErgophone($ergophone_ip)
    {
        require_once __DIR__ . '/../phones/ergophone/lib/ErgophoneXml.php';
        $ip = $_REQUEST['ergophone_ip'];

        $header = ErgophoneHelper::getErgophoneData($ip . '/cgi-bin/do.cgi?cmd=systemInfoCmd');

        if ($header['content']) {
            $data = ErgophoneXml::xmlToArray($header['content']);
            $relevantData = array();
            $relevantData['ipv4_address'] = $data['local_ip'];
            $relevantData['mac_addr'] = $data['mac'];

            $header = ErgophoneHelper::getErgophoneData($ip . '/cgi-bin/do.cgi?cmd=swInfoCmd');
            $data = ErgophoneXml::xmlToArray($header['content']);
            $relevantData['firmware'] = $data['sw_version'];

            $header = ErgophoneHelper::getErgophoneData($ip . '/cgi-bin/do.cgi?cmd=voipInfoCmd');
            $data = ErgophoneXml::xmlToArray($header['content']);
            $relevantData['voipId'] = $data['account'][0]['sip_id'];
        } else {
            return false;
        }

        // save ergophone Phone model and do other provisioning stuff
        $phone = Phones::model()->findByAttributes(array('mac_addr' => str_replace(':', '', $relevantData['mac_addr'])));
        if ($phone) {
            $sipAccountId = SipAccounts::model()->findByPk($phone->sip_account_id);
            if ($sipAccountId) {
                if ($sipAccountId->authname != $relevantData['voipId']) {
                    $sipAccount = SipAccounts::model()->findbyAttributes(array('authname' => $relevantData['voipId']));
                    if ($sipAccount) {
                        $phone->sip_account_id = $sipAccount->id;
                        $phone->ipv4_address = $relevantData['ipv4_address'];
                        $phone->save();
                    }
                } else {
                    return true;
                }
            }
        } else {
            require_once $this->getModule()->getBasePath() . '/phones/ergophone/provisioning.php';
            $prov = new ErgophonePhoneProvisioning();
            $prov->registerErgophone($relevantData);
            return false;
        }
    }

    public function actionExtensionMap()
    {
        $limit = 100;
        $offset = 0;
        $allModels = array();
        do {
            $models = Phones::model()->findAll('', array('limit' => $limit, 'offset' => $offset));
            $allModels = array_merge($allModels, $models);
            $offset = $offset + $limit;
        } while (count($models) != 0);

        $generator = new ExtensionMapPDFGenerator();
        $generator->init(__("PHONALISA_EXTENSION_OVERVIEW"), date("r"));
        $generator->generatePhonesList($allModels);
    }

    public function actionProvisioning()
    {
        if (cfg("PROV_INIT_FROM_NET") !== '') {
            if (!isIpInNetRange(cfg("PROV_INIT_FROM_NET"))) {
                Log::e('Phone with IP "' . Yii::app()->request->getUserHostAddress() . '" is not in provisioning-range "' . cfg("PROV_INIT_FROM_NET") . '"', 'Provisioning');
                throw new CHttpException(403, 'not allowed to request settings.');
            }
        }

        $mac = Yii::app()->request->getParam("mac");
        if ($mac != "") {
            require_once $this->getModule()->getBasePath() . '/lib/phoneprovisioning.php';
            //this is a phone, so check which controller has to be called to route this stuff
            $ua = Yii::app()->request->getUserAgent();
            $controller = VirtualPhoneProvisioningController::getInstanceForPhoneModel($mac, $ua);
            if ($controller != NULL) {
                $controller->run($this);
            } else {
                throw new CHttpException(403, 'not allowed to request settings.');
            }
        } else if (Yii::app()->user->isGuest) {
            throw new CHttpException(403, 'not allowed to request settings.');
        } else {
            $this->actionIndex();
        }
    }

    public function actionTrigger($id)
    {
        if ($id == "") {
            return;
        }

        $phone = Phones::model()->findByPk($id);
        if ($phone != null) {
            $phone->triggerProvisioning();
        }
    }

    public function actionSiemens()
    {
        require_once $this->getModule()->getBasePath() . '/phones/siemens/provisioning.php';
        $prov = new SiemensPhoneProvisioning();
        $prov->run($this);
    }

    public function actionIndex()
    {
        if (Yii::app()->request->getParam("mac") != "") {
            require_once $this->getModule()->getBasePath() . '/lib/phoneprovisioning.php';
            //this is a phone, so check which controller has to be called to route this stuff
            $controller = VirtualPhoneProvisioningController::getInstanceForPhoneModel(Yii::app()->request->getParam("mac"), "");
            if ($controller != NULL) {
                $controller->run($this);
            }
        } else if (Yii::app()->user->isGuest) {
            throw new CHttpException(403, 'not allowed to request settings.');
        } else {
            $this->actionAdmin();
        }
    }

    /**
     * Deletes a particular model.
     * If deletion is successful, the browser will be redirected to the 'admin' page.
     * @param integer $id the ID of the model to be deleted
     */
    public function actionDelete($id)
    {
        if (Yii::app()->request->isPostRequest) {
            // we only allow deletion via POST request
            $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('admin'));
            }
        } else {
            throw new CHttpException(400, 'Invalid request. Please do not repeat this request again.');
        }
    }

    public function actionView($id)
    {
        $this->render('view', array(
            'model' => $this->loadModel($id),
        ));
    }

    /**
     * Updates a particular model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param integer $id the ID of the model to be updated
     */
    public function actionUpdate($id)
    {
        $model = $this->loadModel($id);

        // Uncomment the following line if AJAX validation is needed
        $this->performAjaxValidation($model);

        if (isset($_POST['Phones'])) {
            $currSipAccId = $model->sip_account_id;
            $model->attributes = $_POST['Phones'];
            if ($currSipAccId != $model->sip_account_id) {
                $model->last_sip_account_id = null;
            }

            if ($model->save())
                $this->redirect(array('view', 'id' => $model->id));
        }
        $availebleFirmwares = Firmware::model()->findAllByAttributes(array('phoneType' => $model->type));
        $stdFirmware = array('' => __('PROVISIONING_GENERAL_CONTROLLER_ACTION_UPDATE_STD_FIRMWARE')); // FIXME ! translation !

        $firmwareDropDownData = array();
        foreach ($availebleFirmwares as $firmware) {
            $firmwareDropDownData[$firmware->id] = $firmware->version;
        }
        asort($firmwareDropDownData);
        $firmwareDropDownData = array_merge($stdFirmware, $firmwareDropDownData);
        $this->renderPartial('_form', array('model' => $model, 'availebleFirmwares' => $firmwareDropDownData), false, true);
    }

    /**
     * Manages all models.
     */
    public function actionAdmin()
    {
        $model = new Phones('search');
        $model->unsetAttributes();  // clear any default values
        if (isset($_GET['Phones']))
            $model->attributes = $_GET['Phones'];

        $this->render('admin', array(
            'model' => $model,
        ));
    }

    public function actionNetworkScan()
    {
        $model = new NetworkScanResult("search");
        $networkInterfaceListData = NetworkInterface::getListData();

        $networkScannJobJSON = json_encode(array());
        $currentScannJob = Job::model()->findByAttributes(array("type" => Job::NetworkScan, "status" => Job::Running));

        if ($currentScannJob) {
            $networkScannJobJSON = json_encode($currentScannJob->attributes);
        }

        $this->render("networkScan", array(
            "model" => $model,
            "networkScannJobJSON" => $networkScannJobJSON,
            "networkInterfaceListData" => $networkInterfaceListData
                )
        );
    }

    public function actionStartNetworkScan()
    {
        $runningJobs = Job::model()->findAllByAttributes(array("status" => Job::Running, "type" => Job::NetworkScan));

        if (!count($runningJobs)) {
            $results = NetworkScanResult::model()->findAll();
            foreach ($results as $result) {
                $result->delete();
            }

            $job = new Job();
            $job->type = Job::NetworkScan;
            $job->user_id = "";
            $job->meta = $_POST["networkInterfaceIp"];

            if (!$job->save()) {
                throw new CHttpException(500, "Could not create new Job.");
            }
        }
    }

    public function actionAddToProvisioning($id)
    {
        $model = $this->loadNetworkScanResultModel($id);
        $job = new Job();
        $job->type = Job::AddPhoneToProvisioning;
        $job->user_id = "";
        $job->meta = $model->id;

        if (!$job->save()) {
            throw new CHttpException(500, "Could not create new Job.");
        }
        app()->end();
    }

    public function actionCancelNetworkScan()
    {
        $runningJobs = Job::model()->findAllByAttributes(array("status" => Job::Running, "type" => Job::NetworkScan));
        foreach ($runningJobs as $runningJob) {
            $runningJob->delete();
        }
    }

    /**
     * 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)
    {
        $model = Phones::model()->findByPk($id);
        if ($model === null) {
            throw new CHttpException(404, 'The requested page does not exist.');
        }
        return $model;
    }

    public function loadNetworkScanResultModel($id)
    {
        $model = NetworkScanResult::model()->findByPk($id);
        if ($model === null) {
            throw new CHttpException(404, 'The requested page does not exist.');
        }
        return $model;
    }

    /**
     * Performs the AJAX validation.
     * @param CModel the model to be validated
     */
    protected function performAjaxValidation($model)
    {
        if (isset($_POST['ajax']) && $_POST['ajax'] === 'phones-form') {
            echo CActiveForm::validate($model);
            Yii::app()->end();
        }
    }

    public function getHumanReadeblePhoneName($data)
    {
        $phones = new Phones();
        $phones = $phones->getPhoneManufactorAndModelNames();

        foreach ($phones as $manufactor => $phone) {
            if (isset($phones[$manufactor][$data->type])) {
                $phoneName = $phones[$manufactor][$data->type];
                return $phoneName;
            }
        }
        return $data->type;
    }

    public function renderFirmware($data)
    {
        $firmware = $data->firmware;
        $updateKey = $data->firmware_update_key;
        if ($updateKey === '') {
            $newFirmware = Firmware::model()->findByAttributes(array('standard' => '1', 'phoneType' => $data->type));
        } else {
            $newFirmware = Firmware::model()->findByPk($updateKey);
        }

        if ($newFirmware && $newFirmware->version != $data->firmware) {
            $firmware .= ' <span class="icon-double-angle-right"></span> ' . CHtml::encode($newFirmware->version);
        } else {
            $firmware = CHtml::encode($firmware);
        }
        return $firmware;
    }

    public function actionErgophoneHttpRequest()
    {
        require_once $this->getModule()->getBasePath() . '/phones/ergophone/provisioning.php';
        $prov = new ErgophonePhoneProvisioning();
        $prov->run($this);
    }

    public function actionLogin()
    {
        $this->proccessXMLApps('login');
    }

    public function actionVoicemail()
    {
        if (Yii::app()->request->isPostRequest) {
            $this->getVoicemail();
        } else {
            $this->proccessXMLApps('voicemail');
        }
    }

    protected function getVoicemail()
    {
        $vmID = Yii::app()->request->getParam('mac');
        $id = Yii::app()->request->getPost('id', '');
        $hash = Yii::app()->request->getPost('hash', '');

        $userModel = User::model()->findByPk($id);
        if (!$userModel) {
            throw new CHttpException(404, 'User not found!');
        }

        if ($hash !== $userModel->password) {
            throw new CHttpException(401, 'Unauthorized');
        }

        $model = Voicemail::model()->findByPK($vmID);

        if ($model && $model->ownerExtension === $userModel->extension) {
            $length = 0;
            $data = "";
            $binaryField = "data";
            $model->getBinaryField($binaryField, $data, $length);
            $this->renderPartial('_downloadFile', array('data' => $data));
        } else {
            throw new CHttpException(404, 'Voicemail not found!');
        }
    }

    public function actionPhonebook()
    {
        $this->proccessXMLApps('phonebook');
    }

    public function actionConfig()
    {
        $this->proccessXMLApps('config');
    }

    protected function proccessXMLApps($appName)
    {
        $mac = Yii::app()->request->getParam("mac");
        if ($mac != "") {
            require_once $this->getModule()->getBasePath() . '/lib/phoneprovisioning.php';
            //this is a phone, so check which controller has to be called to route this stuff  
            $ua = Yii::app()->request->getUserAgent();
            $controller = $this->getXmlController($appName, $mac, $ua);
            if ($controller != NULL) {
                $controller->run($this);
            }
        } else if (Yii::app()->user->isGuest) {
            throw new CHttpException(403, 'not allowed to request settings.');
        } else {
            $this->actionIndex();
        }
    }

    protected function getXmlController($appName, $mac, $ua)
    {
        $controller = NULL;
        if ($appName == 'login') {
            $controller = VirtualPhoneProvisioningController::getXmlLoginAppInstanceForPhone($mac, $ua);
        } else if ($appName == 'voicemail') {
            $mac = rtrim($mac, '.xml');
            $controller = VirtualPhoneProvisioningController::getXmlAppVoicemailInstanceForPhoneModel($mac, $ua);
        } else if ($appName == 'phonebook') {
            $controller = VirtualPhoneProvisioningController::getXmlAppPhonebookInstanceForPhoneModel($mac, $ua);
        } else if ($appName == 'config') {
            $controller = VirtualPhoneProvisioningController::getXmlAppPhoneConfigInstanceForPhoneModel($mac, $ua);
        }
        return $controller;
    }

    public function getNavBarNetworkInterfaceDropdown(&$defaultNetworkInterface)
    {
        $data = NetworkInterface::getListData();
        $items = array();
        foreach ($data as $ip => $name) {
            if ($defaultNetworkInterface == "") {
                $defaultNetworkInterface = $ip;
            }

            $items[] = array(
                "label" => $name,
                "url" => "#",
                "linkOptions" => array(
                    "class" => "networkInterfaceValue",
                    "data-value" => $ip,
                )
            );
        }

        $lData = array(
            "label" => array_shift($data),
            "linkOptions" => array(
                "data-translation-id" => "PROVISIONING_GENERAL_NAVBAR_SELECT_NETWORK_INTERFACE"
            ),
            "items" => $items
        );

        return $lData;
    }

    public function renderLastProvDateTime($data)
    {
        $dateTime = $data->last_prov_dateTime;
        $formatedDateTime = '';
        if ($dateTime) {
            $formatedDateTime = PhonalisaDate::userDateTime($dateTime, true);
        }
        return $formatedDateTime;
    }

    public function actionLangSettings()
    {
        if (isset($_REQUEST['type'])) {
            $this->getSnomLanguageFile($_REQUEST['type']);
        }
    }

    public function actionGetLanguage()
    {
        if (isset($_REQUEST['type']) && isset($_REQUEST['file'])) {
            $this->getSnomLanguageFile($_REQUEST['type'], true);
        }
    }

    protected function getSnomLanguageFile($languageType, $getLanguageFile = false)
    {
        if (Yii::app()->request->getParam("mac") != "") {
            require_once $this->getModule()->getBasePath() . '/lib/phoneprovisioning.php';
            //this is a phone, so check which controller has to be called to route this stuff
            $controller = VirtualPhoneProvisioningController::getInstanceForPhoneModel(Yii::app()->request->getParam("mac"), Yii::app()->request->getUserAgent());
            if ($controller != NULL) {
                if (!empty($languageType)) {
                    $controller->generateLanguageOutput(Yii::app()->request->getParam("mac"), $languageType, $getLanguageFile);
                }
            }
        } else if (Yii::app()->user->isGuest) {
            throw new CHttpException(403, 'not allowed to request settings.');
        } else {
            $this->actionIndex();
        }
    }

    public function actionDial()
    {
        if (!isIpInNetRange(cfg("CALL_INIT_FROM_NET"))) {
            throw new CHttpException(500, 'Wrong Network!');
        }
        Webdialer::dial();
    }

    public function getIPv4Url(PhonalisaRecord $data, $row)
    {
        $model = PhoneModelFactory::getPhoneModelOfType($data->type);
        if ($model) {
            $name = $model->getPhoneModelNameHumanReadable();

            if (startsWith($name, "Siemens OpenStage") == false) {
                $ip = "http://" . $data->ipv4_address;
            } else {
                $ip = "https://" . $data->ipv4_address;
            }
            return $this->renderPartial('_phoneWebGui', array('data' => $data, 'ip' => $ip), true);
        }
        return '';
    }

    public function actionGetBootFile()
    {
        $mac = @$_REQUEST['mac'];
        $this->render('bootFile', array('mac' => $mac));
    }

    public function getProvisioningProfileData()
    {
        $lData = array('' => __('GROUPS_ADVANCED_TAB_CHOOSE_PROVISIONING_PROFILE'));
        $listData = CHtml::listData(ProvisioningProfile::model()->find(array(), 'name'), 'id', 'name');
        return array_merge($lData, $listData);
    }

    public function parameterProfilesAllowed($phone)
    {
        if (PhonalisaLicenseManager::provisioningProfileMax() !== 0 && $this->extraFieldsAllowed($phone)) {
            return true;
        }
        return false;
    }

    public function extraFieldsAllowed($phone)
    {
        $supportedPhonesModels = Gigaset::getSupportedPhoneModels();
        if (isset($supportedPhonesModels[$phone->type]) && strpos($phone->mac_addr, '-') === false) {
            return true;
        }
        return false;
    }

    public function getPhonebookData()
    {
        $models = Addressbook::model()->findAll();
        $lData = array('' => __('---'));

        foreach ($models as $model) {
            $lData[AddressbookType::getAddressbookType($model->type)][$model->id] = $model->title;
        }
        return $lData;
    }
}
