<?php

/**
 * Phonalisa REST API Controller
 *
 * PHP version 5
 *
 * @category Phonalisa REST API
 * @package  Phonalisa
 * @author   Sebastian Kauder <sebastian.kauder@aerea.de>
 * @license  Phonalisa Europe GmbH Closed Source Software License
 * @link     http://www.phonalisa.de
 */
class DefaultController extends Controller
{

    protected $isAlarmList = false;
    protected $apiVersion = '1.0.3';
    protected $phonalisaIsOK = true;
    protected $alarmType;

    /**
     * @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';

    /**
     * @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 authenticated user to perform 'create' and 'update' actions
                'actions' => array('index'),
                'users' => array('*'),
            ),
        );
    }

    public function actionIndex()
    {
        $explodedResponse = $this->explodeResponse();
        $alarmType = $this->getAlarmType($explodedResponse);
        $this->setAlarmType($alarmType);
        $this->processIncommingData();
    }

    protected function explodeResponse()
    {
        return explode('/', $_REQUEST['r']);
    }

    protected function getAlarmType($explodedResponse)
    {
        $lastValue = array_pop($explodedResponse);
        if ($lastValue == 'batch') {
            $this->setIsAlarmList(true);
            $lastValue = array_pop($explodedResponse);
        }
        return $lastValue;
    }

    protected function setIsAlarmList($state)
    {
        $this->isAlarmList = $state;
    }

    protected function processIncommingData()
    {
        if ($this->alarmType == 'versionnumber') {
            $this->sendVersionNumber();
        } else if ($this->alarmType == 'heartbeat') {
            $this->sendHeartBeat();
        } else if ($this->alarmType == 'alarmresponse') {
            $this->processAlarmResponse();
        } else if ($this->alarmType == 'uploadaudio') {
            $this->saveAudioFileInPhonalisa();
        } else {
            $this->processIncommingAlarms();
        }
    }

    protected function sendVersionNumber()
    {
        $data = $this->getVersionNumber();
        return $this->sendResponse($data);
    }

    protected function getVersionNumber()
    {
        return $this->apiVersion;
    }

    protected function sendResponse($data)
    {
        header('Content-type: application/json');
        echo CJSON::encode($data);

        foreach (Yii::app()->log->routes as $route) {
            if ($route instanceof CWebLogRoute) {
                $route->enabled = false; // disable any weblogroutes
            }
        }
        Yii::app()->end();
    }

    protected function sendHeartBeat()
    {
        return $this->sendPhonalisaIsOK();
    }

    protected function sendPhonalisaIsOK()
    {
        $this->setPhonalisaIsOK(true);
        $this->sendPhonalisaStateMessage();
    }

    protected function setPhonalisaIsOK($value)
    {
        $this->phonalisaIsOK = $value;
    }

    protected function sendPhonalisaStateMessage($errorMsg = "", $errorSource = "", $errorID = "")
    {
        $data = array(
            'PhonalisaIsOK' => $this->phonalisaIsOK,
            'ErrorID' => $errorID, //FIXME
            'ErrorMessage' => $errorMsg,
            'ErrorSource' => $errorSource
        );

        return $this->sendResponse($data);
    }

    protected function sendPhonalisaErrorMessage($errorMsg = "", $errorSource = "", $errorID = "")
    {
        $this->setPhonalisaIsOK(false);
        $this->sendPhonalisaStateMessage($errorMsg, $errorSource, $errorID);
    }

    protected function saveAudioFileInPhonalisa()
    {
        $model = new AudioFile();
        if (isset($_FILES['uploadaudio'])) {
            $model->attributes = $_FILES['uploadaudio'];
            $model->scenario = 'create';
            $model->type = AudioFileType::alarmType;
            $model->save();
            $file = $_FILES['uploadaudio'];
            $model->data = new CUploadedFile($file['name'], $file["tmp_name"], $file["type"], $file["size"], $file["error"]);
            $model->save();
            $this->validateIncomingData($model);
            $this->sendErrorIfModelNotSave($model);
            $this->sendResponse($model->id);
        }
    }

    protected function processIncommingAlarms()
    {
        $data = file_get_contents('php://input');
        $input = json_decode($data, true);
        $inputDataIsJson = $this->checkIfInputDataIsJson($input);

        if ($inputDataIsJson == true) {
            $this->processInputDataToModel($input);
        } else {
            $this->sendPhonalisaErrorMessage("Incomming data are not in Json-Format!", "Incomming data");
        }
    }

    protected function checkIfInputDataIsJson($input)
    {
        if (!is_array($input)) {
            return false;
        }
        return true;
    }

    protected function setAlarmType($alarmType)
    {
        if (isset($alarmType) && !empty($alarmType)) {
            $this->alarmType = $alarmType;
        } else {
            $this->sendPhonalisaErrorMessage("No Alarmtype is set!", "Incomming data");
        }
    }

    protected function processInputDataToModel($input)
    {
        if ($this->isAlarmList == true) {
            $this->sendErrorMessageIfRequiredAttributeHasError(@$input['AlarmListID'], 'AlarmListID');
            $this->sendErrorMessageIfRequiredAttributeHasError(@$input['Alarms'], 'Alarms');
            $this->processAlarmListDataToModel($input);
            $this->saveAlarmListDataToModel($input);
        } else {
            $model = $this->processSingleAlarmDataToModel($input);
            $this->sendErrorIfModelNotSave($model);
        }
        $this->sendPhonalisaIsOK();
    }

    protected function sendErrorMessageIfRequiredAttributeHasError($input, $attribute = "")
    {
        if (isset($input)) {
            $this->sendErrorMessageIfAttributeIsEmpty($input, $attribute);
        } else {
            $this->sendPhonalisaErrorMessage("$attribute is not set!", "Incomming data");
        }
    }

    protected function sendErrorMessageIfAttributeIsEmpty($input, $attribute = "")
    {
        if (empty($input)) {
            $this->sendPhonalisaErrorMessage("$attribute is empty!", "Incomming data");
        }
    }

    protected function processAlarmListDataToModel($input, $saveData = false)
    {
        $alarmListID = $input['AlarmListID'];

        foreach ($input['Alarms'] as $alarms) {
            $alarms['AlarmListID'] = $alarmListID;
            $model = $this->processSingleAlarmDataToModel($alarms);
            if ($saveData == true) {
                $this->sendErrorIfModelNotSave($model);
            }
        }
    }

    protected function processSingleAlarmDataToModel($input)
    {
        $model = new Alarm();
        foreach ($input as $key => $value) {
            $this->setInputDataToModelAttributes($model, $key, $value);
        }
        $model->scenario = $this->alarmType;
        $model->alarmType = $this->alarmType;
        $model->alarmTimeStamp = $this->getAlarmTimeStamp();
        $this->checkIfRecordingIdIsRequired($model);
        $this->validateIncomingData($model);
        return $model;
    }

    protected function checkIfRecordingIdIsRequired($model)
    {
        if (strtoupper($model->callType) == 'VOICERECORDING') {
            $model->scenario = strtolower($model->callType);
        }
    }

    protected function setInputDataToModelAttributes($model, $key, $value)
    {
        $this->sendErrorIfKeyNotExists($model, $key);
        $modelKey = $this->setFirstKeyLetterToLower($key);
        $model->$modelKey = $value;
    }

    protected function sendErrorIfKeyNotExists($model, $key)
    {
        $modelKey = $this->setFirstKeyLetterToLower($key);
        if (!array_key_exists($modelKey, $model->attributes)) {
            $this->sendPhonalisaErrorMessage(
                    "$key is not implemented!", "Incomming alarm with RequestID $model->requestID"
            );
        }
    }

    protected function setFirstKeyLetterToLower($key)
    {
        return lcfirst($key);
    }

    protected function getAlarmTimeStamp()
    {
        return date("c", PhonalisaDate::newServerTimestamp());
    }

    protected function validateIncomingData($model)
    {
        $model->validate();
        $this->checkIfValidationFailed($model);
    }

    protected function checkIfValidationFailed($model)
    {
        if ($model->errors) {
            $this->sendErrorMessageIfValidationFailed($model);
        }
    }

    protected function sendErrorMessageIfValidationFailed($model)
    {
        $errors = $model->errors;
        foreach ($errors as $error) {
            if ($this->alarmType != 'uploadaudio') {
                $this->sendErrorMessageIfAttributeIsEmpty($model->requestID, 'RequestID');
                $errorSource = "Incomming alarm with RequestID $model->requestID";
            } else {
                $errorSource = 'Incomming AudioUpload';
            }
            $this->sendPhonalisaErrorMessage($error[0], $errorSource);
        }
    }

    protected function saveAlarmListDataToModel($input)
    {
        $this->processAlarmListDataToModel($input, true);
    }

    protected function sendErrorIfModelNotSave($model)
    {
        if (!$model->save()) {
            $this->sendErrorMessageIfValidationFailed($model);
        }
    }

    protected function processAlarmResponse()
    {
        if ($this->isAlarmList == true) {
            $this->sendErrorMessageIfRequiredAttributeHasError(@$_REQUEST['batchid'], 'BatchID');
            $model = $this->getFoundAlarmModels(array('alarmListID' => $_REQUEST['batchid']));
            $data = $this->getAlarmResponseDataForAlarmListRequest($model);
        } else {
            $this->sendErrorMessageIfRequiredAttributeHasError(@$_REQUEST['requestid'], 'RequestID');
            $model = $this->getFoundAlarmModels(array('requestID' => $_REQUEST['requestid']));
            $data = $this->getAlarmResponseDataForSingleAlarmRequest($model);
        }
        $this->sendResponse($data);
    }

    protected function getFoundAlarmModels($searchArray)
    {
        $model = Alarm::model()->findAllByAttributes($searchArray);

        if (!$model) {
            $this->sendPhonalisaErrorMessage("No alarm found!", "Incomming data");
        }
        return $model;
    }

    protected function getAlarmResponseDataForAlarmListRequest($models)
    {
        $data = array(
            'AlarmListID' => $models[0]->alarmListID,
            'Alarms' => array()
        );

        foreach ($models as $key => $model) {
            $data['Alarms'][$key] = $this->getAlarmResponseData($model);
        }
        return $data;
    }

    protected function getAlarmResponseData($model)
    {
        return array(
            'RequestID' => $model->requestID,
            'AlarmTimeStamp' => $model->alarmTimeStamp,
            'ResponseTimeStamp' => $model->responseTimeStamp,
            'Response' => $model->response,
        );
    }

    protected function getAlarmResponseDataForSingleAlarmRequest($models)
    {
        foreach ($models as $key => $model) {
            $data[$key] = $this->getAlarmResponseData($model);
        }
        return $data;
    }
}
