<?php
/**
 * WebEngine CMS
 * https://webenginecms.org/
 * 
 * @version 1.2.0
 * @author Lautaro Angelico <http://lautaroangelico.com/>
 * @copyright (c) 2013-2019 Lautaro Angelico, All Rights Reserved
 * 
 * Licensed under the MIT license
 * http://opensource.org/licenses/MIT
 */

class Changelogs {
	
	private $_configFile = 'changelogs';
	private $_enableShortChangelogs = false;
	private $_shortChangelogsCharLimit = 100;
	
	private $_id;
	private $_language;
	private $_title;
	private $_content;
	
	function __construct() {
		
		$config = loadConfigurations($this->_configFile);
		$this->_enableShortChangelogs = $config['changelogs_short'];
		$this->_shortChangelogsCharLimit = $config['changelogs_short_char_limit'];
		
	}
	
	public function setId($id) {
		if(!Validator::UnsignedNumber($id)) return;
		$this->_id = $id;
	}
	
	public function setLanguage($language) {
		if(!check_value($language)) return;
		$languagesList = getInstalledLanguagesList();
		if(!is_array($languagesList)) return;
		if(!in_array($language, $languagesList)) return;
		$this->_language = $language;
	}
	
	public function setTitle($title) {
		if(!check_value($title)) return;
		$this->_title = $title;
	}
	
	public function setContent($content) {
		if(!check_value($content)) return;
		$this->_content = $content;
	}
	
	function addChangelogs($title,$content,$author='Administrator',$prefijo,$comments=1) {
		$this->db = Connection::Database('Me_MuOnline');
		if(check_value($title) && check_value($content) && check_value($author)) {
			if($this->checkTitle($title)) {
				if($this->checkContent($content)) {
					// make sure comments is 1 or 0
					if($comments < 0 || $comments > 1) {
						$comments = 1;
					}
				
					// collect data
					$changelogs_data = array(
						htmlentities($title),
						$author,
						time(),
						$content,
						$prefijo,
						$comments
					);
					
					// add changelogs
					$add_changelogs = $this->db->query("INSERT INTO ".WEBENGINE_CHANGELOGS." (changelogs_title,changelogs_author,changelogs_date,changelogs_content,changelogs_prefijo,allow_comments) VALUES (?,?,?,?,?,?)", $changelogs_data);
					
					if($add_changelogs) {
						// success message
						message('success', lang('success_15',true));
					} else {
						message('error', lang('error_23',true));
					}
					
				} else {
					message('error', lang('error_43',true));
				}
			} else {
				message('error', lang('error_42',true));
			}
		} else {
			message('error', lang('error_41',true));
		}
	}
	
	function removeChangelogs($id) {
		$this->db = Connection::Database('Me_MuOnline');
		if(Validator::Number($id)) {
			if($this->changelogsIdExists($id)) {
				$remove = $this->db->query("DELETE FROM ".WEBENGINE_CHANGELOGS." WHERE changelogs_id = ?", array($id));
				if($remove) {
					
					$this->setId($id);
					$this->_deleteAllChangelogsTranslations();
					
					return true;
				} else {
					return false;
				}
			} else {
				return false;
			}
		} else {
			return false;
		}
	}
	
	function editChangelogs($id,$title,$content,$author,$prefijo,$comments,$date) {
		$this->db = Connection::Database('Me_MuOnline');
		if(check_value($id) && check_value($title) && check_value($content) && check_value($author) && check_value($prefijo) && check_value($comments) && check_value($date)) {
			if(!$this->changelogsIdExists($id)) { return false; }
			if($this->checkTitle($title) && $this->checkContent($content)) {
				$editData = array(
					$title,
					$content,
					$author,
					$prefijo,
					strtotime($date),
					$comments,
					$id
				);
				$query = $this->db->query("UPDATE ".WEBENGINE_CHANGELOGS." SET changelogs_title = ?, changelogs_content = ?, changelogs_author = ?, changelogs_prefijo = ?, changelogs_date = ?, allow_comments = ? WHERE changelogs_id = ?", $editData);
				if($query) {
					message('success', 'Changelogs successfully edited.');
				} else {
					message('error', lang('error_99'));
				}
			}
		}
	}
	
	function checkTitle($title) {
		if(check_value($title)) {
			if(strlen($title) < 4 || strlen($title) > 80) {
				return false;
			} else {
				return true;
			}
		} else {
			return false;
		}
	}
	
	function checkContent($content) {
		if(check_value($content)) {
			if(strlen($content) < 4) {
				return false;
			} else {
				return true;
			}
		} else {
			return false;
		}
	}
	
	function retrieveChangelogs() {
		$this->db = Connection::Database('Me_MuOnline');
		$changelogs = $this->db->query_fetch("SELECT * FROM ".WEBENGINE_CHANGELOGS." ORDER BY changelogs_id DESC");
		if(is_array($changelogs)) {
			return $changelogs;
		} else {
			return null;
		}
	}
	
	function changelogsIdExists($id) {
		if(!Validator::UnsignedNumber($id)) return;
		$cachedChangelogs = loadCache('changelogs.cache');
		if(!is_array($cachedChangelogs)) return;
		foreach($cachedChangelogs as $cacheData) {
			if($cacheData['changelogs_id'] == $id) return true;
		}
		return;
	}
	
	function deleteChangelogsFiles() {
		$files = glob(__PATH_CHANGELOGS_CACHE__.'*');
		foreach($files as $file) {
			if(is_file($file)) {
				unlink($file);
			}
		}
	}
	
	function cacheChangelogs() {
		if($this->isChangelogsDirWritable()) {
			$changelogs_list = $this->retrieveChangelogs();
			$this->deleteChangelogsFiles();
			if(is_array($changelogs_list)) {
				foreach($changelogs_list as $changelogs) {
					$handle = fopen(__PATH_CHANGELOGS_CACHE__."changelogs_".$changelogs['changelogs_id'].".cache", "a");
					fwrite($handle, $changelogs['changelogs_content']);
					fclose($handle);
					
					if($this->_enableShortChangelogs) {
						$handle2 = fopen(__PATH_CHANGELOGS_CACHE__."changelogs_".$changelogs['changelogs_id']."_s.cache", "a");
						fwrite($handle2, $this->_getShortVersion($changelogs['changelogs_content']));
						fclose($handle2);
					}
				}
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}
	
	function isChangelogsDirWritable() {
		if(is_writable(__PATH_CHANGELOGS_CACHE__)) {
			return true;
		} else {
			return false;
		}
	}
	
	function retrieveChangelogsDataForCache() {
		$this->db = Connection::Database('Me_MuOnline');
		$changelogs = $this->db->query_fetch("SELECT changelogs_id,changelogs_title,changelogs_author,changelogs_date,changelogs_prefijo,allow_comments FROM ".WEBENGINE_CHANGELOGS." ORDER BY changelogs_id DESC");
		if(is_array($changelogs)) {
			return $changelogs;
		} else {
			return null;
		}
	}
	
	function updateChangelogsCacheIndex() {
		$changelogsList = $this->retrieveChangelogsDataForCache();
		if(!is_array($changelogsList)) {
			updateCacheFile('changelogs.cache', '');
			return true;
		}
		
		foreach($changelogsList as $key => $row) {
			$this->setId($row['changelogs_id']);
			$changelogsTranslations = $this->getChangelogsTranslationsDataList();
			if(!is_array($changelogsTranslations)) continue;
			foreach($changelogsTranslations as $translation) {
				$changelogsList[$key]['translations'][$translation['changelogs_language']] = $translation['changelogs_title'];
			}
		}
		
		$cacheData = encodeCache($changelogsList);
		$updateCache = updateCacheFile('changelogs.cache', $cacheData);
		if(!$updateCache) return;
		return true;
	}
	
	function LoadCachedChangelogs($shortVersion=false) {
		if(!check_value($this->_id)) return;
		if(!Validator::UnsignedNumber($this->_id)) return;
		
		// Load changelogs translation cache
		if(check_value($this->_language)) {
			$changelogsTranslationFile = __PATH_CHANGELOGS_TRANSLATIONS_CACHE__.'changelogs_'.$this->_id.'_'.$this->_language.'.cache';
			$changelogsTranslationFileShort = __PATH_CHANGELOGS_TRANSLATIONS_CACHE__.'changelogs_'.$this->_id.'_'.$this->_language.'_s.cache';
			if($shortVersion) {
				if(file_exists($changelogsTranslationFileShort)) {
					$content = file_get_contents($changelogsTranslationFileShort);
					if($content) {
						return $content;
					}
				}
			} else {
				if(file_exists($changelogsTranslationFile)) {
					$content = file_get_contents($changelogsTranslationFile);
					if($content) {
						return $content;
					}
				}
			}
		}
		
		// Load regular changelogs cache (short)
		if($shortVersion) {
			$shortVersion = __PATH_CHANGELOGS_CACHE__ . 'changelogs_'.$this->_id.'_s.cache';
			if(file_exists($shortVersion)) {
				$content = file_get_contents($shortVersion);
				if($content) {
					return $content;
				}
			}
		}
		
		// Load regular changelogs cache
		$file = __PATH_CHANGELOGS_CACHE__ . 'changelogs_'.$this->_id.'.cache';
		if(!file_exists($file)) return;
		$content = file_get_contents($file);
		if(!$content) return;
		return $content;
	}
	
	function loadChangelogsData($id) {
		$this->db = Connection::Database('Me_MuOnline');
		if(check_value($id) && $this->changelogsIdExists($id)) {
			$query = $this->db->query_fetch_single("SELECT * FROM ".WEBENGINE_CHANGELOGS." WHERE changelogs_id = ?", array($id));
			if($query && is_array($query)) {
				return $query;
			}
		}
	}
	
	public function getChangelogsTranslations() {
		$this->db = Connection::Database('Me_MuOnline');
		if(!check_value($this->_id)) return;
		$changelogsTranslations = $this->db->query_fetch("SELECT * FROM ".WEBENGINE_CHANGELOGS_TRANSLATIONS." WHERE changelogs_id = ?", array($this->_id));
		if(!is_array($changelogsTranslations)) return;
		foreach($changelogsTranslations as $translation) {
			$result[] = $translation['changelogs_language'];
		}
		if(!is_array($result)) return;
		return $result;
	}
	
	public function addChangelogsTransation() {
		$this->db = Connection::Database('Me_MuOnline');
		
		if(!check_value($this->_id)) throw new Exception('The provided changelogs id is not valid.');
		if(!check_value($this->_language)) throw new Exception('The provided changelogs language is not valid.');
		if(!check_value($this->_title)) throw new Exception('The provided changelogs title is not valid.');
		if(!check_value($this->_content)) throw new Exception('The provided changelogs content is not valid.');
		
		$changelogsTranslations = $this->getChangelogsTranslations();
		if(is_array($changelogsTranslations)) {
			if(in_array($this->_language, $changelogsTranslations)) throw new Exception('A translation for this language already exists, please use the edit changelogs translation module.');
		}
		
		$result = $this->db->query("INSERT INTO ".WEBENGINE_CHANGELOGS_TRANSLATIONS." (changelogs_id, changelogs_language, changelogs_title, changelogs_content) VALUES (?, ?, ?, ?)", array($this->_id, $this->_language, $this->_title, $this->_content));
		if(!$result) throw new Exception('Could not add the changelogs translation.');
		
		$changelogsTranslationFile = __PATH_CHANGELOGS_TRANSLATIONS_CACHE__.'changelogs_'.$this->_id.'_'.$this->_language.'.cache';
		$changelogsTranslationFileShort = __PATH_CHANGELOGS_TRANSLATIONS_CACHE__.'changelogs_'.$this->_id.'_'.$this->_language.'_s.cache';
		
		$handle = fopen($changelogsTranslationFile, 'w');
		fwrite($handle, $this->_content);
		fclose($handle);
		
		if($this->_enableShortChangelogs) {
			$handle2 = fopen($changelogsTranslationFileShort, 'w');
			fwrite($handle2, $this->_getShortVersion($this->_content));
			fclose($handle2);
		}
	}
	
	public function updateChangelogsTransation() {
		$this->db = Connection::Database('Me_MuOnline');
		
		if(!check_value($this->_id)) throw new Exception('The provided changelogs id is not valid.');
		if(!check_value($this->_language)) throw new Exception('The provided changelogs language is not valid.');
		if(!check_value($this->_title)) throw new Exception('The provided changelogs title is not valid.');
		if(!check_value($this->_content)) throw new Exception('The provided changelogs content is not valid.');
		
		$result = $this->db->query("UPDATE ".WEBENGINE_CHANGELOGS_TRANSLATIONS." SET changelogs_title = ?, changelogs_content = ? WHERE changelogs_id = ? AND changelogs_language = ?", array($this->_title, $this->_content, $this->_id, $this->_language));
		if(!$result) throw new Exception('Could not update the changelogs translation.');
		
		$changelogsTranslationFile = __PATH_CHANGELOGS_TRANSLATIONS_CACHE__.'changelogs_'.$this->_id.'_'.$this->_language.'.cache';
		$changelogsTranslationFileShort = __PATH_CHANGELOGS_TRANSLATIONS_CACHE__.'changelogs_'.$this->_id.'_'.$this->_language.'_s.cache';
		
		$handle = fopen($changelogsTranslationFile, 'w');
		fwrite($handle, $this->_content);
		fclose($handle);
		
		if($this->_enableShortChangelogs) {
			$handle2 = fopen($changelogsTranslationFileShort, 'w');
			fwrite($handle2, $this->_getShortVersion($this->_content));
			fclose($handle2);
		}
	}
	
	public function deleteChangelogsTranslation() {
		$this->db = Connection::Database('Me_MuOnline');
		if(!check_value($this->_id)) throw new Exception('The provided changelogs id is not valid.');
		if(!check_value($this->_language)) throw new Exception('The provided changelogs language is not valid.');
		
		$result = $this->db->query("DELETE FROM ".WEBENGINE_CHANGELOGS_TRANSLATIONS." WHERE changelogs_id = ? AND changelogs_language = ?", array($this->_id, $this->_language));
		if(!$result) throw new Exception('Could not delete changelogs translation.');
		
		$changelogsTranslationFile = __PATH_CHANGELOGS_TRANSLATIONS_CACHE__.'changelogs_'.$this->_id.'_'.$this->_language.'.cache';
		$changelogsTranslationFileShort = __PATH_CHANGELOGS_TRANSLATIONS_CACHE__.'changelogs_'.$this->_id.'_'.$this->_language.'_s.cache';
		
		if(file_exists($changelogsTranslationFile)) {
			unlink($changelogsTranslationFile);
		}
		
		if(file_exists($changelogsTranslationFileShort)) {
			unlink($changelogsTranslationFileShort);
		}
	}
	
	public function loadChangelogsTranslationData() {
		$this->db = Connection::Database('Me_MuOnline');
		if(!check_value($this->_id)) return;
		if(!check_value($this->_language)) return;
		$result = $this->db->query_fetch_single("SELECT * FROM ".WEBENGINE_CHANGELOGS_TRANSLATIONS." WHERE changelogs_id = ? AND changelogs_language = ?", array($this->_id, $this->_language));
		if(!is_array($result)) return;
		return $result;
	}
	
	public function loadChangelogsTranslationCache() {
		if(!check_value($this->_id)) return;
		if(!check_value($this->_language)) return;
		
		$changelogsTranslationFile = __PATH_CHANGELOGS_TRANSLATIONS_CACHE__.'changelogs_'.$this->_id.'_'.$this->_language.'.cache';
		if(!file_exists($changelogsTranslationFile)) return;
		
		$cacheContent = file_get_contents($changelogsTranslationFile);
		if($cacheContent == false) return;
		
		return $cacheContent;
	}
	
	public function getChangelogsTranslationsDataList() {
		$this->db = Connection::Database('Me_MuOnline');
		if(!check_value($this->_id)) return;
		$result = $this->db->query_fetch("SELECT * FROM ".WEBENGINE_CHANGELOGS_TRANSLATIONS." WHERE changelogs_id = ?", array($this->_id));
		if(!is_array($result)) return;
		return $result;
	}
	
	private function _deleteAllChangelogsTranslations() {
		$this->db = Connection::Database('Me_MuOnline');
		if(!check_value($this->_id)) return;
		
		$changelogsTranslations = $this->getChangelogsTranslations();
		if(!is_array($changelogsTranslations)) return;

		foreach($changelogsTranslations as $translation) {
			try {
				$this->setLanguage($translation);
				$this->deleteChangelogsTranslation();
			} catch(Exception $ex) {
				continue;
			}
		}
		
		return true;
	}
	
	// SnakeDrak
	// https://stackoverflow.com/a/39569929
	private function _getShortVersion($changelogsData) {
		$value = html_entity_decode($changelogsData);
		if(mb_strwidth($value,'UTF-8') <= $this->_shortChangelogsCharLimit) {
			return $value;
		}
		do {
			$len = mb_strwidth( $value, 'UTF-8' );
			$len_stripped = mb_strwidth( strip_tags($value), 'UTF-8' );
			$len_tags = $len - $len_stripped;
			$value = mb_strimwidth($value, 0, $this->_shortChangelogsCharLimit+$len_tags, '', 'UTF-8');
		} while( $len_stripped > $this->_shortChangelogsCharLimit);
		$dom = new DOMDocument();
		@$dom->loadHTML('<?xml encoding="utf-8" ?>' . $value, LIBXML_HTML_NODEFDTD);
		$value = $dom->saveHtml($dom->getElementsByTagName('body')->item(0));
		$value = mb_strimwidth($value, 6, mb_strwidth($value, 'UTF-8') - 13, '', 'UTF-8');
		return preg_replace('/<(\w+)\b(?:\s+[\w\-.:]+(?:\s*=\s*(?:"[^"]*"|"[^"]*"|[\w\-.:]+))?)*\s*\/?>\s*<\/\1\s*>/', '', $value);
	}

}