<?php
/* Copyright (C) 2016 Garcia MICHEL <garcia@soamichel.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

dol_include_once('/autoupgrade/class/ziparchive2.class.php');

class AutoUpgrade{
	var $db;
	var $langs;

	var $localFileVersion;
	var $remoteFileVersion;
	var $cachetime;

	function __construct($db, $langs){
		$this->db = $db;
		$this->langs = $langs;

		$this->localFileVersion = DOL_DATA_ROOT.'/autoupgrade/dolibarr.json';
		$this->remoteFileVersion = 'https://packagist.org/p/dolibarr/dolibarr.json';
		$this->cachetime = 86400; // 24H
	}

	function checkNewVersions($unstable=false, $force=false){
		// read list versions on file
		if($force or !file_exists($this->localFileVersion) or (time() - filemtime($this->localFileVersion) > $this->cachetime)){
			$content = @file_get_contents($this->remoteFileVersion);
			if($content === false){
				throw new Exception($this->langs->trans("FailedToCheckUpgrade"));
			}

			$hlFile = fopen($this->localFileVersion, 'w+');
			fwrite($hlFile, $content);
			fclose($hlFile);
		}else{
			$content = @file_get_contents($this->localFileVersion);
			if($content === false){
				throw new Exception($this->langs->trans("FailedToCheckUpgrade"));
			}
		}

		$data = json_decode($content, true);
		$newversions = array();
		foreach($data["packages"]["dolibarr/dolibarr"] as $key => $value){
			if(!$unstable and strlen($key) > 5) continue;

			if(version_compare($key, DOL_VERSION) > 0){
				$newversions[] = $key;
			}
		}

		return $newversions;
	}

	function backUp(){
		global $conf;

    if(ini_get('max_execution_time') < 900 and set_time_limit(900) === false){ // set max_time_limit to 15minutes
			throw new Exception($this->langs->trans("FailedToChangeMaxExecutionTime"));
		}

		if(!file_exists(DOL_DATA_ROOT.'/autoupgrade/backups')){
			dol_mkdir(DOL_DATA_ROOT.'/autoupgrade/backups');
		}

		$zipFile = DOL_DATA_ROOT.'/autoupgrade/backups/v'.DOL_VERSION.'-'.date('Y-m-d-H-i-s').'.zip';
		$zip = new ZipArchive2();
		if($zip->open($zipFile, ZipArchive::CREATE) !== true){
			throw new Exception($this->langs->trans("FailedToCreateBackUp"));
		}

		$zip->addDir($conf->file->dol_document_root['main'], 'htdocs');
		$zip->close();
	}

	function upgradeTo($version){
		global $conf;

		if(version_compare($version, DOL_VERSION) <= 0){
			throw new Exception($this->langs->trans("IncorrectVersion"));
		}

		if(ini_get('max_execution_time') < 900 and set_time_limit(900) === false){ // set max_time_limit to 15minutes
			throw new Exception($this->langs->trans("FailedToChangeMaxExecutionTime"));
		}

		// download from github
		$url = "https://github.com/Dolibarr/dolibarr/archive/".$version.".zip";
		$zipContent = @file_get_contents($url);
		if($zipContent === false){
			throw new Exception($this->langs->trans("FailedToDownloadUpdate"));
		}

		// save on temp file
		$zipFile = tempnam(sys_get_temp_dir(), 'doli_');
		$hlFile = fopen($zipFile, 'w+');
		if(!fwrite($hlFile, $zipContent)){
			fclose($hlFile);
			throw new Exception($this->langs->trans("FailedToSaveUpgrade"));
		}
		fclose($hlFile);

		// extract the ZIP
    $srcDir = sys_get_temp_dir().'/'.uniqid('doli_', true);
    dol_mkdir($srcDir);
    $zipHandle = new ZipArchive();
    if($zipHandle->open($zipFile) !== true){
      throw new Exception($this->langs->trans("FailedToOpenZip"));
    }
    if($zipHandle->extractTo($srcDir) !== true){
      throw new Exception($this->langs->trans("FailedToExtractZip"));
    }
    unlink($zipFile);

    // Sync src to install
    $exclude = array(
      $conf->file->dol_document_root['main'].'/conf/conf.php',
      $conf->file->dol_document_root['main'].'/custom'
    );
    $log = $this->syncDir($srcDir.'/dolibarr-'.$version.'/htdocs', $conf->file->dol_document_root['main'], $exclude);

    // Sync scripts directory
    if(!empty($conf->global->AUTOUPGRADE_SCRIPTS_DIR)){
      $log .= $this->syncDir($srcDir.'/dolibarr-'.$version.'/scripts', $conf->global->AUTOUPGRADE_SCRIPTS_DIR);
    }

    // remove temp directory
    dol_delete_dir_recursive($srcDir);

		// save log
		if(!file_exists(DOL_DATA_ROOT.'/autoupgrade/logs')){
			dol_mkdir(DOL_DATA_ROOT.'/autoupgrade/logs');
		}
		$hlFile = fopen(DOL_DATA_ROOT.'/autoupgrade/logs/v'.$version.'-'.date('Y-m-d-H-i-s').'.log', 'w+');
		fwrite($hlFile, $log);
		fclose($hlFile);
	}

  function syncDir($src, $dst, $exclude=array()){
    $log = '';

    if(!file_exists($dst)){
      dol_mkdir($dst);
    }

    $list = scandir($src);
    foreach($list as $file){
      if($file == '.' or $file == '..'){
        continue;
      }

      if(in_array($dst.'/'.$file, $exclude)){
        $log .= "\nIgnore ".$dst.'/'.$file;
        continue;
      }

      if(is_dir($src.'/'.$file)){
        $log .= $this->syncDir($src.'/'.$file, $dst.'/'.$file, $exclude);
        continue;
      }

      if(!file_exists($dst.'/'.$file)){
        copy($src.'/'.$file, $dst.'/'.$file);
        $log .= "\nNew ".$dst.'/'.$file;
        continue;
      }

      if(md5_file($src.'/'.$file) != md5_file($dst.'/'.$file)){
        copy($src.'/'.$file, $dst.'/'.$file);
        $log .= "\nUpdate ".$dst.'/'.$file;
      }
    }

    $list = scandir($dst);
    foreach($list as $file){
      if($file == '.' or $file == '..'){
        continue;
      }

      if(in_array($dst.'/'.$file, $exclude)){
        $log .= "\nIgnore ".$dst.'/'.$file;
        continue;
      }

      if(is_dir($dst.'/'.$file)){
        continue;
      }

      if(!file_exists($src.'/'.$file)){
        unlink($dst.'/'.$file);
        $log .= "\nRemove ".$dst.'/'.$file;
      }
    }

    return $log;
  }
}
