<?php

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

    public $fileType = 'audio/wav';

    /**
     * @var string if set, the FILEINFO_RAW is checked after that.
     */
    public $fileInfoRaw;

    /**
     * @var boolean whether the error message will show as flash or CHttpException.
     * Defaults to false, meaning the error message will show as CHttpException.
     */
    public $useFlashError = false;

    /**
     * Set the attribute and then validates using {@link validateFile}.
     * If there is any error, the error message is added to the object.
     * @param CModel $object the object being validated
     * @param string $attribute the attribute being validated
     */
    protected function validateAttribute($object, $attribute)
    {
        if (isset($_POST['ajax'])) {
            return;
        }
        if ($this->maxFiles > 1) {
            $files = $object->$attribute;
            if (!is_array($files) || !isset($files[0]) || !$files[0] instanceof CUploadedFile) {
                $files = CUploadedFile::getInstances($object, $attribute);
            }
            if (array() === $files) {
                $this->emptyAttribute($object, $attribute);
                return;
            }
            if (count($files) > $this->maxFiles) {
                $message = $this->tooMany !== null ? $this->tooMany : Yii::t('yii', '{attribute} cannot accept more than {limit} files.');
                $this->addError($object, $attribute, $message, array('{attribute}' => $attribute, '{limit}' => $this->maxFiles));
            } else {
                foreach ($files as $file) {
                    $this->validateFile($object, $attribute, $file);
                }
            }
        } else {
            $file = $object->$attribute;
            if (!$file instanceof CUploadedFile) {
                $file = CUploadedFile::getInstanceByName(get_class($object) . "[$attribute]");
                if (null === $file || ($error = $file->getError()) == UPLOAD_ERR_NO_FILE) {
                    $this->emptyAttribute($object, $attribute);
                    return;
                }
                if ($file->hasError) {
                    $errorMessage = $this->fileUploadErrorMessage($file);
                    if ($this->useFlashError == true) {
                        $this->addError($object, $attribute, $errorMessage, array('{file}' => $file->getName(), '{mimeTypes}' => $this->mimeTypes));
                    } else {
                        throw new CHttpException(500, $errorMessage);
                    }
                    return;
                }
                if (!empty($this->fileInfoRaw)) {
                    $this->validateFileInfoRaw($object, $attribute, $file);
                }
            }
            $this->validateFile($object, $attribute, $file);
        }
    }

    /**
     * Internally validates a file object.
     * @param CModel $object the object being validated
     * @param string $attribute the attribute being validated
     * @param CUploadedFile $file uploaded file passed to check against a set of rules
     */
    protected function validateFileInfoRaw($object, $attribute, $file)
    {
        $finfo = new finfo(FILEINFO_RAW);

        if (isset($finfo)) {
            $receivedFileInfo = $finfo->file($file->tempName);
            $exceptedFileInfo = $this->fileInfoRaw;
            if ($receivedFileInfo != $exceptedFileInfo) {
                if ($this->useFlashError == true) {
                    $message = __('GLOBAL_FILE_UPLOAD_WRONG_MIME_TYPE_ERROR_MESSAGE');
                    $this->addError($object, $attribute, $message, array('{file}' => $file->getName(), '{mimeTypes}' => $this->mimeTypes));
                } else {
                    throw new CHttpException(500, __('FILE_VALIDATOR_EXCEPTED_FILE_INFO') . ":\n'$exceptedFileInfo'.\n" . __('FILE_VALIDATOR_RECEIVED_FILE_INFO') . ":\n'$receivedFileInfo'.");
                }
            }
        }
    }

    /**
     * Returns a error message for an upload error.
     * @param CUploadedFile $file uploaded file, which has an error
     * @return string errror message
     */
    protected function fileUploadErrorMessage($file)
    {
        $errorMessage = '';

        switch ($file->error) {
            case UPLOAD_ERR_FORM_SIZE:
            case UPLOAD_ERR_INI_SIZE:
            case $this->maxSize !== null && $file->getSize() > $this->maxSize:
                $errorMessage = $this->tooLarge !== null ? $this->tooLarge : Yii::t('yii', 'The file "{file}" is too large. Its size cannot exceed {limit} bytes.');
                break;
            case UPLOAD_ERR_PARTIAL:
                $errorMessage = Yii::t('yii', 'The file "{file}" was only partially uploaded.');
                break;
            case UPLOAD_ERR_NO_TMP_DIR:
                $errorMessage = Yii::t('yii', 'Missing the temporary folder to store the uploaded file "{file}".');
                break;
            case UPLOAD_ERR_CANT_WRITE:
                $errorMessage = Yii::t('yii', 'Failed to write the uploaded file "{file}" to disk.');
                break;
            case UPLOAD_ERR_EXTENSION:
                $errorMessage = Yii::t('yii', 'File upload was stopped by extension.');
                break;
            default:
                $errorMessage = "";
                break;
        }

        $errorMessage = strtr(
                $errorMessage, array('{file}' => $file->getName(), '{limit}' => $this->getSizeLimit())
        );
        return $errorMessage;
    }

    public function clientValidateAttribute($object, $attribute)
    {
        $inputId = '#' . get_class($object) . "_" . $attribute;
        $message = $this->message;
        $mimeTypes = $this->mimeTypes;

        if (is_array($mimeTypes)) {
            $formatedMimeTypes = '';
            foreach ($mimeTypes as $mimeType) {
                $formatedMimeTypes.= $mimeType . ',';
            }
            $mimeTypes = $formatedMimeTypes;
        }
        $mimeTypeString = rtrim(str_replace(' ', '', $mimeTypes), ',');

        return "
            if ($('$inputId').val()) {
                var mimeTypesAsString = '$mimeTypeString';
                var mimeTypes = mimeTypesAsString.split(',');
                if ($.inArray($('$inputId')[0].files[0].type, mimeTypes) === -1) {
                    $('$inputId').val('');
                    messages.push(" . CJSON::encode($message) . ");
                }
            }
            ";
    }
}
