<?php
	/* -- set headers for response -- */
	header("Content-Type: application/json; charset=UTF-8");
	require_once "./shared/classes.php";
	if (checkSource()==false) {return;}


	/* -- S E R V I C E -- */
	if (isset($_POST['service'])) { $service=trim(htmlspecialchars($_POST['service'])); } 
	else if (isset($_GET['service'])) { $service=trim(htmlspecialchars($_GET['service'])); } else {
		returnError(-1002, "Service Name is Required");
		return false;
	}

	/* -- T O K E N -- */
	if (isset($_POST['token'])) { 
		$token=trim(htmlspecialchars($_POST['token'])); 
	} else {
		returnError(-1002, "Invalid Token");
		return false;
	}

	/*-- fulltext --*/
	$search="";
	if (isset($_POST['search'])) { $search=trim(htmlspecialchars($_POST['search'])); } 

	/*-- record uid --*/
	$uid="";
	if (isset($_POST['uid'])) { $uid=trim(htmlspecialchars($_POST['uid'])); } 

	/*-- Additional Criterians --*/
	$operator1="";
	$field1="";
	$value1="";
	if (isset($_POST['field1'])) { $field1=trim(htmlspecialchars($_POST['field1'])); } 
	if (isset($_POST['operator1'])) { $operator1=trim($_POST['operator1']); } 
	if (isset($_POST['value1'])) { $value1=trim(htmlspecialchars($_POST['value1'])); } 
	$operator2="";
	$field2="";
	$value2="";
	if (isset($_POST['field2'])) { $field2=trim(htmlspecialchars($_POST['field2'])); } 
	if (isset($_POST['operator2'])) { $operator2=trim($_POST['operator2']); } 
	if (isset($_POST['value2'])) { $value2=trim(htmlspecialchars($_POST['value2'])); } 

	/* -- User data filter --*/
	$userdata=0;
	if (isset($_POST['userdata'])) { $userdata=trim(htmlspecialchars($_POST['userdata'])); } 

	/*-- parentpk --*/
	$parentpk="";
	if (isset($_POST['parentpk'])) { $parentpk=trim(htmlspecialchars($_POST['parentpk'])); } 
	/*-- foreignkey --*/
	$foreignkey="";
	if (isset($_POST['foreignkey'])) { $foreignkey=trim(htmlspecialchars($_POST['foreignkey'])); } 

	/*-- extra parentpk --*/
	$extraparentpk="";
	if (isset($_POST['extraparentpk'])) { $extraparentpk=trim(htmlspecialchars($_POST['extraparentpk'])); } 
	/*-- extra foreignkey --*/
	$extraforeignkey="";
	if (isset($_POST['extraforeignkey'])) { $extraforeignkey=trim(htmlspecialchars($_POST['extraforeignkey'])); } 
	
	/* -- Soundex --*/
	$fulltextfield="";
	$soundex="false";
	if (isset($_POST['soundex'])) { $soundex=trim(htmlspecialchars($_POST['soundex'])); } 
	if (isset($_POST['fulltext-field'])) { $fulltextfield=trim(htmlspecialchars($_POST['fulltext-field'])); } 
	
	/*-- Spatial Data --*/
	$spatial_lat="";
	$spatial_lng="";
	$spatial_geopoint="";
	$spatial_distance="";
	$spatialSearch=false;
	if (isset($_POST['spatial_lat'])) { $spatial_lat=trim(htmlspecialchars($_POST['spatial_lat'])); } 
	if (isset($_POST['spatial_lng'])) { $spatial_lng=trim(htmlspecialchars($_POST['spatial_lng'])); } 
	if (isset($_POST['spatial_geopoint'])) { $spatial_geopoint=trim(htmlspecialchars($_POST['spatial_geopoint'])); } 
	if (isset($_POST['spatial_distance'])) { $spatial_distance=trim(htmlspecialchars($_POST['spatial_distance'])); } 
	if ((strlen($spatial_lat) > 0) && (strlen($spatial_lng) > 0) && (strlen($spatial_geopoint) > 0) && (strlen($spatial_distance) > 0)) {
		$spatialSearch=true;
	}

	/*-- sort --*/
	$orderby='';
	$sort='asc';
	if (isset($_POST['orderby'])) { $orderby=trim(htmlspecialchars($_POST['orderby'])); } 
	if (isset($_POST['sort'])) { $sort=trim(htmlspecialchars($_POST['sort'])); } 
	/*-- maxrows --*/
	$maxrows=0;
	if (isset($_POST['maxrows'])) { $maxrows=trim(htmlspecialchars($_POST['maxrows'])); } 
	$offset=0;
	if (isset($_POST['offset'])) { $offset=trim(htmlspecialchars($_POST['offset'])); } 

	/*-- Sql Connection --*/
	$dbCo = phpPdoConnect();
	if ($dbCo===false) {return; } //Error message is handled in function

	/*-- Get Service --*/
	$repeaterRequest='';
	$displayerRequest='';
	$customSQL='';
	$privilege_anonymous=4; //No access by default
	$privilege_admin=4;//No access by default
	$privilege_user=4;//No access by default
	$customService=0;
	try {
		$sql="Select * from _services where service=:service";
		$stmt = $dbCo->prepare($sql);
		$stmt->bindParam(':service', $service);
		$stmt->execute();
		if ($row = $stmt->fetch(PDO::FETCH_OBJ)) {
			$repeaterRequest=$row->request;
			$displayerRequest=$row->loadrecordsql;
			$customSQL=$row->custom_sql;
			$privilege_anonymous=$row->privilege_anonymous;
			$privilege_admin=$row->privilege_admin;
			$privilege_user=$row->privilege_user;
			$customService=$row->custom;
			$searchfield=$row->fulltextfield;
			if (strlen($fulltextfield)>0) {
				$searchfield=$fulltextfield;
			}


		} else {
			returnError(-1002, "Service ".$service." does not exist");
			return false;
		}
	} catch (PDOException $e) {
		returnError(-1002, "Unable to load Service ".$service.': '.$e->getMessage());
		return false;
	}

	//get user from token and check rights
	$user_pk="0";
	$user_uid="";
	$user_isanonymous="0";
	$user_admin="0";
	try {
		$sql="Select * from _auth where auth_token=:token";
		$stmt = $dbCo->prepare($sql);
		$stmt->bindParam(':token', $token);
		$stmt->execute();
		if ($row = $stmt->fetch(PDO::FETCH_OBJ)) {
			$user_pk=$row->pk;
			$user_uid=$row->uid;
			$user_isanonymous=$row->auth_anonymous;
			$user_admin=$row->auth_admin;
			$user_enabled=$row->auth_enabled;
		} else {
			returnError(-1010, "Invalid user token ".$token);
			return false;
		}
	} catch (PDOException $e) {
		returnError(-1002, "Unable to load user from token: ".$e->getMessage());
		return false;
	}
	/*-- Disabled User --*/
	if ( ($user_enabled=="0")) {
		returnError(-1011, "User is disabled");
		return false;
	}

	/*-- Access Rights --*/
	if ($user_isanonymous == 1) { /*-- Anonymous User --*/
		if ($privilege_anonymous ==4) {	returnError(-1011, "Insufficient privileges");return false;}
	} elseif ($user_admin == 1) { /*-- Admin --*/
		if ($privilege_admin==4) {returnError(-1011, "Insufficient privileges");return false;} 
	} else { /*-- Registred USer --*/
		if ($privilege_user==4) {returnError(-1011, "Insufficient privileges");return false;} 
	}

	//* -- SQL Request Construction -- */
	if ($customService >= 1) {	
		if ($operator1=="contains") {
			$operator1=" like ";
			$value1="%". $value1."%";
		}
		if ($operator2=="contains") {
			$operator2=" like ";
			$value2="%". $value2."%";
		}

		if ((strlen($operator1) > 0) && (strlen($field1) > 0) && (strlen($value1) > 0)) {
			if (strpos(strtolower($customSQL) , ' where ') == false) {
				$customSQL=$customSQL." where ". $field1 . $operator1 . "'" . $value1 . "' ";
			} else {
				$customSQL = str_ireplace(" where " ," where ".$field1 . $operator1 . "'" . $value1 . "' and ",$customSQL);
			}
		}
		if ((strlen($operator2) > 0) && (strlen($field2) > 0) && (strlen($value2) > 0)) {
			if (strpos(strtolower($customSQL) , ' where ') == false) {
				$customSQL=$customSQL." where ". $field2 . $operator2 . "'" . $value2 . "' ";
			} else {
				$customSQL = str_ireplace(" where " ," where ".$field2 . $operator2 . "'" . $value2 . "' and ",$customSQL);
			}
		}
	} else {  //Standard Service
		/*-- Additional criterians --*/
		if ((strlen($operator1) > 0) && (strlen($field1) > 0) && (strlen($value1) > 0)) {
			if ($value1=="{today}") {
				$h1=strtotime('today 00:00:00');
				$h2=strtotime('today 23:59:59');
				if ( ($operator1=="=") or ($operator1=="contains") ) {
					$repeaterRequest = $repeaterRequest ." and ".$field1." BETWEEN ".$h1." and ".$h2;
				} else if (($operator1==">") or ($operator1==">=") ) {
					$repeaterRequest = $repeaterRequest ." and ".$field1. $operator1.$h2." ";
				} else if (($operator1=="<") or ($operator1=="<=") ) {
					$repeaterRequest = $repeaterRequest ." and ".$field1. $operator1.$h1." ";
				}
				
			} else {
				if (($operator1=="contains") ) {
					$repeaterRequest = $repeaterRequest . " and " . $field1 . " like('%" . $value1 . "%') ";
				} else {
					$repeaterRequest = $repeaterRequest . " and " . $field1 . $operator1 . "'" . $value1 . "' ";
				}
			}	
		}
		if ((strlen($operator2) > 0) && (strlen($field2) > 0) && (strlen($value2) > 0)) {
			if ($value2=="{today}") {
				$h1=strtotime('today 00:00:00');
				$h2=strtotime('today 23:59:59');
				if ( ($operator2=="=") or ($operator2=="contains") ) {
					$repeaterRequest = $repeaterRequest ." and ".$field2." BETWEEN ".$h1." and ".$h2;
				} else if (($operator2==">") or ($operator2==">=") ) {
					$repeaterRequest = $repeaterRequest ." and ".$field2. $operator2.$h2." ";
				} else if (($operator2=="<") or ($operator2=="<=") ) {
					$repeaterRequest = $repeaterRequest ." and ".$field2. $operator2.$h1." ";
				} 
			} else {
				if (($operator2=="contains") ) {
					$repeaterRequest = $repeaterRequest . " and " . $field2 . " like('%" . $value2 . "%') ";
				} else {
					$repeaterRequest = $repeaterRequest . " and " . $field2 . $operator2 . "'" . $value2 . "' ";
				}
			}	
		}
		/*-- User owner data only --*/
		if ($userdata == 1) {
			if ($service=="_auth") {
				$repeaterRequest = $repeaterRequest . " and a.pk=:userpk ";
			} else {
				$repeaterRequest = $repeaterRequest . " and b.pk=:userpk ";
			}
			
		}

		//* -- Parent UID --*/
		if ((strlen($parentpk) > 0) && (strlen($foreignkey) > 0)) {
			$repeaterRequest = $repeaterRequest . " and a." . $foreignkey . "=:parentpk ";
		}  else	if ($service=="_objects") {
			$repeaterRequest = $repeaterRequest . " and a.fk_objects is null ";
		}
		
		/*-- Extra Foreign KEy (additional filter) -- */
		if ((strlen($extraparentpk) > 0) && (strlen($extraforeignkey) > 0)) {
			$repeaterRequest = $repeaterRequest . " and a." . $extraforeignkey . "=:extraparentpk ";
		}

		/*-- Full text --*/
		if ( (strlen($searchfield)>0) && (strlen($search)>0) ) {
			if (strpos($search,"*")>-1) {
				$search=str_replace("*","%",$search);
			}
			if (strpos($search,"%")>-1) {
				$repeaterRequest = $repeaterRequest . " and a.".$searchfield." like '".$search."' ";
			} else {
				$repeaterRequest = $repeaterRequest . " and a.".$searchfield." = '".$search."' ";
			}	
		}

		if ($spatialSearch==true) {
			$gp=explode(";",$spatial_geopoint);
			$lat=$gp[0];
			$lng=$gp[1];
			$r_earth=6357;
			$latmin  = $lat  - ($spatial_distance / $r_earth) * (180 / pi());
			$latmax  = $lat  + ($spatial_distance / $r_earth) * (180 / pi());
			$lngmin = $lng - ($spatial_distance / $r_earth) * (180 / pi()) / cos($lat * pi()/180);
			$lngmax = $lng + ($spatial_distance / $r_earth) * (180 / pi()) / cos($lat * pi()/180);
			$repeaterRequest = $repeaterRequest ." and ( ( a.".$spatial_lat." between ".$latmin." AND ".$latmax.")  and (a.".$spatial_lng." between ".$lngmin." and ".$lngmax.") ) ";
		}


		//Sorted by
		if (strlen($orderby) > 0) {
			$repeaterRequest = $repeaterRequest . " order by " . $orderby . " " . $sort;
		} else {
			$repeaterRequest = $repeaterRequest . " order by a.pk " . $sort;
		}
		//MaxRows (Limit)
		if ($maxrows > 0) {
			$repeaterRequest = $repeaterRequest . " limit " . $maxrows . " offset " . $offset;
		}
	} 

	
	/*-- execute service -- */
	try {
		if ($customService != 1) { 
			if (strlen($uid)>0) {
				$stmt = $dbCo->prepare($displayerRequest);
				$stmt->bindParam(':uid', $uid);
			} else {
				$stmt = $dbCo->prepare($repeaterRequest);
				if ( (strlen($parentpk)>0) && (strlen($foreignkey)>0) ) {
					$stmt->bindParam(':parentpk', $parentpk);
				}
				if ( (strlen($extraparentpk)>0) && (strlen($extraforeignkey)>0) ) {
					$stmt->bindParam(':extraparentpk', $extraparentpk);
				}
			}
		} else { //Custom SQL
			$stmt = $dbCo->prepare($customSQL);
		}

		if ($userdata==1) {
			$stmt->bindParam(':userpk',$user_pk);
		}
		$countrows=0;
		$rows=NULL;
		//$memory_limit = ini_get('memory_limit');
		$stmt->execute();
		while ($row = $stmt->fetch(PDO::FETCH_OBJ)) {
			unset($row->auth_password);
			if ($spatialSearch==true) {
				$gp=explode(";",$spatial_geopoint);
				$lat=$gp[0];
				$lng=$gp[1];
				$dist=haversineGreatCircleDistance($row->{$spatial_lat}, $row->{$spatial_lng},$lat,$lng)/1000;
				if ($dist>$spatial_distance) {

				} else {
					$row->spatial_distance=$dist;
					$rows[] = $row;
					$countrows=$countrows+1;
				}
			} else {
				$rows[] = $row;
				$countrows=$countrows+1;
			}			
			//if ($countrows>20000) {break;}  
			$mem=memory_get_usage(true);
			if ($mem>(134217728*0.5)) {break;} //134217728
		}
		
		try {
			$soundexSql="";
			$soundexresult=null;
			$fuzzyvalue="";
			//Phonetic search with similar_text()  
			if ( ($customService != 1) && (strlen($uid)==0) && ($countrows==0) && (strlen($search)>0) && (strlen($searchfield)>0) && ($soundex=="true")) { // && 
				$fuzzyKeyLength=2; 
				$soundexvalue=substr($search,0,$fuzzyKeyLength);
				$soundexSql="Select distinct ".$searchfield." from ".$service."  where ".$searchfield." like '".substr($search,0,$fuzzyKeyLength)."%' ";
				if ((strlen($parentpk) > 0) && (strlen($foreignkey) > 0)) {
					$soundexSql = $soundexSql . " and " . $foreignkey . "=:parentpk ";
				}
				if ((strlen($extraparentpk) > 0) && (strlen($extraforeignkey) > 0)) {
					$soundexSql = $soundexSql . " and " . $extraforeignkey . "=:extraparentpk ";
				}
				if ($userdata == 1) {
					$soundexSql = $soundexSql . " and a.createdby=:userpk ";
				}
				$stmt = $dbCo->prepare($soundexSql);
				if ( (strlen($parentpk)>0) && (strlen($foreignkey)>0) ) {
					$stmt->bindParam(':parentpk', $parentpk);
				}
				if ( (strlen($extraparentpk)>0) && (strlen($extraforeignkey)>0) ) {
					$stmt->bindParam(':extraparentpk', $extraparentpk);
				}
				if ($userdata==1) {
					$stmt->bindParam(':userpk',$user_pk);
				}
				$stmt->execute();
				$maxScore=0;
				while ($row = $stmt->fetch(PDO::FETCH_OBJ)) {
					unset($row->auth_password);
					$item=$row->{$searchfield};	
					similar_text($item,$search,$score); 
					if ($score>$maxScore) {
						$maxScore=$score;
						$fuzzyvalue=$item;
					}			
				}
			}
		} catch (PDOException $e) {
			returnError(-1002, "Unable to get Soundex Data ".$e->getMessage());
			return false;
		}

		header("Content-Type: application/json; charset=UTF-8");
		/* -- Object returned decalaration --*/
		$obj = new stdClass();
		$obj->code=0;
		$obj->message="Returned Results";
		$obj->result=$rows;
		$obj->count=$countrows;
		$obj->soundex=$fuzzyvalue;
		echo safe_json_encode($obj);
		return;
	} catch (PDOException $e) {
		returnError(-1002, "Unable to get Service ".$e->getMessage());
		return false;
	}
?>