<?php
defined('WikyBlog') or die("Not an entry point...");

class objectSave{
	
	function objectSave(){
		global $dbObject,$langA, $wbParser,$page, $jsNum;
		
		
		if( !cookies() ){
			message('COOKIES_REQUIRED');
			return;
		}
		
		switch( $page->userCmd ){
			
			case 'save'://maps don't use $langA['save']
			case wbStrtolower($langA['save']):
			
				//try to save the object
				if( objectSave::saveControl($dbObject) ){
					$mess = wbLang::text('SAVED_FILE');
					if( $page->ajaxRequest && $dbObject->validData && !empty($_GET['wb']['u']) ){
						$url = fromStorageUrl($_GET['wb']['u']);
						if( $url ){
							$url = wbLinks::getUrl($url);
							$mess .= ' - ';
							$mess .= '<a href="javascript:void(0)" onclick="WBt.go(\''.$_GET['wb']['u'].'\',\''.$url.'\')">'.$langA['continue_editing'].'</a>';
							$page->scripts[] = '/include/js/editingAll.js?'.$jsNum;
						}
					}
					message($mess);
					
					$field = $dbObject->outputObj();
					$dbObject->addFooter($field);
					
				}elseif( !$page->ajaxRequest ){
					// need to send the the edit form again if it's not an xmlHttp request
					includeFile('tool/EditPage.php');
					initEdit::init();
				}
			break;
		}
	}
	
	
	function saveControl( &$saveObj,$newValues = NULL, $timestamp = false){
		global $pageOwner, $page, $wbConfig, $wbTables, $langA, $wbNow, $wbUniq, $wbAdminUser;
		
		$existingData = array();
		$existingData['size'] = 0;
		$existingData['keywords'] = '';
		
		if( !$saveObj->editable ){
			message('PROTECTED_FILE');
			return false;
		}
		
		$pageOwner += array('totalUsage' => 0);
		if( 	($GLOBALS['maxUserDiskUsage'] > 0) 
			&& ($pageOwner['totalUsage'] > $GLOBALS['maxUserDiskUsage'])
			&& !wbStrcasecmp($wbAdminUser, $pageOwner['username'])
			&& !wbStrcasecmp($GLOBALS['wbConfig']['pUser'], $pageOwner['username'])
			){
				
				message('SURPASSED_MAX');
				return false;
		}
		
		//////////////////////////////////////////////////////////////////////////////////////////
		//
		//			I) Copy existing values for comparison later on in the script
		//
		if( $saveObj->exists ){
			$existingData = objectSave::prepExisting($saveObj, isset($newValues) );
		}
		
		
		//////////////////////////////////////////////////////////////////////////////////////////
		//
		//			II) Set and check the new values
		//
		
		if( !isset($newValues) ){
			
			if( !objectSave::fromPost($saveObj) ){
				return false;
			}
			
		}else{
			//	Using $newValues, we override the check for consistency... 
			//		this should be used carefully
			//	Note: $newValues could just be an array
			$saveObj->setVariables( $newValues, $saveObj->userValues);
		}
		$saveObj->checkData(); //could checkData
		
		if( !$saveObj->validData ){
			return false;
		}
		
		//////////////////////////////////////////////////////////////////////////////////////////
		//
		//			III) cont.. flood check
		//					Keeps users who are not logged in and not in the current workgroup from editing/saving files too quickly
		//					Done here because a setFromPost needs to be before (in case we refuse the edit, we don't want to discard the changes)
		//
		if( isset($_SESSION['lastSave']) ){
			reset($_SESSION['lastSave']); //key() doesn't work right for all php versions
			
			if( isset($wbConfig['floodInterval']) 
				&& ($wbConfig['floodInterval'] > 0)
				&& ($_SESSION['userlevel'] < 2)
				){
			
				$checkFlood = false;
				if( !$existingData['gotLast'] ){
					$checkFlood = true;
				}elseif( $saveObj->uniqStorage != key($_SESSION['lastSave'])  ){
					$checkFlood = true;
				}
				
				if( $checkFlood ){
					$timeDiff = time()-current($_SESSION['lastSave']);
					if( $timeDiff < $wbConfig['floodInterval'] ){
						message('FLOOD_WARN',$wbConfig['floodInterval'],$wbConfig['floodInterval']-$timeDiff);
						return false;
					}
				}
			}
		}
		
		if( (strpos($saveObj->flags,'captcha') !== false)
			&& ($saveObj->editable === 1)
			){
				if( empty($_POST['captcha']) ){
					message('INCORRECT_CAPTCHA');
					return false;
				}
				
				//prep the text
				$r = $_SESSION['captcha'][$saveObj->uniqStorage];
				$text = md5($wbUniq.$r);
				$text = str_replace(array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'),array(''),$text);
				$text = substr($text,1,6);

				
				if( $text !== $_POST['captcha'] ){
					$i = 0;
					while($i < strlen($text) ){
						$a = $text{$i};
						$b = $_POST['captcha']{$i};
						$i++;
					}
					message('INCORRECT_CAPTCHA');
					return false;
				}
		}
		
		
		//////////////////////////////////////////////////////////////////////////////////////////
		//
		//			IV) flags
		// 
		
		//unchecked?
		if( isset($pageOwner['fEdits']) 
			&& ((int)$pageOwner['fEdits'] >= (int)$_SESSION['userlevel']) 
			&& (strpos($saveObj->flags,'notchecked') === false)
			){
			$saveObj->flags .= ',notchecked';
		}
		
		//clean the flags .. if they've been changed they might not be in clean sql form
		$temp = explode(',',$saveObj->flags);
		$temp = array_unique($temp);
		$temp = array_diff($temp,array(''));
		$saveObj->flags = implode(',',$temp);
		
		
		
		//////////////////////////////////////////////////////////////////////////////////////////
		//
		//			V) Save it
		// 
		if( $saveObj->exists ){
			
			if( !objectSave::existingFile($saveObj,$existingData) ){
				return false;
			}
			
		}elseif( !objectSave::newFile($saveObj) ){
			return false;
		}
		
		objectSave::afterSave($saveObj,$existingData);

		
		return true;
	}
	
	////////////////////////////////////////////////////////////////////////////////////
	//	
	//		Save Old File
	//
	function existingFile(&$saveObj,&$existingData){
		global $wbNow;
		$timestamp = $wbNow;
		
	 	//	A) Get Instructions
		includeFile('tool/History2.php');
		$comparison = new difference_main( objectSave::getObjectValues($saveObj), $existingData['values']); // get instructions for changing from new to past version
		
		
		//	B) HISTORY
		//	start with the history so that we can easily get the revision number if we don't have it yet
		if( !$existingData['gotLast'] ){
			
			if( empty($comparison->instructions) ){
				message('NO_CHANGES','1');
				return false;				
			}
			
			//add another row to represent the new edit
			$revisionNum = objectSave::newHistoryRow($saveObj);
			objectSave::cleanHistory($saveObj->file_id,$revisionNum);
			$updRevision = ($revisionNum-1);
			
		}else{
			
			if( empty($comparison->instructions) ){
				//
				//	Get rid of the newest history row because any changes that were made have been undone
				//	
				
				objectSave::undoHistoryRow($saveObj);
				$updRevision = false;
				$timestamp = $saveObj->modified;
			}else{
				objectSave::updHistoryRow($saveObj);
				$updRevision = $saveObj->revision;
			}
		}
		
		
		//	C)	UPDATE
		if( !objectSave::updateAll($saveObj,$comparison->instructions,$updRevision,$timestamp) ){
			return false;
		}
		
		// Save All Edits
		// "On" will save all edits in the revision history. "Off" will record revisions based on editing sessions.
		if( isset($_SESSION['saveAll']) && ($_SESSION['saveAll'] === 'On') ){
			$_SESSION['editPage'][$saveObj->uniqStorage] = $wbNow;
		}
		
		return true;
	}
	
	function getObjectValues(&$saveObj){
		$values = array();
		foreach($saveObj->userValues as $key => $null){
			$values[$key] = $saveObj->$key;
		}
		foreach($saveObj->dbValues as $key => $null){
			if( array_key_exists($key,$saveObj->userValues) ){
				continue;
			}
			$values[$key] = $saveObj->$key;
		}
		return $values;
	}
	
	
	////////////////////////////////////////////////////////////////////////////////////
	//	
	//		Copy the important information of the existing file before setting the new
	//		values so that we can compare them with the new object
	//
	function prepExisting(&$saveObj, $hasNewValues ){
		
		$existingData['keywords'] = $saveObj->keywords;
		$existingData['size'] = $saveObj->size;
		$existingData['gotLast'] = false;
		
		//	1)	Existing Values
		
		//	So whats the criteria here?... that the user is continuing to make changes during a xmlHTTP session
		//	--> this means that they haven't gone back to toolEditPage.PHP -> modified times will be different
		//	--> the current username/id will be from the same user!
		
		
		//Get the last version?
		if( isset($_SESSION['editPage'][$saveObj->uniqStorage])					//	Must be within users editing session
			&& $_SESSION['editPage'][$saveObj->uniqStorage] != $saveObj->modified	//	Session-time shouldn't match object-time
			&& !$hasNewValues											//	and it can't be an internal change (includes "RevertEdit", File Uploads)
			){
			
			$getLast = false;
			if( isset($_SESSION['username']) ){								//	and it's the same editor
				if($_SESSION['username'] == $saveObj->username){
					$getLast = true;
				}
			}elseif($_SERVER['REMOTE_ADDR'] == $saveObj->ip){
				$getLast = true;
			}
			
			$existingData['gotLast'] = false;
			if( $getLast ){
				includeFile('tool/History1.php');
				if( getLastRevision($saveObj,$_SESSION['editPage'][$saveObj->uniqStorage]) ){
					$existingData['gotLast'] = true;
				}else{
					// 	Didn't get any rows
					//	... so just make sure it gets added by setting the modified value correctly
					$_SESSION['editPage'][$saveObj->uniqStorage] = $saveObj->modified;
				}
			}
		}
		
		
		$existingData['values'] = objectSave::getObjectValues($saveObj);  //this needs to be done after getLastRevsion()
		
		return $existingData;
	}
	
	////////////////////////////////////////////////////////////////////////////////////
	//	
	//		Set Values from $_POST
	//		and check the `modified` value
	//
	function fromPost(&$saveObj){
		
		if( $saveObj->requirePOST &&  ($_SERVER['REQUEST_METHOD'] != 'POST') ){
			message('INVALID_REQUEST');
			//trigger_error('Saves can only be made with "POST".');
			return false;
		}

		$saveObj->setFromPost();
		
		
		// Check existing vs $_SESSION
		// after setting new values so that the user doesn't lose the new values if there's an error
		//if( empty($_SESSION['editPage'][$saveObj->uniqStorage]) ||($_SESSION['editPage'][$saveObj->uniqStorage] != $saveObj->modified) ){
		if( !isset($_SESSION['editPage']) || !is_array($_SESSION['editPage']) ){
			message('VERSION_CONFLICT_2');
			return false;
		}
		if( !array_key_exists($saveObj->uniqStorage, $_SESSION['editPage']) && $saveObj->exists ){
			message('VERSION_CONFLICT');
			return false;
		}

		if( !array_key_exists($saveObj->uniqStorage, $_SESSION['editPage'] ) || ($_SESSION['editPage'][$saveObj->uniqStorage] != $saveObj->modified)){
// 			message('stored: '.$_SESSION['editPage'][$saveObj->uniqStorage]);
// 			message('file: '.$saveObj->modified);
			message('VERSION_CONFLICT_2');
			return false;
		}
		return true;
	}
	
	////////////////////////////////////////////////////////////////////////////////////
	//	
	//		Save a new file
	//
	
	function newFile(&$saveObj){
		global $wbTables,$wbNow,$pageOwner;
		
		$saveObj->owner_id = $pageOwner['user_id'];
		
		
		//	changes made?
		$insert = array();
		$insert = $saveObj->toDB();
		if($insert === false){
			message('UNABLE_TO_SAVE','2');
			return false;
		}
		
		//	all files table
		$allInsert = array();
		$allInsert['owner_id'] = $saveObj->owner_id;
		$allInsert['modified'] = $wbNow;
		$allInsert['posted'] = $wbNow;
		$allInsert['created'] = $wbNow;
		$allInsert['keywords'] = $saveObj->keywords;
		$allInsert['flags'] = $saveObj->flags; //for defaults: see SPECdefaultOptions.php
		$allInsert['ip'] = $_SERVER['REMOTE_ADDR'];
		$allInsert['size'] = $saveObj->size = objectSave::getSize($saveObj);
		$allInsert['info'] =& $saveObj->uniqLink; //papyrusbb won't have this set
		
		if( isset($_SESSION['username']) ){
			$allInsert['username'] = $_SESSION['username'];
		}
		if( (strpos($saveObj->flags,'hidden') !== false)
			|| (strpos($saveObj->flags,'relvisible') !== false)
			){
			$allInsert['visible'] = '0';
		}
		
		wbDB::dbInsert2($wbTables['all_files'],$allInsert);
		$saveObj->file_id = mysql_insert_id();
		
		//	data type table
		$insert['file_id'] = $saveObj->file_id;
		$query = 'REPLACE INTO '.$saveObj->dbInfo['dbTable'].' SET '.wbDB::toSet($insert,true); 
		$numc = wbDB::runQuery($query,true);
		$_SESSION['editPage'][$saveObj->uniqStorage] = $wbNow;
		
		if($numc < 1){
			message('UNABLE_TO_SAVE','4');
			return false;
		}
		
		objectSave::newHistoryRow($saveObj);
		
		//	all links
		$query = 'UPDATE '.$wbTables['all_links'];
		$query .= ' SET `to_id` = "'.$saveObj->file_id.'" ';
		$query .= ' WHERE `to_link` = "'.wbDB::escape($saveObj->uniqStorage).'" ';
		wbDB::runQuery($query);	
		
		
		//if it's a comment
		if( isset($saveObj->objectType) && $saveObj->objectType == 'comment' ){
			includeFile('tool/FileComments.php');
			fileComments::updateByFileId($saveObj->parent_id);
		}
		
		//if it's a template
		if( strpos($saveObj->flags,'template') !== false){
			
			$query = 'UPDATE '.$wbTables['all_included'];
			$query .= ' SET `incl_id` = "'.$saveObj->file_id.'" ';
			$query .= ' WHERE  ';
			$query .= ' `owner_id` = "'.wbDB::escape($saveObj->owner_id).'" ';
			$query .= ' AND `incl_title` = "'.wbDB::escape($saveObj->title).'" ';
			wbDB::runQuery($query);	
		}
		
		
		return true;
	}
		
	////////////////////////////////////////////////////////////////////////////////////
	//	
	//		After save organisation
	//
	function afterSave(&$saveObj,&$existingData){
		global $pageOwner,$wbNow;
		
		$saveObj->modified = $wbNow;
		$saveObj->exists = true;
		
		if( method_exists($saveObj,'afterSave') ){
			$saveObj->afterSave();
		}
		
		if( $_SESSION['userlevel'] < 2 ){
			$_SESSION['lastSave'] = array($saveObj->uniqStorage=>time());
		}
		
		$pageOwner['totalUsage'] = ($pageOwner['totalUsage'] + $saveObj->size - $existingData['size']);
		
		////	Hidden? 	
			if( (strpos($saveObj->flags,'hidden') === false)
				&& (strpos($saveObj->flags,'relvisible') === false)
				){
				if( $existingData['keywords'] != $saveObj->keywords ){
					includeFile('tool/Tags.php');
					updateTags($existingData['keywords'],$saveObj->keywords);
				}
				
				//all_search
				allSearch::update($saveObj);
				
			}elseif( !empty($saveObj->keywords) ){
				message('HIDDEN_FILE3');
			}
			
			
		////	Blog This (new)
		
				$blogMessage = false;
				$flags =& $saveObj->flags;
				if( isOwner(false,false)
					&& isset($pageOwner['sBlog']) 
					&& ($pageOwner['sBlog'] == 'On')
					&& method_exists($saveObj,'abbrevOutputContent')
					&& (strpos($flags,'hidden') === false)
					&& (strpos($flags,'relvisible') === false)
					&& (strpos($flags,'template') === false)
					&& (strpos($flags,'blogged') === false)
					){
						if( ($saveObj->objectType == 'page') && wbStrcasecmp($saveObj->title,$GLOBALS['wbDefaultTitle']) ){
							$blogMessage = false;
							
						}elseif( isset($pageOwner['sBlog']) && ($pageOwner['sBlog'] == 'On') ){
							$blogMessage = true;
							
						}elseif( $saveObj->objectType == $pageOwner['blogT'] ){
							$blogMessage = true;
						}
				}
				if( $blogMessage ){
					message(wbLinks::local($saveObj->uniqLink.'?cmd=blogthis','blog_this'));
				}
				
			
			
		////	all_blog
			includeFile('tool/BlogContent.php');
			BlogContent::purge($saveObj);
			BlogContent::saveFromObject($saveObj);
		
			
		////	all_links
			objectSave::links($saveObj);
			objectSave::includes($saveObj);
	}


	
	////////////////////////////////////////////////////////////////////////////////////
	//	
	//		this function does most of the work for file updates
	//		updates all_files, $dbInfo['dbTable'], and all_history
	//		(Each save affects two rows in all_history)
	//
	function updateAll(&$saveObj,&$instructions,$revision,$timestamp=false){
		global $wbTables,$wbNow;
		
		//for backwards compatibility with papyrusbb
		if( $timestamp === false ){
			$timestamp = $wbNow;
		}

		
		//dbTable values
		$updateA = array();
		$updateA = $saveObj->toDB();
		if($updateA === false){
			message('UNABLE_TO_SAVE','1');
			return false;
		}
		
		$query = 'UPDATE /* updateall() */ '.$wbTables['all_files'].', '.$saveObj->dbInfo['dbTable'];
		if( $revision !== false ){
			$query .= ', '.$wbTables['all_history'];
		}
		$query .= ' SET ';
		$query .= wbDB::toSet($updateA,true,$saveObj->dbInfo['dbTable']);
		
		
		//all_files values
		
		$updateA = array();
		if( isset($_SESSION['username']) ){
			$updateA['username'] = $_SESSION['username'];
		}else{
			$updateA['username'] = '';
		}
		$updateA['modified'] = $timestamp;
		$updateA['keywords'] = $saveObj->keywords;
		$updateA['ip'] = $_SERVER['REMOTE_ADDR'];
		$updateA['size'] = $saveObj->size = objectSave::getSize($saveObj);
		//remove redirect 
		if( strpos($saveObj->flags,'redirect') !== false ){
			$saveObj->flags = str_replace(array('redirect',',,'),array('',','),$saveObj->flags);
			$updateA['info'] = '';
		}
		$query .= ','.wbDB::toSet($updateA,false,$wbTables['all_files']);
		
		//these are added here to avoid "data truncated" errors with NULL values
		$query .= ', '.$wbTables['all_files'].'.`flags` = "'.wbDB::escape($saveObj->flags).'" ';
		
		//all_history values
		if( $revision !== false ){
			$updateA = array();
			$updateA['instructions'] = $instructions;
			$query .= ','.wbDB::toSet($updateA,true,$wbTables['all_history']);
		}
		
		
		//where
		$query .= ' WHERE ';
		$query .= $saveObj->dbInfo['dbTable'].'.`file_id` = "'.$saveObj->file_id.'" ';
		$query .= ' AND '.$saveObj->dbInfo['dbTable'].'.`file_id` = '.$wbTables['all_files'].'.`file_id` ';
		if( $revision !== false ){
			$query .= ' AND '.$saveObj->dbInfo['dbTable'].'.`file_id` = '.$wbTables['all_history'].'.`file_id` ';
			$query .= ' AND '.$wbTables['all_history'].'.`revision` = "'.$revision.'" ';
		}

		
		$numA = wbDB::runQuery($query,true);
		if($numA == 0){
			message('NO_CHANGES','2');
			return false;
		}elseif($numA > 3){
			//could be one, two or three because we're affecting all_files, dbTable, and all_history now..
			trigger_error('Affected more than 3 '.$numA);
		}
		return true;
	}
	
	////////////////////////////////////////////////////////////////////////////////////
	//	
	//		The first edit of an xmlHTTP session creates a new row in all_history
	//		to represent the current edit
	//		(Each save affects two rows in all_history)
	//
	/* static */
	function newHistoryRow(&$saveObj){
		global $wbNow,$wbTables;
		
		//	all history table
		$tempA['file_id'] = $saveObj->file_id;
		$tempA['instructions'] = '';
		$tempA['modified'] = $wbNow;
		$tempA['ip'] = $_SERVER['REMOTE_ADDR'];
		if( isset($_SESSION['username']) ){
			$tempA['username'] = $_SESSION['username'];
		}
		$_POST += array('summary'=>'');
		$tempA['summary'] = wbHtmlspecialchars($_POST['summary']);
		$numB = wbDB::dbInsert2($wbTables['all_history'],$tempA);
		if($numB == 0){
			trigger_error('History was not saved (new).');
		}
		return mysql_insert_id();
	}
	
	
	/* static */
	function undoHistoryRow(&$saveObj){
		global $wbNow,$wbTables;
		
		$query = 'DELETE FROM '.$wbTables['all_history'];
		$query .= ' WHERE ';
		$query .= ' `file_id` = "'.wbDB::escape($saveObj->file_id).'" ';
		$query .= ' AND `revision` = "'.wbDB::escape($saveObj->revision+1).'" ';
		
		wbDB::runQuery($query);
	}

	////////////////////////////////////////////////////////////////////////////////////
	//	
	//		If a user is making two or more edits during an xmlHTTP session, the all_history
	//		row representing the most recent edit is updated by this function
	//		(Each save affects two rows in all_history)
	//
	/* static */
	function updHistoryRow(&$saveObj){
		global $wbNow,$wbTables;
		
		//update row above
		$histWhere = array();
		$histWhere['file_id'] = $saveObj->file_id;
		$histWhere['revision'] = $saveObj->revision+1;
		
		$tempA = array();
		$tempA['modified'] = $wbNow;
		$tempA['summary'] = wbHtmlspecialchars($_POST['summary']);

		$num = wbDB::dbUpdate2($wbTables['all_history'], $tempA, $histWhere);
		if($num < 0){ 
			trigger_error('History was not updated.');
			return true;
		}
	}

	
	////////////////////////////////////////////////////////////////////////////////////
	//	
	//	check HISTORY LIMIT and delete the oldest rows if there are more than $maxHistory for a page
	//	-	setting $historyTolerance > 1 will delay the deletions untill that many rows more than
	//		the tolerance have been reached.
	//	-	this may delete more than $historyTolerance because of changes made by users to $maxHistory.
	//
	/* static */
	function cleanHistory(&$file_id,&$revisionNum){
		global $maxHistory,$wbTables,$pageOwner;

		$historyTolerance = 10; //will delete excess rows when there are $maxHistory+(n*10) rows
		
		$max = false;
		$maxHistory = (int)$maxHistory;
		$pageOwner['maxHistory'] = (int)$pageOwner['maxHistory'];
		if( ($maxHistory > 0) && ($maxHistory < $pageOwner['maxHistory']) ){
			$max = $maxHistory;
		}elseif( $pageOwner['maxHistory'] > 0 ){
			$max = $pageOwner['maxHistory'];
		}
		
		
		if( $max && ($revisionNum > $max) ){
			if( ( ($revisionNum-$max) % $historyTolerance) === 0 ){
				$query = 'DELETE FROM '.$wbTables['all_history'];
				$query .= ' WHERE `file_id` = '.$file_id;
				$query .= ' AND revision <= '.($revisionNum-$max);
				wbDB::runQuery($query);
				return;
			}
		}
	}
	
	////////////////////////////////////////////////////////////////////////////////////
	//	
	//		Updates the all_links table according to all the 
	//		internal links saved and previously saved in a file
	//
	/* static */
	function links(&$saveObj){
		global $wbTables,$dbInfo;
		
		$cleanedLinks = array();
		$oldLinks = array();
		
		foreach($saveObj->inLinks as $link){
			$link = toStorage($link); //make sure spaces are translated
			if( $pos = strpos($link,'#') ){
				$link = substr($link,0,$pos);
			}
			
			if( $pos = strpos($link,'?') ){
				$link = substr($link,0,$pos);
			}
			
			//don't save link to self
			$lower = wbStrtolower($link);
			if($lower == $saveObj->uniqStorage ){
				continue;
			}
			$cleanedLinks[$lower] = $link; 	// $lower used to compare with the database values
		}
		
		
		//Compare with links in database
		$query = 'SELECT LOWER(`to_link`) as `to_link` FROM '.$wbTables['all_links'].' where `file_id` = "'.$saveObj->file_id.'" ';
		$result = wbDB::runQuery($query);
		$oldLinks = array();
		while($row = mysql_fetch_assoc($result) ){
			if( array_key_exists($row['to_link'],$cleanedLinks) ){
				unset($cleanedLinks[$row['to_link']]); //link alread in db, so we don't need to add it later
			}else{
				$oldLinks[] = ' (`to_link` = "'.wbDB::escape($row['to_link']).'") '; //link in db but not in $cleanedLinks.. so we need to remove it
			}
		}
		
		//Delete Removed Links
		if( count($oldLinks) > 0 ){
			$query = 'DELETE FROM '.$wbTables['all_links'];
			$query .= ' WHERE ';
			$query .= ' `file_id` = "'.$saveObj->file_id.'" ';
			$query .= ' AND ( ';
			$query .= implode(' OR ',$oldLinks);
			$query .= ' )';
			wbDB::runQuery($query);
		}
		
		if( count($cleanedLinks) < 1){
			return;
		}
		
		//this will only be new links
		foreach($cleanedLinks as $lower => $link){
			
			$pathArray = interpretPath($link);
			if( !isset($dbInfo[$pathArray['type']]['dbTable']) ){
				unset($cleanedLinks[$lower]);
				continue;
			}
			
			if( count($pathArray['path']) < 1){
				$link = str_replace('//','/',$link.'/'.$GLOBALS['wbDefaultTitle']); //!!this is the biggest issue with getting rid of wbDefaultTitle
			}
			
			$space =& $pathArray['type'];
			
			//one query
			//REQUIRES MySQL 4.1
			// $toIdQuery = '( SELECT '.$dbInfo[$space]['dbTable'].'.`file_id` ';
			// $toIdQuery .= ' FROM '.$dbInfo[$space]['dbTable'];
			// $toIdQuery .= ' INNER JOIN '.$wbTables['all_files'];
			// $toIdQuery .= ' USING(`file_id`) ';
			// //might be able to use keys instead of uniqLink
			// $toIdQuery .= ' WHERE '.wbData::dbInfo($space,'uniqLink').' = "'.wbDB::escape($link).'" '; 
			// $toIdQuery .= ' LIMIT 1 OFFSET 0 )';
			
			// $query = 'INSERT IGNORE INTO '.$wbTables['all_links'].' SET ';
			// $query .= ' `file_id` = "'.$saveObj->file_id.'" ';
			// $query .= ', `to_link` = "'.wbDB::escape($link).'" ';
			// $query .= ', `to_owner` = "'.$pathArray['owner'].'" ';
			// $query .= ', `to_id` = '.$toIdQuery;
			// $result = wbDB::runQuery($query);
			
			//
			//	INSERT ..SELECT
			//		.. if the file doesn't exits, it won't insert anything
			//
			$query = 'INSERT IGNORE INTO '.$wbTables['all_links'];
			$query .= ' ( `file_id`, `to_link`, `to_owner`, `to_id` )';
			$query .= ' SELECT ';
			$query .= ' "'.$saveObj->file_id.'" ';
			$query .= ', "'.wbDB::escape($link).'" ';
			$query .= ', "'.$pathArray['owner'].'" ';
			$query .= ', '.$dbInfo[$space]['dbTable'].'.`file_id` ';
			$query .= ' FROM '.$dbInfo[$space]['dbTable'];
			$query .= ' WHERE '.wbData::dbInfo($space,'uniqLink').' = "'.wbDB::escape($link).'" '; 
			$query .= ' LIMIT 1 OFFSET 0 ';
			$num = wbDB::runQuery($query,true);
			
			//nothing was inserted, so the file doesn't exist
			if( $num == 0 ){
				$query = 'INSERT IGNORE INTO '.$wbTables['all_links'].' SET ';
				$query .= ' `file_id` = "'.$saveObj->file_id.'" ';
				$query .= ', `to_link` = "'.wbDB::escape($link).'" ';
				$query .= ', `to_owner` = "'.$pathArray['owner'].'" ';
				wbDB::runQuery($query);
			}
			
		}
	}
	
	//save included file in all_included
	function includes(&$saveObj){
		global $wbTables, $wbNow, $pageOwner;
		
		
		foreach( $saveObj->includes as $incl_title => $incl_id ){
			
			$query = 'REPLACE INTO '.$wbTables['all_included'];
			$query .= ' SET ';
			$query .= ' `file_id` = "'.$saveObj->file_id.'" ';
			$query .= ', `incl_title` = "'.wbDB::escape($incl_title).'" ';
			$query .= ', `owner_id` = "'.wbDB::escape($pageOwner['user_id']).'" ';
			$query .= ', `updated` = "'.wbDB::escape($wbNow).'" ';
			if( $incl_id !== false ){
				$query .= ', `incl_id` = "'.wbDB::escape($incl_id).'" ';
			}else{
				$query .= ', `incl_id` = NULL ';
			}
			wbDB::runQuery($query);
		}
		
		$query = 'DELETE FROM '.$wbTables['all_included'];
		$query .= ' WHERE ';
		$query .= ' `file_id` = "'.$saveObj->file_id.'" ';
		$query .= ' AND `updated` != "'.wbDB::escape($wbNow).'" ';
		wbDB::runQuery($query);
	}

	////////////////////////////////////////////////////////////////////////////////////
	//	
	//		Get the ~size of a file
	//
	/* static */
	function getSize(&$saveObj){
		
		//Starting size should include dateTime values
		//	= (4 bytes)* 3 = 12 insignificant compared to the following
		//-this does not account for history tables
		//-flags are stored in a SET which does not have the same storage requirements as VARCHAR, BLOB, etc
		//-summary is more of a history concern
		
		
		$size = 12;
		$size += strlen($_SERVER['REMOTE_ADDR']);
		
		if( isset($saveObj->username) ){
			$size += strlen($saveObj->username);
		}
		
		if( isset($saveObj->dbValues) ){
			foreach($saveObj->dbValues as $key => $nothing){
				$size += strlen($saveObj->$key)+1; //+1 is nit-picky but true, +2 for blobs but we'll let it go
			}
		}
		
		if( isset($saveObj->files) && is_array($saveObj->files) ){
			clearstatcache();
			foreach($saveObj->files as $file => $null){
				$path = $saveObj->$file;
				if( file_exists($path) ){
					$fileSize = sprintf("%u",@filesize($path));
					if( is_numeric($fileSize) ){
						$size += $fileSize;
					}
				}
			}
		}
		
		return $size;
	}
	

	
}


global $initiateFileClass;
if( $initiateFileClass ){
	new objectSave();
}
