<?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 "BackupDataBase".
 *
 *
 * @version 0.1
 * @author Safaa
 * @package application.models
 */
class BackupDataBase {

    /**
     * @var array Array of tables names
     */
    public $tables = array();
    /**
     * @var File The text file we create it for puting the backup result in
     */
    public $fp;
    /**
     * @var String The name of the backup file 
     */
    public $file_name;
    /**
     * @var String The full path of the backup file
     */
    public $path = null;
    /**
     * @var String The temporary name of the backup file
     */
    public $back_temp_file = 'db_backup_';

    /**
     * Get the columns of the given table
     *
     * @param string $table_name name of the table
     *
     * @return columns of given table
     */
    public function getColumns($table_name) {
	$sql = 'SHOW CREATE TABLE ' . $table_name;
	$cmd = Yii::app()->db->createCommand($sql);
	$table = $cmd->queryRow();
	$create_query = $table['Create Table'] . ';';

	$create_query = preg_replace('/^CREATE TABLE/', 'CREATE TABLE IF NOT EXISTS', $create_query);
	//$create_query = preg_replace('/AUTO_INCREMENT\s*=\s*([0-9])+/', '', $create_query);
	if ($this->fp) {
	    $this->writeComment('TABLE ' . addslashes($table_name));
	    $final = 'DROP TABLE IF EXISTS ' . addslashes($table_name) . ';' . PHP_EOL . $create_query . PHP_EOL . PHP_EOL;
	    fwrite($this->fp, $final);
	} else {
	    $this->tables[$table_name]['create'] = $create_query;
	    return $create_query;
	}
    }

    /**
     * Get the Data that locates in the given table between two dates
     *
     * @param string $table_name name of the table
     * @param datetime $from_date the date we start getting the data at
     * @param datetime $to_date  the date we end getting the data at
     *
     * @return columns of given table
     */
    public function getData($table_name, $from_date=null, $to_date=null) {

	$sql = 'SELECT * FROM ' . $table_name;

	$cmd = Yii::app()->db->createCommand($sql);
	$dataReader = $cmd->query();

	$data_string = '';


	$values = "";
	$data = "";
	$row_number = 1;
	$rows = array();
	foreach ($dataReader as $data) {
	    $itemNames = array_keys($data);
	    $itemNames = array_map("addslashes", $itemNames);
	    $items = join('`,`', $itemNames);
	    $itemValues = array_values($data);
	    $itemValues = array_map("addslashes", $itemValues);
	    $valueString = join("','", $itemValues);

	    $valueString = str_replace("''", 'NULL', $valueString);
	    $valueString = "('" . $valueString . "'),";
	    $values = $values . "\n" . $valueString;
	    if ($row_number % 600 == 0) {
		if ($values != "") {
		    $data_string = "INSERT INTO `$table_name` (`$items`) VALUES" . rtrim($values, ",") . ";" . PHP_EOL;
		    array_push($rows, $data_string);
		    $data_string = '';
		    $values = "";
		}
	    }
	    $row_number++;
	}
	if ($values != "") {
	    $data_string = "INSERT INTO `$table_name` (`$items`) VALUES" . rtrim($values, ",") . ";" . PHP_EOL;
	    array_push($rows, $data_string);
	}

	if (count($rows) == 0)
	    return null;

	if ($this->fp) {
	    $this->writeComment('TABLE DATA ' . $table_name);
	    foreach ($rows as $row_data) {
		$final = $row_data . PHP_EOL . PHP_EOL . PHP_EOL;
		fwrite($this->fp, $final);
	    }
	} else {
	    $this->tables[$table_name]['data'] = $data_string;
	    return $data_string;
	}
    }

    /**
     * Get the tables of the given database
     *
     * @param string $db_name name of the database
     *
     * @return tables of given database
     */
    public function getTables($db_name = null) {
	$sql = 'SHOW TABLES';
	$cmd = Yii::app()->db->createCommand($sql);
	$tables = $cmd->queryColumn();
	return $tables;
    }

    /**
     * Start the backup operation and write logs
     *
     * @param boolean $add_check 
     * @param string $type type of the backup (daily , weekly or full)
     *
     * @return boolean tells if the backup starts successfully or not
     */
    public function StartBackup($add_check = true, $type='') {
//        $this->file_name = $this->path . $this->back_temp_file . date('Y.m.d_H.i.s') . $type . '.sql';
	$this->file_name = $this->path . date('Y.m.d_H.i.s') . $type . '.sql';

	$this->fp = fopen($this->file_name, 'w+');

	if ($this->fp == null)
	    return false;
	fwrite($this->fp, '-- -------------------------------------------' . PHP_EOL);
	if ($add_check) {
	    fwrite($this->fp, 'SET AUTOCOMMIT=0;' . PHP_EOL);
	    fwrite($this->fp, 'START TRANSACTION;' . PHP_EOL);
	    fwrite($this->fp, 'SET SQL_QUOTE_SHOW_CREATE = 1;' . PHP_EOL);
	}
	fwrite($this->fp, 'SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;' . PHP_EOL);
	fwrite($this->fp, 'SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;' . PHP_EOL);
	fwrite($this->fp, '-- -------------------------------------------' . PHP_EOL);
	$this->writeComment('START BACKUP');
	return true;
    }

    /**
     * End the backup operation and write logs
     *
     * @param boolean $add_check 
     *
     * @return boolean tells if the backup ends successfully or not
     */
    public function EndBackup($add_check = true) {
	fwrite($this->fp, '-- -------------------------------------------' . PHP_EOL);
	fwrite($this->fp, 'SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;' . PHP_EOL);
	fwrite($this->fp, 'SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;' . PHP_EOL);

	if ($add_check) {
	    fwrite($this->fp, 'COMMIT;' . PHP_EOL);
	}
	fwrite($this->fp, '-- -------------------------------------------' . PHP_EOL);
	$this->writeComment('END BACKUP');
	fclose($this->fp);
	$this->fp = null;
    }

    /**
     * writes comments  in the output backup file during the backup operation
     *
     * @param string $string the comment we want to write in the file
     *
     */
    public function writeComment($string) {
	fwrite($this->fp, '-- -------------------------------------------' . PHP_EOL);
	fwrite($this->fp, '-- ' . $string . PHP_EOL);
	fwrite($this->fp, '-- -------------------------------------------' . PHP_EOL);
    }

    /**
     * This function performs the full backup onthe database of the application
     *
     * @param boolean $conatin_structure tells if we want to get the structure of the database within the backup file
     * @param boolean $conatin_data tells if we want to get the data of the database within the backup file
     *
     */
    public function fullBackup($conatin_structure=false, $conatin_data=false) {
	$tables = $this->getTables();

	if ($this->StartBackup(true, '__FullBackup')) {
	    if ($conatin_structure) {
		foreach ($tables as $table_name) {
		    if (substr($table_name, 0, 2) != "v_")
			$this->getColumns($table_name);
		}
	    }
	    if ($conatin_data) {
		foreach ($tables as $table_name) {
		    if (substr($table_name, 0, 2) != "v_")
			$this->getData($table_name);
		}
	    }
	    $this->EndBackup();
	}
    }

    /**
     * This function performs the partial backup onthe database of the application
     *
     * @param boolean $conatin_structure tells if we want to get the structure of the database within the backup file
     * @param boolean $conatin_data tells if we want to get the data of the database within the backup file
     * @param datetime $from_date the date we start getting the data at
     * @param datetime $to_date  the date we end getting the data at
     *
     */
    public function partialBackup($conatin_structure=false, $conatin_data=false, $from_date=null, $to_date=null, $type='') {
	$tables = $this->getTables();
	if ($this->StartBackup(true, '_' . $type)) {

	    if ($conatin_structure) {
		foreach ($tables as $table_name) {
		    if ($table_name != 'document')
			if (substr($table_name, 0, 2) != "v_")
			    $this->getColumns($table_name);
		}
	    }
	    if ($conatin_data) {
		foreach ($tables as $table_name) {
		    if ($table_name != 'document')
			if (substr($table_name, 0, 2) != "v_")
			    $this->getData($table_name, $from_date, $to_date);
		}
	    }
	    $this->EndBackup();
	}
    }

}