<?php

/**
 * Upload class 
 *
 * this class contain the methods that deals with files and uploading 
 * 
 *
 * LICENSE: Open source
 *
 * @category   general
 * @package    core system
 * @subpackage parent
 * @copyright  coderg
 * @license    http://coderg.com
 * @version    .01
 * @link       http://coderg.com
 * @since      2018
 */
class Upload {

    // upload directory 
    private $uploadDirectory;
    //file types to be used 
    private $type;
    //file size limit 
    private $sizeLimit;
    //error 
    private $errors = array();
    //input name 
    private $inputName;
    //file name array
    private $fileName = array();
    //file size array 
    private $fileSize = array();
    //file error array
    private $fileError = array();
    //file type array
    private $fileType = array();
    //temperory file array
    private $fileTempName = array();
    //new file name array
    private $newFileName = array();
    //input flag array
    private $inputFlag = FALSE;
    //result to be returned from upload 
    private $result = array();
	
	private $required;

    /**
     *  constructor
     * 
     * set input name and configrations 
     * @param    $inputName (string) input field name 
     * @param    $config   (array)   array of the input configurations like direcotry/size limit/types 
     * @return   none 
     *
     */
    public function __construct($inputName,$required = TRUE) {
        global $uploadConfig;

        $this->uploadDirectory = $uploadConfig['upload_dir'];
        $this->setSizeLimit($uploadConfig['max_size']);
        $this->type = explode('|', $uploadConfig['types']);
		$this->required = $required;
        //take input array 
        $this->inputName = $_FILES[$inputName];
        //set file name 
        $this->setName();
        //set file size
        $this->setSize();
        //set temperory file name
        $this->setTempName();
        //set file type 
        $this->setType();
        //check if there is an input or not 
        $this->checkEmptyInput();
    }

    

    /**
     *  setName
     * 
     * set the file names into the fileName array 
     * @param    none 
     * @return   none      
     *
     */
    private function setName() {
        //set files names in an array of file name 
        if (is_array($this->inputName['name'])) {
            $this->fileName = $this->inputName['name'];
        } else {
            // at a single file name to the file name array
            $this->fileName[] = $this->inputName['name'];
        }
    }

    /**
     *  getName
     * 
     * get the fileName array 
     * @param    none 
     * @return   fileName (array)      
     *
     */
    private function getName() {
        return $this->fileName;
    }

    /**
     *  setSize
     * 
     * set the file size into the fileSize array 
     * @param    none 
     * @return   none      
     *
     */
    private function setSize() {
        //set files size in an array of file size 
        if (is_array($this->inputName['size'])) {
            $this->fileSize = $this->inputName['size'];
        } else {
            // add a single file size to the file size array
            $this->fileSize[] = $this->inputName['size'];
        }
    }

    /**
     *  setSize
     * 
     * get array of files size 
     * @param    none 
     * @return   fileSize (array)      
     *
     */
    private function getSize() {
        //return array of file size 
        return $this->fileSize;
    }

    /**
     *  setSize
     * 
     * get array of files size 
     * @param    none 
     * @return   fileSize (array)      
     *
     */
    private function setType() {
        //set files types in an array of file type 
        if (is_array($this->inputName['type'])) {
            $this->fileType = $this->inputName['type'];
        } else {
            // add a single file typ to the file type array
            $this->fileType[] = $this->inputName['type'];
        }
    }

    /**
     *  setSize
     * 
     * get array of files size 
     * @param    none 
     * @return   fileSize (array)      
     *
     */
    private function getType() {
        //return array of file type 
        return $this->fileType;
    }

    /**
     *  setTempName
     * 
     * set array of files temp name 
     * @param    none 
     * @return   none      
     *
     */
    private function setTempName() {
        if (is_array($this->inputName['tmp_name'])) {
            $this->fileTempName = $this->inputName['tmp_name'];
        } else {
            $this->fileTempName[] = $this->inputName['tmp_name'];
        }
    }

    /**
     *  getTempName
     * 
     * get array of files temp name 
     * @param    none 
     * @return   fileTempName (array)      
     *
     */
    private function getTempName() {
        return $this->fileTempName;
    }

    /**
     *  setSizeLimit
     * 
     * set file size limit in megabytes 
     * @param    none 
     * @return   fileTempName (array)      
     *
     */
    private function setSizeLimit($sizeInMega) {
        $sizeInByte = $sizeInMega * 1024 * 1024;
        $this->sizeLimit = $sizeInByte;
    }

    /**
     *  checkSize
     * 
     * check the file size  
     * @param    none 
     * @return   none      
     *
     */
    private function checkSize() {
        //loop through the file size array 
        foreach ($this->getSize() as $key => $value) {
            //if not the name exists in the error array 
            if (!array_key_exists($this->getName()[$key], $this->errors)) {
                //check if the file size if less than the size limit 
                if ($this->sizeLimit > $value) {
                    continue;
                } else {
                    //add size error 
                    $this->errors[$this->getName()[$key]] = ' size is greater than ' . ($this->sizeLimit / 1024 / 1024) . 'MB';
                }
            }
        }
    }

    /**
     *  checkType
     * 
     * check the file type  
     * @param    none 
     * @return   none      
     *
     */
    private function checkType() {
        //loop through the array of file type 
        foreach ($this->getType() as $key => $value) {
            //check if the file name not exists in the error array 
            if (!array_key_exists($this->getName()[$key], $this->errors)) {
                //get the file type 
                $type = explode('/', $value);
                $extension = end($type);
                //check if the type is in the type array 
                if (in_array($extension, $this->type)) {
                    continue;
                }
                //add an error with key of file name and value of the error 
                $this->errors[$this->getName()[$key]] = 'type is not exist!';
            }
        }
    }

    /**
     *  changeName
     * 
     * check the file name 
     * @param    $name (string) file name that will be changed  
     * @return   (string) new file name       
     *
     */
    private function changeName($Name) {
        //convert the name into an array based on the . 
        $array = explode('.', $Name);
        //get the time in micro seconds
        $time = (ceil(microtime(true)));
        //return  random number concactenated with time concactenated with the last element in the array  
        return rand(0,99).$time . '.' . end($array);
    }

    /**
     *  validate 
     * 
     * validate the files (check type and check size)  
     * @param    none 
     * @return   none      
     *
     */
    private function validate() {
        //check size 
        $this->checkSize();
        //check type
        $this->checkType();
    }


    /**
     *  get_uploaded
     * 
     * return array of new file names  
     * @param    none 
     * @return   array      
     *
     */
    public function get_uploaded() {
        //return all the uploaded file names 
        return $this->newFileName;
    }

    /**
     *  get_error
     * 
     * return error array 
     * @param    none 
     * @return   array       
     *
     */
    public function get_error() {
        //return error array 
        return $this->errors;
    }
	/**
     *  checkEmptyInput
     * 
     * check if there is an input or not  
     * set the input flag to false if there is not input otherwise it will be sit to true
     * @param    none 
     * @return   none      
     *
     */
    private function checkEmptyInput() {
		if($this->required == TRUE)
		{
			//check if there is a file uploaded or not by checking its size 
			if (is_array($this->inputName['size'])) {
				//if size is equal to zero 
				if (($this->inputName['size'][0]) == 0) {
					//set input flag to be false 
					$this->inputFlag = false;
                    return;
				}
			} else {
				//if size is equal to zero
				if (($this->inputName['size']) == 0) {
					//set input flag to be false
					$this->inputFlag = false;
                    return;
				}
			}
		}else{
			//check if there is a file uploaded or not by checking its size 
			if (is_array($this->inputName['size'])) {
				//if size is equal to zero 
				if (($this->inputName['size'][0]) > 0) {
					//set input flag to be false 
					$this->inputFlag = true;
					return;
				}
			}else {
				//if size is equal to zero
				if (($this->inputName['size']) > 0) {
					//set input flag to be false
					$this->inputFlag = true;
					return;
				}else{
					$this->inputFlag = false;
					return;
				}
			}
		}
		$this->inputFlag = true;
    }

    /**
     *  do_upload
     * 
     * do the upload process 
     * @param    none 
     * @return   boolean       
     *
     */
    public function do_upload() {
			//check if there is an input or not 
			if ($this->inputFlag) {
				//validate the files to check its size and type 
				$this->validate();
				//loop through the files temp name 
				foreach ($this->getTempName() as $key => $value) {
					//check if the file uploaded or not 
					if (is_uploaded_file($this->getTempName()[$key])) {
						//check if the file name exists in the error array 
						if (array_key_exists($this->getName()[$key], $this->errors)) {
							//go to the next loop iteration and skip the next code 
							continue;
						}
						//store the changed name that will be added in the db in the newfileName array 
						$this->newFileName[$key] = $this->changeName($this->getName()[$key]);
						//set the destination of the uploading process 
						$destination = $this->uploadDirectory . DIRECTORY_SEPARATOR . $this->newFileName[$key];
						//check if the temp file is moved completely or not 
						if (move_uploaded_file($this->getTempName()[$key], $destination)) {
							//go to the next iteration in case the file in moved sucessfully 
							continue;
						} else {
							//check if the name of the file is in the array error 
							if (!array_key_exists($this->getName()[$key], $this->errors)) {
								//add an error with key of the file name and value of not moved 
								$this->errors[$this->getName()[$key]] = 'not moved';
							}
						}
					} else {
						//check if the file name is in the errror array 
						if (!array_key_exists($this->getName()[$key], $this->errors)) {
							// set not uploaded error with key of the file name and value of not uploaded
							$this->errors[$this->getName()[$key]] = 'not uploaded';
						}
					}
				}

				//check if there is an error in the error array or not 
				if (count($this->errors) > 0) {
					$this->result['uploadError'] = $this->errors;
				}if (count($this->newFileName) > 0) {
					$this->result['uploaded'] = $this->newFileName;
				}
			}else if($this->inputFlag == false && $this->required == FALSE) {
				$this->result['uploaded'] = NULL;
        	}else {
				//add an empty input array 
				$this->result['uploadError'] = 'please select a file to be uploaded';
				return $this->result;
        	} 

        return $this->result;
    }

}

?>
