<?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 Guides {
	
	private $_configFile = 'guides';
	private $_enableShortGuides = false;
	private $_shortGuidesCharLimit = 100;
	
	private $_id;
	private $_language;
	private $_title;
	private $_content;
	
	function __construct() {
		
		$config = loadConfigurations($this->_configFile);
		$this->_enableShortGuides = $config['guides_short'];
		$this->_shortGuidesCharLimit = $config['guides_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 addGuides($title,$content,$author='Administrator',$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
					$guides_data = array(
						htmlentities($title),
						$author,
						time(),
						$content,
						$comments
					);
					
					// add guides
					$add_guides = $this->db->query("INSERT INTO ".WEBENGINE_GUIDES." (guides_title,guides_author,guides_date,guides_content,allow_comments) VALUES (?,?,?,?,?)", $guides_data);
					
					if($add_guides) {
						// 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 removeGuides($id) {
		$this->db = Connection::Database('Me_MuOnline');
		if(Validator::Number($id)) {
			if($this->guidesIdExists($id)) {
				$remove = $this->db->query("DELETE FROM ".WEBENGINE_GUIDES." WHERE guides_id = ?", array($id));
				if($remove) {
					
					$this->setId($id);
					$this->_deleteAllGuidesTranslations();
					
					return true;
				} else {
					return false;
				}
			} else {
				return false;
			}
		} else {
			return false;
		}
	}
	
	function editGuides($id,$title,$content,$author,$comments,$date) {
		$this->db = Connection::Database('Me_MuOnline');
		if(check_value($id) && check_value($title) && check_value($content) && check_value($author) && check_value($comments) && check_value($date)) {
			if(!$this->guidesIdExists($id)) { return false; }
			if($this->checkTitle($title) && $this->checkContent($content)) {
				$editData = array(
					$title,
					$content,
					$author,
					strtotime($date),
					$comments,
					$id
				);
				$query = $this->db->query("UPDATE ".WEBENGINE_GUIDES." SET guides_title = ?, guides_content = ?, guides_author = ?, guides_date = ?, allow_comments = ? WHERE guides_id = ?", $editData);
				if($query) {
					message('success', 'Guia Editado correctamente.');
				} 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 retrieveGuides() {
		$this->db = Connection::Database('Me_MuOnline');
		$guides = $this->db->query_fetch("SELECT * FROM ".WEBENGINE_GUIDES." ORDER BY guides_id DESC");
		if(is_array($guides)) {
			return $guides;
		} else {
			return null;
		}
	}
	
	function guidesIdExists($id) {
		if(!Validator::UnsignedNumber($id)) return;
		$cachedGuides = loadCache('guides.cache');
		if(!is_array($cachedGuides)) return;
		foreach($cachedGuides as $cacheData) {
			if($cacheData['guides_id'] == $id) return true;
		}
		return;
	}
	
	function deleteGuidesFiles() {
		$files = glob(__PATH_GUIDES_CACHE__.'*');
		foreach($files as $file) {
			if(is_file($file)) {
				unlink($file);
			}
		}
	}
	
	function cacheGuides() {
		if($this->isGuidesDirWritable()) {
			$guides_list = $this->retrieveGuides();
			$this->deleteGuidesFiles();
			if(is_array($guides_list)) {
				foreach($guides_list as $guides) {
					$handle = fopen(__PATH_GUIDES_CACHE__."guides_".$guides['guides_id'].".cache", "a");
					fwrite($handle, $guides['guides_content']);
					fclose($handle);
					
					if($this->_enableShortGuides) {
						$handle2 = fopen(__PATH_GUIDES_CACHE__."guides_".$guides['guides_id']."_s.cache", "a");
						fwrite($handle2, $this->_getShortVersion($guides['guides_content']));
						fclose($handle2);
					}
				}
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}
	
	function isGuidesDirWritable() {
		if(is_writable(__PATH_GUIDES_CACHE__)) {
			return true;
		} else {
			return false;
		}
	}
	
	function retrieveGuidesDataForCache() {
		$this->db = Connection::Database('Me_MuOnline');
		$guides = $this->db->query_fetch("SELECT guides_id,guides_title,guides_author,guides_date,allow_comments FROM ".WEBENGINE_GUIDES." ORDER BY guides_id DESC");
		if(is_array($guides)) {
			return $guides;
		} else {
			return null;
		}
	}
	
	function updateGuidesCacheIndex() {
		$guidesList = $this->retrieveGuidesDataForCache();
		if(!is_array($guidesList)) {
			updateCacheFile('guides.cache', '');
			return true;
		}
		
		foreach($guidesList as $key => $row) {
			$this->setId($row['guides_id']);
			$guidesTranslations = $this->getGuidesTranslationsDataList();
			if(!is_array($guidesTranslations)) continue;
			foreach($guidesTranslations as $translation) {
				$guidesList[$key]['translations'][$translation['guides_language']] = $translation['guides_title'];
			}
		}
		
		$cacheData = encodeCache($guidesList);
		$updateCache = updateCacheFile('guides.cache', $cacheData);
		if(!$updateCache) return;
		return true;
	}
	
	function LoadCachedGuides($shortVersion=false) {
		if(!check_value($this->_id)) return;
		if(!Validator::UnsignedNumber($this->_id)) return;
		
		// Load guides translation cache
		if(check_value($this->_language)) {
			$guidesTranslationFile = __PATH_GUIDES_TRANSLATIONS_CACHE__.'guides_'.$this->_id.'_'.$this->_language.'.cache';
			$guidesTranslationFileShort = __PATH_GUIDES_TRANSLATIONS_CACHE__.'guides_'.$this->_id.'_'.$this->_language.'_s.cache';
			if($shortVersion) {
				if(file_exists($guidesTranslationFileShort)) {
					$content = file_get_contents($guidesTranslationFileShort);
					if($content) {
						return $content;
					}
				}
			} else {
				if(file_exists($guidesTranslationFile)) {
					$content = file_get_contents($guidesTranslationFile);
					if($content) {
						return $content;
					}
				}
			}
		}
		
		// Load regular guides cache (short)
		if($shortVersion) {
			$shortVersion = __PATH_GUIDES_CACHE__ . 'guides_'.$this->_id.'_s.cache';
			if(file_exists($shortVersion)) {
				$content = file_get_contents($shortVersion);
				if($content) {
					return $content;
				}
			}
		}
		
		// Load regular guides cache
		$file = __PATH_GUIDES_CACHE__ . 'guides_'.$this->_id.'.cache';
		if(!file_exists($file)) return;
		$content = file_get_contents($file);
		if(!$content) return;
		return $content;
	}
	
	function loadGuidesData($id) {
		$this->db = Connection::Database('Me_MuOnline');
		if(check_value($id) && $this->guidesIdExists($id)) {
			$query = $this->db->query_fetch_single("SELECT * FROM ".WEBENGINE_GUIDES." WHERE guides_id = ?", array($id));
			if($query && is_array($query)) {
				return $query;
			}
		}
	}
	
	public function getGuidesTranslations() {
		$this->db = Connection::Database('Me_MuOnline');
		if(!check_value($this->_id)) return;
		$guidesTranslations = $this->db->query_fetch("SELECT * FROM ".WEBENGINE_GUIDES_TRANSLATIONS." WHERE guides_id = ?", array($this->_id));
		if(!is_array($guidesTranslations)) return;
		foreach($guidesTranslations as $translation) {
			$result[] = $translation['guides_language'];
		}
		if(!is_array($result)) return;
		return $result;
	}
	
	public function addGuidesTransation() {
		$this->db = Connection::Database('Me_MuOnline');
		
		if(!check_value($this->_id)) throw new Exception('The provided guides id is not valid.');
		if(!check_value($this->_language)) throw new Exception('The provided guides language is not valid.');
		if(!check_value($this->_title)) throw new Exception('The provided guides title is not valid.');
		if(!check_value($this->_content)) throw new Exception('The provided guides content is not valid.');
		
		$guidesTranslations = $this->getGuidesTranslations();
		if(is_array($guidesTranslations)) {
			if(in_array($this->_language, $guidesTranslations)) throw new Exception('A translation for this language already exists, please use the edit guides translation module.');
		}
		
		$result = $this->db->query("INSERT INTO ".WEBENGINE_GUIDES_TRANSLATIONS." (guides_id, guides_language, guides_title, guides_content) VALUES (?, ?, ?, ?)", array($this->_id, $this->_language, $this->_title, $this->_content));
		if(!$result) throw new Exception('Could not add the guides translation.');
		
		$guidesTranslationFile = __PATH_GUIDES_TRANSLATIONS_CACHE__.'guides_'.$this->_id.'_'.$this->_language.'.cache';
		$guidesTranslationFileShort = __PATH_GUIDES_TRANSLATIONS_CACHE__.'guides_'.$this->_id.'_'.$this->_language.'_s.cache';
		
		$handle = fopen($guidesTranslationFile, 'w');
		fwrite($handle, $this->_content);
		fclose($handle);
		
		if($this->_enableShortGuides) {
			$handle2 = fopen($guidesTranslationFileShort, 'w');
			fwrite($handle2, $this->_getShortVersion($this->_content));
			fclose($handle2);
		}
	}
	
	public function updateGuidesTransation() {
		$this->db = Connection::Database('Me_MuOnline');
		
		if(!check_value($this->_id)) throw new Exception('The provided guides id is not valid.');
		if(!check_value($this->_language)) throw new Exception('The provided guides language is not valid.');
		if(!check_value($this->_title)) throw new Exception('The provided guides title is not valid.');
		if(!check_value($this->_content)) throw new Exception('The provided guides content is not valid.');
		
		$result = $this->db->query("UPDATE ".WEBENGINE_GUIDES_TRANSLATIONS." SET guides_title = ?, guides_content = ? WHERE guides_id = ? AND guides_language = ?", array($this->_title, $this->_content, $this->_id, $this->_language));
		if(!$result) throw new Exception('Could not update the guides translation.');
		
		$guidesTranslationFile = __PATH_GUIDES_TRANSLATIONS_CACHE__.'guides_'.$this->_id.'_'.$this->_language.'.cache';
		$guidesTranslationFileShort = __PATH_GUIDES_TRANSLATIONS_CACHE__.'guides_'.$this->_id.'_'.$this->_language.'_s.cache';
		
		$handle = fopen($guidesTranslationFile, 'w');
		fwrite($handle, $this->_content);
		fclose($handle);
		
		if($this->_enableShortGuides) {
			$handle2 = fopen($guidesTranslationFileShort, 'w');
			fwrite($handle2, $this->_getShortVersion($this->_content));
			fclose($handle2);
		}
	}
	
	public function deleteGuidesTranslation() {
		$this->db = Connection::Database('Me_MuOnline');
		if(!check_value($this->_id)) throw new Exception('The provided guides id is not valid.');
		if(!check_value($this->_language)) throw new Exception('The provided guides language is not valid.');
		
		$result = $this->db->query("DELETE FROM ".WEBENGINE_GUIDES_TRANSLATIONS." WHERE guides_id = ? AND guides_language = ?", array($this->_id, $this->_language));
		if(!$result) throw new Exception('Could not delete guides translation.');
		
		$guidesTranslationFile = __PATH_GUIDES_TRANSLATIONS_CACHE__.'guides_'.$this->_id.'_'.$this->_language.'.cache';
		$guidesTranslationFileShort = __PATH_GUIDES_TRANSLATIONS_CACHE__.'guides_'.$this->_id.'_'.$this->_language.'_s.cache';
		
		if(file_exists($guidesTranslationFile)) {
			unlink($guidesTranslationFile);
		}
		
		if(file_exists($guidesTranslationFileShort)) {
			unlink($guidesTranslationFileShort);
		}
	}
	
	public function loadGuidesTranslationData() {
		$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_GUIDES_TRANSLATIONS." WHERE guides_id = ? AND guides_language = ?", array($this->_id, $this->_language));
		if(!is_array($result)) return;
		return $result;
	}
	
	public function loadGuidesTranslationCache() {
		if(!check_value($this->_id)) return;
		if(!check_value($this->_language)) return;
		
		$guidesTranslationFile = __PATH_GUIDES_TRANSLATIONS_CACHE__.'guides_'.$this->_id.'_'.$this->_language.'.cache';
		if(!file_exists($guidesTranslationFile)) return;
		
		$cacheContent = file_get_contents($guidesTranslationFile);
		if($cacheContent == false) return;
		
		return $cacheContent;
	}
	
	public function getGuidesTranslationsDataList() {
		$this->db = Connection::Database('Me_MuOnline');
		if(!check_value($this->_id)) return;
		$result = $this->db->query_fetch("SELECT * FROM ".WEBENGINE_GUIDES_TRANSLATIONS." WHERE guides_id = ?", array($this->_id));
		if(!is_array($result)) return;
		return $result;
	}
	
	private function _deleteAllGuidesTranslations() {
		$this->db = Connection::Database('Me_MuOnline');
		if(!check_value($this->_id)) return;
		
		$guidesTranslations = $this->getGuidesTranslations();
		if(!is_array($guidesTranslations)) return;

		foreach($guidesTranslations as $translation) {
			try {
				$this->setLanguage($translation);
				$this->deleteGuidesTranslation();
			} catch(Exception $ex) {
				continue;
			}
		}
		
		return true;
	}
	
	// SnakeDrak
	// https://stackoverflow.com/a/39569929
	private function _getShortVersion($guidesData) {
		$value = html_entity_decode($guidesData);
		if(mb_strwidth($value,'UTF-8') <= $this->_shortGuidesCharLimit) {
			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->_shortGuidesCharLimit+$len_tags, '', 'UTF-8');
		} while( $len_stripped > $this->_shortGuidesCharLimit);
		$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);
	}

}