<?php
// ------------------------------------------------------------------------- //
//                XOOPS - PHP Content Management System                      //
//                       <http://www.xoops.org/>                             //
// ------------------------------------------------------------------------- //
//  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 2 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, write to the Free Software              //
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA //
// ------------------------------------------------------------------------- //
// Author of File: 							     //
// Kazumi Ono (http://www.mywebaddons.com/ , http://www.myweb.ne.jp/)        //
// ------------------------------------------------------------------------- //

class XoopsModule{

	var $db;
	var $mid;
	var $name;
	var $dirname;
	var $weight;
	var $isactive;
	var $hasadmin;
	var $hasmain;
	var $hassearch;
	var $modinfo = array();
	var $modvars = array();
	var $errors = array();
	var $adminmenu = array();
	
	// these table cannot be installed nor uninstalled
	// this is a very dirty workaround...may need to find a better method
	var $reservedTables = array('groups','groups_users_link','groups_modules_link','groups_blocks_link','bannerclient','banner','bannerfinish','metafooter','priv_msgs','ranks','session','smiles','users','newblocks','modules');

	function XoopsModule($mid = -1, $load=true){
		$this->db =& Database::getInstance();
		if ( $mid != -1 ) {
			if ( is_array($mid) ) {
				$this->makeModule($mid);
			} else {
				$this->getModule(intval($mid));
			}
			if ( $load ) {
				$this->loadModInfo($this->dirname);
				$this->loadModVars($this->dirname);
			}
		}
	}

	function loadModInfo($dirname) {
		global $xoopsConfig;
		if(file_exists(XOOPS_ROOT_PATH."/modules/".$dirname."/language/".$xoopsConfig['language']."/modinfo.php")) {
			include_once(XOOPS_ROOT_PATH."/modules/".$dirname."/language/".$xoopsConfig['language']."/modinfo.php");
		} elseif(file_exists(XOOPS_ROOT_PATH."/modules/".$dirname."/language/english/modinfo.php")) {
			include_once(XOOPS_ROOT_PATH."/modules/".$dirname."/language/english/modinfo.php");
		}
		if(file_exists(XOOPS_ROOT_PATH."/modules/".$dirname."/xoops_version.php")) {
			include(XOOPS_ROOT_PATH."/modules/".$dirname."/xoops_version.php");
		} else {
			echo "Module File for $dirname Not Found!";
			return;
		}
		$this->modinfo =& $modversion;
	}

	function loadModVars($dirname){
		if ( isset($this->modinfo['varfile']) && $this->modinfo['varfile'] != "" ) {
			if ( file_exists(XOOPS_ROOT_PATH."/modules/".$dirname."/".$this->modinfo['varfile']."")) {
				include(XOOPS_ROOT_PATH."/modules/".$dirname."/".$this->modinfo['varfile']."");
				$this->modvars =& $modvars;
			}
		}
	}

	function getModVar($key){
		return $this->modvars[$key];
	}

	function getModule($mid){
		$sql = "SELECT * FROM ".$this->db->prefix("modules")." WHERE mid = ".$mid."";
		$result = $this->db->query($sql);
		$array = $this->db->fetchArray($result);
		$this->makeModule($array);
	}

	function makeModule($array){
		foreach($array as $key=>$value){
			$this->$key = $value;
		}
	}

	function getByDirname($dirname){
		$db =& Database::getInstance();
		$ret = false;
		$sql = "SELECT * FROM ".$db->prefix("modules")." WHERE dirname = '".trim($dirname)."'";
		if ( $result = $db->query($sql) ) {
			$count = $db->getRowsNum($result);
			if ( $count == 1 ) {
				$arr = $db->fetchArray($result);
				$ret = new XoopsModule($arr);
			}
		}
		return $ret;
	}

	function activate(){
		if ( !isset($this->weight) || !is_numeric($this->weight) ) {
			$this->weight = 0;
		}
		$sql = "UPDATE ".$this->db->prefix("modules")." SET last_update=".time().", weight=".$this->weight.", isactive=1 WHERE mid=".$this->mid."";
		if ( !$result = $this->db->query($sql) ) {
			array_push($this->errors,"Could not update modules table");
			return false;
		}
		$sql = "UPDATE ".$this->db->prefix("newblocks")." SET isactive=1 WHERE mid=".$this->mid."";
		if ( !$result = $this->db->query($sql) ) {
			array_push($this->errors,$this->db->error());
			return false;
		}
		return true;
	}

	function deactivate(){
		if ( !isset($this->weight) || !is_numeric($this->weight) ) {
			$this->weight = 0;
		}
		$sql = "UPDATE ".$this->db->prefix("modules")." SET last_update=".time().", weight=".$this->weight.", isactive=0 WHERE mid=".$this->mid."";
		if ( !$result = $this->db->query($sql) ) {
			array_push($this->errors,$this->db->error());
			return false;
		}
		$sql = "UPDATE ".$this->db->prefix("newblocks")." SET isactive=0 WHERE mid=".$this->mid."";
		if ( !$result = $this->db->query($sql) ) {
			array_push($this->errors,$this->db->error());
			return false;
		}
		return true;
	}

	/**
   	* Install a module
	* If the module has blocks, insert blocks info in blocks table
	*/
	function install($create_tbl=true){
		global $xoopsConfig;
		$error = false;
		if ($create_tbl != false) {
			if ( !empty($this->modinfo['sqlfile']) && is_array($this->modinfo['sqlfile']) ) {
				$sql_file_path = XOOPS_ROOT_PATH."/modules/".$this->dirname()."/".$this->modinfo['sqlfile'][$xoopsConfig['database']]."";
				if ( !file_exists($sql_file_path) ) {
					array_push($this->errors,"SQL file not found at $sql_file_path!");
					$error = true;
				} else {
					$sql_query = fread(fopen($sql_file_path, 'r'), filesize($sql_file_path));
        				if (get_magic_quotes_runtime() == 1) {
        					$sql_query = stripslashes($sql_query);
					}
					$sql_query = trim($sql_query);
					$this->db->splitSqlFile($pieces, $sql_query);
					$created_tables = array();
					foreach ( $pieces as $piece ) {
						// [0] contains the prefixed query
						// [4] contains unprefixed table name
						$prefixed_query = $this->db->prefixQuery($piece);
						// check if the table name is reserved 
						if ( !$prefixed_query ) {
							array_push($this->errors,"$piece is not a valid SQL!");
							$error = true;
							break;
						}
						// check if the table name is reserved 
						if ( !in_array($prefixed_query[4], $this->reservedTables) ) {
							// not reserved, so try to create one
							if ( !$this->db->query($prefixed_query[0]) ) {
								array_push($this->errors,$this->db->error());
								$error = true;
								break;
							} else {
								if ( !in_array($prefixed_query[4], $created_tables) ) {
									$created_tables[] = $prefixed_query[4];
								}
							}
						} else {
							// the table name is reserved, so halt the installation
							array_push($this->errors,$prefixed_query[4]." is a reserved table!");
							$error = true;
							break;
						}
					}
					// if there was an error, delete the tables created so far, so the next installation will not fail
					if ( $error == true ) {
						foreach ($created_tables as $ct) {
							//echo $ct;
							$this->db->query("DROP TABLE ".$this->db->prefix($ct)."");
						}
					}
				}
			}
		}
		// if no error, save the module info and blocks info associated with it
		if ( !$error ) {
			$newmid = $this->db->genId($this->db->prefix("modules")."_mid_seq");
			if ( !isset($this->modinfo['hasAdmin']) || $this->modinfo['hasAdmin'] != 1 ) {
				$this->modinfo['hasAdmin'] = 0;
			}
			if ( !isset($this->modinfo['hasMain']) || $this->modinfo['hasMain'] != 1 ) {
				$this->modinfo['hasMain'] = 0;
			}
			if ( !isset($this->modinfo['hasSearch']) || $this->modinfo['hasSearch'] != 1 ) {
				$this->modinfo['hasSearch'] = 0;
			}
			if ( !isset($this->weight) || !is_numeric($this->weight) ) {	
				$this->weight = 1;
			}
			$version = $this->modinfo['version'] * 100;
			$sql = "INSERT INTO ".$this->db->prefix("modules")." (mid, name, dirname, version, last_update, weight, isactive, hasmain, hasadmin, hassearch) VALUES ($newmid, '".addslashes($this->modinfo['name'])."', '".addslashes($this->modinfo['dirname'])."', ".$version.", ".time().", ".$this->weight.", 1, ".$this->modinfo['hasMain'].", ".$this->modinfo['hasAdmin'].", ".$this->modinfo['hasSearch']." )";
			if ( !$this->db->query($sql) ) {
				array_push($this->errors,$sql);
				foreach ($created_tables as $ct) {
					//echo $ct;
					$this->db->query("DROP TABLE ".$this->db->prefix($ct)."");
				}
				return false;
			} else {
				if ( empty($newmid) ) {
					$newmid = $this->db->getInsertId();
				}
				//foreach ( $created_tables as $ct ) {
				//	$sql = "INSERT INTO ".$this->db->prefix("module_tables")." (mid, table) VALUES ($newmid, '$ct')";
				//	$this->db->query($sql);
				//}
				if ( isset($this->modinfo['blocks']) ) {
					$i = 1;
					foreach ( $this->modinfo['blocks'] as $block ) {
						$options = "";
						if ( isset($block['options']) && $block['options']!= "" ) {
							$options = $block['options'];
						}
						$newbid = $this->db->genId($this->db->prefix("blocks")."_bid_seq");
						$sql = "INSERT INTO ".$this->db->prefix("newblocks")." (bid, mid, func_num, options, name, position, title, content, side, weight, visible, type, isactive) VALUES ($newbid, $newmid, $i,'$options','".addslashes($block['name'])."',0,'','',0,0,0,'M',1)";
						if ( !$this->db->query($sql) ) {
							array_push($this->errors,$this->db->error());
						}
						$i++;
					}
				}
			}
			return $newmid;
		} else {
			return false;
		}
	}

	function uninstall(){
		$sql = "DELETE FROM ".$this->db->prefix("modules")." WHERE mid=".$this->mid."";
		if ( !$this->db->query($sql) ) {
			array_push($this->errors, $this->db->error());
			return false;
		}
		$sql = "DELETE FROM ".$this->db->prefix("groups_modules_link")." WHERE mid=".$this->mid."";
		if ( !$this->db->query($sql) ) {
			array_push($this->errors, $this->db->error());
		}
		$block_arr = XoopsBlock::getByModule($this->mid);
		foreach ( $block_arr as $block ) {
			if ( !$block->delete() ) {
				array_push($this->errors, "Could not delete block. Block name: ".$block->name()." Block ID: ".$block->bid());
			}
		}
		if ( !empty($this->modinfo['tables']) && is_array($this->modinfo['tables']) ) {
			foreach ( $this->modinfo['tables'] as $table ) {
				// prevent deletion of reserved core tables!
				if ( !in_array($table, $this->reservedTables) ) {
					$sql = "DROP TABLE ".$this->db->prefix($table)."";
					if ( !$this->db->query($sql) ) {
						array_push($this->errors, "Could not delete table ".$this->db->prefix($table)."");
					}
				} else {
					array_push($this->errors, "Not allowed to delete table ".$this->db->prefix($table)."!");
				}
			}
		}
		if ( count($this->errors) > 0 ) {
			return false;
		}
		return true;
	}

	function isActivated(){
		if ( !empty($this->isactive) && $this->isactive == 1 ) {
			return true;
		}
		return false;
	}

	/**
   	* Updates module info in module table and blocks info in blocks table.
	* It is generally used when blocks are added or modified.
	* Or to change the block title in blocks admin menu.
	* This does not change the actual block contents in DB
	*/
	function update(){
		if ( !isset($this->modinfo['hasAdmin']) || $this->modinfo['hasAdmin'] != 1 ) {
			$this->modinfo['hasAdmin'] = 0;
		}
		if ( !isset($this->modinfo['hasMain']) || $this->modinfo['hasMain'] != 1 ) {
			$this->modinfo['hasMain'] = 0;
		}
		if ( !isset($this->modinfo['hasSearch']) || $this->modinfo['hasSearch'] != 1 ) {
			$this->modinfo['hasSearch'] = 0;
		}
		if ( !isset($this->weight) || !is_numeric($this->weight) ) {
			$this->weight = 0;
		}
		$version = $this->modinfo['version'] * 100;
		$sql = "UPDATE ".$this->db->prefix("modules")." SET name='".addslashes($this->modinfo['name'])."', dirname='".addslashes($this->modinfo['dirname'])."', version=".$version.", last_update=".time().", weight=".$this->weight.", hasmain=".$this->modinfo['hasMain'].", hasadmin=".$this->modinfo['hasAdmin'].", hassearch=".$this->modinfo['hasSearch']." WHERE mid=".$this->mid."";
		if ( !$result = $this->db->query($sql) ) {
			array_push($this->errors,$this->db->error());
		}
		if ( isset($this->modinfo['blocks']) ) {
			$i = 0;
			foreach ( $this->modinfo['blocks'] as $block ) {
				$i++;
				$options = "";
				if ( isset($block['options']) && $block['options']!= "" ) {
					$options = $block['options'];
				}
				$sql = "SELECT COUNT(*) FROM ".$this->db->prefix("newblocks")." WHERE mid=".$this->mid." AND func_num=".$i."";
				list($count) = $this->db->fetchRow($this->db->query($sql));
				if ( $count > 0 ) {
					$sql = "UPDATE ".$this->db->prefix("newblocks")." SET options='".$options."', name='".addslashes($block['name'])."' WHERE mid=".$this->mid." AND func_num=".$i."";
				} else {
					$newbid = $this->db->genId($this->db->prefix("blocks")."_bid_seq");
					$sql = "INSERT INTO ".$this->db->prefix("newblocks")." (bid, mid, func_num, options, name, position, title, content, side, weight, visible, type, isactive) VALUES (".$newbid.", ".$this->mid.", ".$i.",'".$options."','".addslashes($block['name'])."',0,'','',0,0,0,'M',1)";
				}
				if ( !$result = $this->db->query($sql) ) {
					array_push($this->errors,"Could not update ".$block['name']."");
				}
			}
			$sql = "SELECT COUNT(*) FROM ".$this->db->prefix("newblocks")." WHERE mid=".$this->mid."";
			list($count) = $this->db->fetchRow($this->db->query($sql));
			if ( $count > $i ) {
				for ( $j = $i + 1; $j <= $count; $j++ ) {
					$sql = "DELETE FROM ".$this->db->prefix("newblocks")." WHERE mid=".$this->mid." AND func_num=".$j."";
					$this->db->query($sql);
				}
			}
		}
		if ( count($this->errors) > 0 ) {
			return false;
		}
		return true;
	}

	function changeOrder($order){
		if ( empty($order) || !is_numeric($order) ) {
			$order = 0;
		}
		$sql = "UPDATE ".$this->db->prefix("modules")." SET weight=".$order." WHERE mid=".$this->mid."";
		if ( !$this->db->query($sql) ) {
			array_push($this->errors,$this->db->error());
			return false;
		}
		return true;
	}

	function moduleExists($dirname){
		$db =& Database::getInstance();
		$sql = "SELECT COUNT(*) FROM ".$db->prefix("modules")." WHERE dirname='$dirname'";
		list($count) = $db->fetchRow($db->query($sql));
		if ( $count > 0 ) {
			return true;
		}
		return false;
	}

	function currentVersion(){
		if ( isset($this->version) ) {
			$version = round($this->version / 100,2);
		} else {
			$version = $this->version();
		}
		return $version;
	}

	function last_update(){
		return $this->last_update;
	}

	function isactive(){
		return $this->isactive;
	}

	function setWeight($value){
		$this->weight = $value;
	}

	function weight(){
		return $this->weight;
	}

	function mid(){
		if ( isset($this->mid) ) {
			return $this->mid;
		}
	}

	function hasAdmin(){
		if ( $this->modinfo['hasAdmin'] ) {
			return true;
		}
		return false;
	}

	function hasMain(){
		if ( $this->modinfo['hasMain'] ) {
			return true;
		}
		return false;
	}

	function name(){
		if ( isset($this->modinfo['name']) ) {
			return $this->modinfo['name'];
		} else {
			return false;
		}
	}

	function dirname(){
		if ( isset($this->modinfo['dirname']) ) {
			return $this->modinfo['dirname'];
		} else {
			return false;
		}
	}

	function date(){
		if ( isset($this->modinfo['date']) ) {
			return $this->modinfo['date'];
		} else {
			return false;
		}
	}

	function version(){
		if ( isset($this->modinfo['version']) ) {
			return $this->modinfo['version'];
		} else {
			return false;
		}
	}

	function description(){
		if ( isset($this->modinfo['description']) ) {
			return $this->modinfo['description'];
		} else {
			return false;
		}
	}

	function author(){
		if ( isset($this->modinfo['author']) ) {
			return $this->modinfo['author'];
		} else {
			return false;
		}
	}

	function credits(){
		if ( isset($this->modinfo['credits']) ) {
			return $this->modinfo['credits'];
		} else {
			return false;
		}
	}

	function help(){
		if ( isset($this->modinfo['help']) ) {
			return $this->modinfo['help'];
		} else {
			return false;
		}
	}

	function license(){
		if ( isset($this->modinfo['license']) ) {
			return $this->modinfo['license'];
		} else {
			return false;
		}
	}

	function official(){
		if ( isset($this->modinfo['official']) ) {
			return $this->modinfo['official'];
		} else {
			return 1;
		}
	}

	function image(){
		if ( isset($this->modinfo['image']) ) {
			return $this->modinfo['image'];
		} else {
			return false;
		}
	}

	function adminindex(){
		if ( isset($this->modinfo['adminindex']) ) {
			return $this->modinfo['adminindex'];
		} else {
			return false;
		}
	}

	function blockFuncFile($func_number){
		return $this->modinfo['blocks'][$func_number]['file'];
	}

	function blockShowFunc($func_number){
		if ( isset($this->modinfo['blocks'][$func_number]['show_func']) ){
			return $this->modinfo['blocks'][$func_number]['show_func'];
		}
		return false;
	}

	function blockEditFunc($func_number){
		if ( isset($this->modinfo['blocks'][$func_number]['edit_func']) ){
			return $this->modinfo['blocks'][$func_number]['edit_func'];
		}
		return false;
	}

	function mainLink(){
		if ( $this->hasMain() ) {
			$ret = "<a href='".XOOPS_URL."/modules/".$this->dirname()."/'>".$this->name()."</a>";
			return $ret;
		}
		return false;
	}

	function subLink(){
		$ret = array();
		if ( isset($this->modinfo['sub']) && is_array($this->modinfo['sub']) ) {
			foreach ( $this->modinfo['sub'] as $submenu ) {
				$ret[] .= "<a href='".XOOPS_URL."/modules/".$this->dirname()."/".$submenu['url']."'>".$submenu['name']."</a>";
			}
			return $ret;
		}
		return false;
	}



	function search($term="", $andor="AND", $limit=0, $offset=0, $userid=0){
		global $xoopsConfig;
		if (!isset($this->modinfo['hasSearch']) || !$this->modinfo['hasSearch'] || !isset($this->modinfo['search']['func']) || !isset($this->modinfo['search']['file']) || $this->modinfo['search']['func'] == "" || $this->modinfo['search']['file'] == "" ) {
			return false;
		}
		if ( file_exists(XOOPS_ROOT_PATH."/modules/".$this->dirname()."/".$this->modinfo['search']['file']) ) {
			include_once(XOOPS_ROOT_PATH."/modules/".$this->dirname()."/".$this->modinfo['search']['file']);
		} else {
			return false;
		}
		//$ret = array();
		if ( function_exists($this->modinfo['search']['func']) ) {
			$func = $this->modinfo['search']['func'];
			$ret = $func($term, $andor, $limit, $offset, $userid);
			return $ret;
		} else {
			return false;
		}
	}

	function loadAdminMenu() {
		global $xoopsConfig;
		if ( isset($this->modinfo['adminmenu']) && $this->modinfo['adminmenu'] != "" && file_exists(XOOPS_ROOT_PATH."/modules/".$this->dirname()."/".$this->modinfo['adminmenu']) ) {
			include_once(XOOPS_ROOT_PATH."/modules/".$this->dirname()."/".$this->modinfo['adminmenu']);
			$this->adminmenu = $adminmenu;
		}
	}

	function getAdminMenu() {
		$this->loadAdminMenu();
		return $this->adminmenu;
	}

	function errors(){
		return $this->errors;
	}

	function getHasMainModulesList($dirname=false){
		$db =& Database::getInstance();
		$ret = array();
		$result = $db->query("SELECT mid, name, dirname from ".$db->prefix("modules")." WHERE isactive=1 AND hasmain=1 ORDER BY name ASC");
		while($myrow=$db->fetchArray($result)){
			if ( $dirname == true ) {
				$ret[$myrow['dirname']] = $myrow['name'];
			} else {
				$ret[$myrow['mid']] = $myrow['name'];
			}
		}
		return $ret;
	}

	function getHasSearchModulesList($aslist = true){
		$db =& Database::getInstance();
		$ret = array();
		$result = $db->query("SELECT mid,name from ".$db->prefix("modules")." WHERE isactive=1 AND hassearch=1 ORDER BY name ASC");
		while ( $myrow=$db->fetchArray($result) ) {
			if ( $aslist ) {
				$ret[$myrow['mid']] = $myrow['name'];
			} else {
				$ret[] = $myrow['mid'];
			}
		}
		return $ret;
	}

	function getHasAdminModulesList($aslist = true){
		$db =& Database::getInstance();
		$ret = array();
		$result = $db->query("SELECT mid,name from ".$db->prefix("modules")." WHERE isactive=1 AND hasadmin=1 ORDER BY mid ASC");
		while ( $myrow=$db->fetchArray($result) ) {
			if ($aslist) {
				$ret[$myrow['mid']] = $myrow['name'];
			} else {
				$ret[] = $myrow['mid'];
			}
		}
		return $ret;
	}

	/*
	*  static
	*  Get all modules as a list
	*  set $aslist to true for ease of use with class XoopsLists
	*  $exclude is an array of module ids that you dont want to get
	*/
	function getInstalledModules($asobject=true){
		$db =& Database::getInstance();
		$ret = array();
		$sql = "SELECT * from ".$db->prefix("modules")." ORDER BY weight,hasmain ";
		$result = $db->query($sql);
		while ( $myrow = $db->fetchArray($result) ) {
			if ( $asobject == true ) {
				$ret[] = new XoopsModule($myrow);
			} else {
				$ret[] = $myrow['mid'];
			}
		}
		return $ret;
	}

	function getByRight($groupid, $right="R"){
		$db =& Database::getInstance();
		$sql = "SELECT DISTINCT mid FROM ".$db->prefix("groups_modules_link")." WHERE type='".$right."'";
		if ( is_array($groupid) ) {
			$sql .= " AND (groupid=".$groupid[0]."";
			$size = sizeof($groupid);
			if ( $size  > 1 ) {
				for ( $i = 1; $i < $size; $i++ ) {
					$sql .= " OR groupid=".$groupid[$i]."";
				}
			}
			$sql .= ")";
		} else {
			$sql .= " AND groupid=".$groupid."";
		}
		$result = $db->query($sql);
		$mids = array();
		while ( $myrow = $db->fetchArray($result) ) {
			$mids[] = $myrow['mid'];
		}
		return $mids;
	}

}

?>