<?php
/**
 * IMPORTANT NOTE
 * The code of this system is closed and a private proprietary of Flex Solutions.
 * A written authorization/license from Flex Solutions is required before using or modifying this code.
 * Email: sales@flexsolution.biz, Phone: +962795342585, Website: http://www.flexsolutions.biz
 */
 
/**
 * This is the model class for table "document".
 *
 * The followings are the available columns in table 'document':
 * @property integer $id
 * @property integer $tid_id
 * @property string $date
 * @property string $file_type
 * @property double $file_size
 * @property integer $created_by
 * @property string $created_date
 *
 * The followings are the available model relations:
 * @property Tid $tid
 *
 * @author Amaney
 * @package application.models
 */
class Document extends TidansActiveRecord {

    /**
     * @return string the associated database table name
     */
    public function tableName() {
	return 'document';
    }

    /**
     * @return array validation rules for model attributes.
     */
    public function rules() {
	// NOTE: you should only define rules for those attributes that
	// will receive user inputs.
	return array(
	    array('tid_id', 'required'),
	    array('tid_id, created_by', 'numerical', 'integerOnly' => true),
	    array('file_size', 'numerical'),
	    array('file_type', 'length', 'max' => 45),
	    array('date, created_date', 'safe'),
	    array('file_size', 'validateSize'),
	    array('file_type', 'fileValidate'),
	    // The following rule is used by search().
	    // @todo Please remove those attributes that should not be searched.
	    array('id, tid_id, date, file_type, file_size, created_by, created_date', 'safe', 'on' => 'search'),
	);
    }

    /**
     * @return array relational rules.
     */
    public function relations() {
	// NOTE: you may need to adjust the relation name and the related
	// class name for the relations automatically generated below.
	return array(
	    'tid' => array(self::BELONGS_TO, 'Tid', 'tid_id'),
	);
    }

    /**
     * @return array customized attribute labels (name=>label)
     */
    public function attributeLabels() {
	return array(
	    'id' => 'ID',
	    'tid_id' => 'Tid',
	    'name' => 'Name',
	    'date' => 'Date',
	    'file_type' => 'File Type',
	    'file_size' => 'File Size',
	    'created_by' => 'Created By',
	    'created_date' => 'Created Date',
	);
    }

    /**
     * Retrieves a list of models based on the current search/filter conditions.
     *
     * Typical usecase:
     * - Initialize the model fields with values from filter form.
     * - Execute this method to get CActiveDataProvider instance which will filter
     * models according to data in model fields.
     * - Pass data provider to CGridView, CListView or any similar widget.
     *
     * @return CActiveDataProvider the data provider that can return the models
     * based on the search/filter conditions.
     */
    public function search() {
	// @todo Please modify the following code to remove attributes that should not be searched.

	$criteria = new CDbCriteria;

	$criteria->compare('id', $this->id);
	$criteria->compare('tid_id', $this->tid_id);
	$criteria->compare('date', $this->date, true);
	$criteria->compare('file_type', $this->file_type, true);
	$criteria->compare('file_size', $this->file_size);
	$criteria->compare('created_by', $this->created_by);
	$criteria->compare('created_date', $this->created_date, true);

	return new CActiveDataProvider($this, array(
	    'criteria' => $criteria,
	));
    }

    /**
     * Returns the static model of the specified AR class.
     * Please note that you should have this exact method in all your CActiveRecord descendants!
     * @param string $className active record class name.
     * @return Document the static model class
     */
    public static function model($className=__CLASS__) {
	return parent::model($className);
    }

    /**
     * The Following function is responsible for return array of documents models
     * @param integer $model_id id of the tid model
     * @return Document[] array of Document model .
     */
    public static function getModelDocuments($model_id) {
	$documents = Document::model()->findAllByAttributes(array('tid_id' => $model_id));
	if ($documents != null)
	    return $documents;
	return array();
    }

    /**
     * The Following function is responsible for return array of data of the $documents of the model
     * @param Document[] $documents array of Document model of the model
     * @return array array of Document data.
     */
    public static function getModelDocumentData($documents) {
	$dataArray = array();
	if ($documents != null) {
	    foreach ($documents as $value) {
		if ($value != null) {
		    $columns = array();
		    $columns['id'] = $value->id;
		    $columns['name'] = $value->name;
		    $columns['date'] = $value->date;
		    $columns['path'] = '';
		    $columns['file_type'] = '';
		    $columns['file_size'] = '';

		    $dataArray[] = $columns;
		}
	    }
	}
	return $dataArray;
    }

    /**
     * The Following function is responsible for saving documents models
     * @param Object $model the model that documents are related to
     * @param Object $transaction the transaction that is opened if exist
     * @return true if all documents models are saved successfully, false otherwise.
     */
    public static function saveModelDocuments($model, $transaction = null) {
	//-------------------------------------------

	$document_transaction = ($transaction == null) ? Yii::app()->db->beginTransaction() : $transaction;
	$documents = null;
	$document_model_not_saved = null;
	$document_array = null;
	$saving_is_successful = true;

	if ($model->document_array != null && $model->document_array != "") {
	    $array = json_decode($model->document_array);
	    foreach ($array as $value) {
		if ($value != null) {
		    $columns = array();
		    $columns['id'] = $value->id;
		    $columns['date'] = $value->date;
		    $columns['name'] = $value->name;
		    $columns['path'] = $value->path;
		    $columns['file_type'] = $value->file_type;
		    $columns['file_size'] = $value->file_size;

		    $document_array[] = $columns;
		}
	    }
	}

	if ($document_array != null) {
	    //delete old document if not exists
	    if (!$model->isNewRecord) {
		$documents = Document::getModelDocuments($model->id);
		if ($documents != null) {
		    $doc_ids = array();
		    foreach ($documents as $document) {
			if (!Document::isInDocumentsArray($document_array, $document, $doc_ids[])) {
			    if (!$document->delete()) {
				$saving_is_successful = false;
				$document_model_not_saved = $document;
				break;
			    }
			}
		    }
		    foreach ($doc_ids as $doc_id) {
			if ($doc_id != -1)
			    unset($document_array[$doc_id]);
		    }
		}
	    }
	    if ($saving_is_successful) {

		foreach ($document_array as $document) {
		    if (isset($document) && $document != '' && $document != ' ') {
			$document_model = new Document();
			$doc_name = '';
			$doc_name = substr($document["name"], 0, strrpos($document["name"], "-")) . substr($document["name"], strrpos($document["name"], "."), strlen($document["name"]));

			$document_model->name = $doc_name; //$document['name'];
			$document_model->date = date("Y-m-d");
			$document_model->tid_id = $model->id;
			$document_model->created_by = Yii::app()->user->id;
			$document_model->created_date = date("Y-m-d");
			$document_model->file_type = $document['file_type'];
			$document_model->file_size = $document['file_size'];

			if ($document_model->save()) {
			    $saving_is_successful = true;
			    $target_folder_path = Setting::getDocumentsPath();
			    $slash = ( substr($target_folder_path, -1) == "\\") ? "" : "\\";
			    $target_folder = $target_folder_path . $slash;
			    $newfilename = $document_model->getDocumentName();
			    if (file_exists(Yii::app()->basePath . '\\temp\\' . $document['name'])) {
				copy(Yii::app()->basePath . '\\temp\\' . $document['name'], $target_folder . $newfilename);
				unlink(Yii::app()->basePath . '\\temp\\' . $document['name']);
			    }
			} else {
			    $saving_is_successful = false;
			    $document_model_not_saved = $document_model;
			    break;
			}
		    }
		}
	    }
	} else {
	    if ($model->document_array != "" && $model->document_array != null)
		if (!$model->isNewRecord) {
		    $documents = Document::getModelDocuments($model->id);
		    if ($documents != null) {
			foreach ($documents as $document) {
			    if (!$document->delete()) {
				$saving_is_successful = false;
				$document_model_not_saved = $document;
				break;
			    }
			}
		    }
		}
	}
	if ($saving_is_successful) {
	    if ($document_array != null)
		foreach ($document_array as $document)
		    if (file_exists($document['path']))
			unlink($document['path']);
	    $folder_temp = Yii::app()->basePath . "/temp/";
	    $handle = opendir($folder_temp);
	    while (false !== ($entry = readdir($handle))) {
		if (!is_dir($entry)) {
		    $file_date = date("Y-m-d", filectime($folder_temp . $entry));
		    $Now_minus_four = date("Y-m-d", strtotime(date("Y-m-d", strtotime(date("Y-m-d"))) . " -4 day"));

		    if ($file_date <= $Now_minus_four)
			unlink($folder_temp . $entry);
		}
	    }
	    if ($transaction == null)
		$document_transaction->commit();
	    return "";
	} else {
	    if ($transaction == null)
		$document_transaction->rollback();
	    return CHtml::errorSummary($document_model_not_saved);
	}
    }

    /**
     * The Following function is responsible for checking if document is in array of documents
     * @param Document[] $document_array array of documents
     * @param Document $document the document to check
     * @return true if document model is in  array of documents , false otherwise
     */
    public static function isInDocumentsArray($document_array, $document, &$model_index) {
	for ($index = 0; $index < count($document_array); $index++)
	    if ($document->id == $document_array[$index]['id']) {
		$model_index = $index;
		return true;
	    }
	return false;
    }

    protected function beforeValidate() {
	return true;
    }

    /**
     * The Following function is responsible for getting the name of the stored document
     * @return String the name of the stored document
     */
    public function getDocumentName() {
	return $this->tid_id . "-" . $this->id . "-" . $this->name;
    }

    protected function afterDelete() {
	$path = $this->getDocumentPath();
	if (file_exists($path))
	    unlink($path);
	return parent::afterDelete();
    }

    /**
     * The Following function is responsible for getting the path with the name of the stored document
     * @return String the path with the name of the stored document
     */
    public function getDocumentPath() {
	$document_path = Setting::getDocumentsPath();
	if (isset($document_path) && $document_path != '') {

	    return $document_path . $this->getDocumentName();
	}
	return '';
    }

    /**
     * The Following function is responsible for checking that the size of all tid documents don't exceed the max_document_size from the Setting
     */
    public function validateSize($attribute, $params) {
	$document_size = Setting::getDocumentSizeLimit();
	if ($document_size != null && $document_size != '') {
	    $criteria = new CDbCriteria();
	    $criteria->select = 'sum(file_size) as total_file_size';
	    $criteria->condition = 'tid_id = ' . $this->tid_id;

	    $model = new Document();
	    $result = $model->commandBuilder->createFindCommand(
			    $model->tableName(), $criteria)->queryAll();

	    if ($result[0]['total_file_size'] + $this->file_size > $document_size * 1024 * 1024)
		$this->addError('file_size', 'Documents size can not exceed max document size specified in the setting');
	}
    }

    /**
     * Check if the folder of Documents and expired documents folders exist or not
     */
    public function fileValidate($attribute, $params) {
	$target_folder_path = Setting::getDocumentsPath();

	if (!is_dir($target_folder_path)) {
	    $this->addError('file', yii::t("default", 'The Documents Path has not been configured correctly in the system settings, please contact the system admin to solve this issue.'));
	}
    }

    /**
     * Creates a compressed zip file
     *
     * @param string $files an array of files
     * @param string $zip_name the name of the destination file
     *
     * @return boolean true if the file was created, false if the process runs into any problems.
     */
    public static function create_zip($files = array(), $zip_name = 'documents_zip.zip') {
//vars
	$valid_files = array();
//if files were passed in...
	if (is_array($files)) {
//cycle through each file
	    foreach ($files as $file) {
//make sure the file exists
		if (file_exists($file)) {
		    $valid_files[] = $file;
		}
	    }
	}

//if we have good files...
	if (count($valid_files)) {
//create the archive
	    $zip = new ZipArchive();
	    if ($zip->open($zip_name, ZIPARCHIVE::CREATE) !== TRUE) {
		$error .= "* Sorry ZIP creation failed at this time";
	    }
//add the files
	    foreach ($valid_files as $file) {
//this is a directory not a file
		if (is_dir($file)) {
//extract the name of the internal folder
		    $folder_name_arr = explode('\\', $file);
		    $index = count($folder_name_arr) - 1;
		    if ($folder_name_arr[$index] == '')
			$index = count($folder_name_arr) - 2;
		    $folder_name = $folder_name_arr[$index];
		    Document::addFolderToZip($file, $zip, $folder_name);
		}
		else
//add file to zip simply
		    $zip->addFile($file, pathinfo($file, PATHINFO_BASENAME));
	    }


//close the zip -- done!
	    $zip->close();

//check to make sure the file exists
// File Exists?
	    if (file_exists($zip_name)) {
//debug
		echo "numfiles: " . $zip->numFiles . "\n";
		echo "status:" . $zip->status . "\n";
		echo 'Zip File:' . $zip_name . "\n";
		return true;
	    }
	    return false;
	} else {
	    return false;
	}
    }

    /**
     *  Function to recursively add a directory, sub-directories and files to a zip archive
     *
     * @param string $dir the local path of the directory you want to put in zip
     * @param ZipArchive $zip_archive the zip archive file
     * @param string $zip_dir the name of the inner directory you want to put in zip
     *
     */
    public static function addFolderToZip($dir, $zip_archive, $zip_dir = 'inner_dir') {
	if (is_dir($dir)) {
	    if ($dh = opendir($dir)) {

		//Add the directory
		if (!empty($zip_dir)) {
		    $zip_archive->addEmptyDir($zip_dir);
		}

		// Loop through all the files
		while (($file = readdir($dh)) !== false) {

		    //If it's a folder, run the function again!
		    if (!is_file($dir . "/" . $file)) {
			// Skip parent and root directories
			if (($file !== ".") && ($file !== "..")) {
			    Document::addFolderToZip($dir . "/" . $file, $zip_archive, $zip_dir . "/" . $file);
			}
		    } else {
			// Add the files
			$zip_archive->addFile($dir . "/" . $file, $zip_dir . "/" . $file);
		    }
		}
	    }
	}
    }

}
