<?php

// similar to java startsWith
function startsWith($haystack, $needle) {
  return (strpos($haystack, $needle) === 0);
}

// similar to java endsWith
function endsWith($haystack, $needle) {
   return (strpos(strrev($haystack), strrev($needle)) === 0);
}

function lang2code($lang){
	if ($lang == "arabic")
		return "ar";
	else if ($lang == "english")
		return "en";
	else if ($lang == "french")
		return "fr";
	else if ($lang == "spanish")
		return "es";
	else if ($lang == "indonesian")
		return "id";
	else if ($lang == "urdu")
		return "ur";
}

function getUserActions($username){
	$actionXml = new DOMDocument();
	$path = __DIR__ . "/../actions.xml";
	$actionXml->load($path);
	$actionXPathXml = new DOMXpath($actionXml);
	$actionElements = $actionXPathXml->query("/actions/user[@username=\"$username\"]/action");
	return $actionElements;
}

function getList($listName){
	$actionXml = new DOMDocument();
	$actionXml->load($_SERVER['DOCUMENT_ROOT'] . "/iventitymatcherhtm/xml_example/WLMSG0.xml");
	$actionXPathXml = new DOMXpath($actionXml);
	$actionElements = $actionXPathXml->query("/IVEnvelope/Request/LoadWatchList/InputParameters/WatchList[@name=\"$listName\"]/Entities/Entity/Names/Name");

	return $actionElements;
}


function sendRequestToServer($out, $serverId="127.0.0.1")
{
	global $errorcode;
	global $errormsg;
	$numRetries = 0;
	$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

	if ($socket === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);

		return false;
	}

	$result = socket_connect($socket, $serverId, 40000);

	if ($result === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);
		return false;
	}
	//Dosen't work on windows platform
	//$result = socket_send($socket, $out, strlen($out), MSG_EOF);
	$result = socket_write($socket, $out, strlen($out));
	if ($result === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);
		return false;
	}

	$rval = socket_set_option($socket,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>5, "usec"=>0));
	$output="";
	while ($numRetries++ < 50){
		set_time_limit(30); //extend the time limit
		$read = socket_read($socket, 1024);
		if ($read === false)
		{
			$errorcode = socket_last_error($socket);
			if ($errorcode == ETIMEDOUT || $errorcode == 10060)
				continue;

				$errormsg = socket_strerror($errorcode);
				return false;
		}
		$output = $output . $read;
		$ending = strpos($output, "</IVEnvelope>");
		if ($ending !== false) //|| strlen($output) == 0)
			break;
	}

	socket_close($socket);

	return $output;
}

function getVersion()
{
	$out = "<IVEnvelope><Request id=\"13\"><getVersion/></Request></IVEnvelope>";
	return sendRequestToServer($out);
}

function getMaxId($name, $serverIp="127.0.0.1")
{
    $out = "<IVEnvelope><Request id=\"5\"><getMaxId><InputParameters><Name>";
    $out .= "<value>$name</value></Name></InputParameters></getMaxId></Request></IVEnvelope>";
    
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    
    if ($socket === false)
    {
        $errorcode = socket_last_error();
        $errormsg = socket_strerror($errorcode);
        
        return false;
    }
    
    $result = socket_connect($socket, $serverIp, 40000);
    
    if ($result === false)
    {
        $errorcode = socket_last_error();
        $errormsg = socket_strerror($errorcode);
        return false;
    }
    //Dosen't work on windows platform
    //$result = socket_send($socket, $out, strlen($out), MSG_EOF);
    $result = socket_write($socket, $out, strlen($out));
    if ($result === false)
    {
        $errorcode = socket_last_error();
        $errormsg = socket_strerror($errorcode);
        return false;
    }
    
    $rval = socket_set_option($socket,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>5, "usec"=>0));
    $output="";
    $waitSec = 5;
    while (true){
        //$rval = socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 5, 'usec' => 0));
        $output = $output . socket_read($socket, 1024);
        $ending = strpos($output, "</IVEnvelope>");
        if ($ending !== false) //|| strlen($output) == 0)
            break;
            if (empty($output))
            {
                $waitSec -= 1;
            }
            if ($waitSec == 0)
            {
                $errormsg = "timed out";
                return false;
            }
    }
    
    socket_close($socket);
    
    $xml = simplexml_load_string($output);
    
    $maxId = $xml->Reply->getMaxId[0];
    
    return (string) $maxId;
}


function loadList($filePath, $listFile, $serverIp="127.0.0.1", $data_compressed = false, $isAppend=FALSE, $maxId = null){
    return loadListExt($filePath, $listFile, NULL, $serverIp, $data_compressed , $isAppend, $maxId);
}

function loadListExt($filePath, $listFile, $digestRdf, $serverIp="127.0.0.1", $data_compressed = false, $isAppend=FALSE, $maxId = null){
    $xml = convertTsvAndDigestRdfToXml($filePath,$listFile, $digestRdf, $data_compressed, $isAppend, $maxId);

	$out = $xml;
	global $errorcode;
	global $errormsg;
	$numRetries = 0;
	$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

	if ($socket === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);

		return false;
	}

	$result = socket_connect($socket, $serverIp, 40000);
	
	if ($result === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);
		return false;
	}
	//Dosen't work on windows platform
	//$result = socket_send($socket, $out, strlen($out), MSG_EOF);
	$result = socket_write($socket, $out, strlen($out));
	if ($result === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);
		return false;
	}

	$rval = socket_set_option($socket,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>5, "usec"=>0));
	$output="";
	while ($numRetries++ < 50){
		set_time_limit(30); //extend the time limit
		$read = socket_read($socket, 1024);
		if ($read === false)
		{
			$errorcode = socket_last_error($socket);
			if ($errorcode == ETIMEDOUT || $errorcode == 10060)
				continue;

			$errormsg = socket_strerror($errorcode);
			return false;
		}
		$output = $output . $read;
		$ending = strpos($output, "</IVEnvelope>");
		if ($ending !== false) //|| strlen($output) == 0)
			break;
	}

	socket_close($socket);

	return true;

}

function deleteWatchList($wlName, $serverIp="127.0.0.1")
{
	global $errorcode;
	global $errormsg;
	$out = "<IVEnvelope><Request id=\"5\"><DeleteWatchList><InputParameters><Name>";
	$out .= "<value>$wlName</value></Name></InputParameters></DeleteWatchList></Request></IVEnvelope>";

	$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

	if ($socket === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);

		return false;
	}

	$result = socket_connect($socket, $serverIp, 40000);

	if ($result === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);
		return false;
	}
	//Dosen't work on windows platform
	//$result = socket_send($socket, $out, strlen($out), MSG_EOF);
	$result = socket_write($socket, $out, strlen($out));
	if ($result === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);
		return false;
	}

	$rval = socket_set_option($socket,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>5, "usec"=>0));
	$output="";
	$waitSec = 5;
	while (true){
		//$rval = socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 5, 'usec' => 0));
		$output = $output . socket_read($socket, 1024);
		$ending = strpos($output, "</IVEnvelope>");
		if ($ending !== false) //|| strlen($output) == 0)
			break;
		if (empty($output))
		{
			$waitSec -= 1;
		}
		if ($waitSec == 0)
		{
			$errormsg = "timed out";
			return false;
		}
	}

	socket_close($socket);

	$xml = simplexml_load_string($output);

	$ExecutionStatus = $xml->Reply->DeleteWatchList->ExecutionStatus;
	$ExecutionCode = (string)$ExecutionStatus->ExecutionCode;
	$ExecutionMessage = (string)$ExecutionStatus->ExecutionMessage;

	if ($ExecutionCode != "0" || $ExecutionMessage != "OK")
	{
		$errormsg = "Unexpected execution code: $ExecutionCode, message: $ExecutionMessage";
		return false;
	}
	else
		return true;
}

function getListOfWatchList($serverIp="127.0.0.1")
{
	$out = "<IVEnvelope><Request id=\"5\"><getListOfWatchList>";
	$out .= "</getListOfWatchList></Request></IVEnvelope>";

	$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

	if ($socket === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);

		return false;
	}

	$result = socket_connect($socket, $serverIp, 40000);

	if ($result === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);
		return false;
	}
	//Dosen't work on windows platform
	//$result = socket_send($socket, $out, strlen($out), MSG_EOF);
	$result = socket_write($socket, $out, strlen($out));
	if ($result === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);
		return false;
	}

	$rval = socket_set_option($socket,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>5, "usec"=>0));
	$output="";
	$waitSec = 5;
	while (true){
		$output = $output . socket_read($socket, 1024);
		$ending = strpos($output, "</IVEnvelope>");
		if ($ending !== false) //|| strlen($output) == 0)
			break;
		if (empty($output))
		{
			$waitSec -= 1;
		}
		if ($waitSec == 0)
			return false;
	}

	socket_close($socket);

	$xml = simplexml_load_string($output);

	$mainReplyElement = $xml->Reply->getListOfWatchList;

	$ExecutionStatus = $mainReplyElement->ExecutionStatus;
	$ExecutionCode = (string)$ExecutionStatus->ExecutionCode;
	$ExecutionMessage = (string)$ExecutionStatus->ExecutionMessage;

	if ($ExecutionCode != "0" || $ExecutionMessage != "OK")
		return false;
	else
	{
		$wl_array = array();
		$wl = $mainReplyElement->OutputParameters->Lists->List;
		$i = 0;
		foreach ($wl as $list)
		{
			$wl_array[$i++] = (string)$list;//->attributes();
		}
		return $wl_array;
	}

}
function searchEntity($searchtext,$textAnalaysed, $type, $wlSelected, $serverIp="127.0.0.1", $v2 = false)
{
    $idCol = $v2 ? "ID" : 'person_input_id';
    $nameCol = $v2 ? "Name" : 'person_input_name';
    
	if (empty($wlSelected))
		return false;

	$query = "/IVEnvelope/Request/LoadWatchList/InputParameters/WatchList";
	//$filePath = "I:/apps/entitymatcher/tmp/";
	$filePath = __DIR__.DIRECTORY_SEPARATOR."upload_file".DIRECTORY_SEPARATOR;

	$listName = $wlSelected;//getWatchListName($filePath. "Watchlist.xml",$query);

	if ($type == "sourceFile")
		$out = fileToXml($searchtext,$listName);
	else
		$out = nameToXml($searchtext,$listName, $type);

	$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

	if ($socket === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);

		return false;
	}

	$result = socket_connect($socket, $serverIp, 40000);

	if ($result === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);
		return false;
	}
	//Dosen't work on windows platform
	//$result = socket_send($socket, $out, strlen($out), MSG_EOF);
	$result = socket_write($socket, $out, strlen($out));
	if ($result === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);
		return false;
	}

	$rval = socket_set_option($socket,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>5, "usec"=>0));
	$output="";
	while (true){
		//$rval = socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 5, 'usec' => 0));
		$output = $output . socket_read($socket, 1024);
		$ending = strpos($output, "</IVEnvelope>");
		if ($ending !== false) //|| strlen($output) == 0)
			break;
	}
	//print_r($output);

	//check if load successed
	$xml = simplexml_load_string($output);

	$mainReplyElement = $xml->Reply->MatchEntity;
	if (empty($mainReplyElement))
		$mainReplyElement = $xml->Reply->MatchEntityList;

	$ExecutionStatus = $mainReplyElement->ExecutionStatus;
	$ExecutionCode = (string)$ExecutionStatus->ExecutionCode;
	$ExecutionMessage = (string)$ExecutionStatus->ExecutionMessage;

	if ($ExecutionCode != "0" || $ExecutionMessage != "OK")
		return false;

	$resultId = array();
	$Matches = $mainReplyElement->OutputParameters->Matches->Match;
	$k = 0;

	foreach ($Matches as $match)
	{
		$arr = array();

		$person_input_id = (string)$match->attributes()->id;
		$person_input_name = (string)$match->attributes()->name;
      
     
        $arr[$idCol] = $person_input_id;
        $arr[$nameCol] = $person_input_name;            
        
        $arr['Rules'] = array();
        
	
		$i = 0;
		#obsolete code

		foreach($match->Rule as $rule)
		{
			$arr['Rules'][(string)$rule->attributes()->id] = array();
			#$arr[$i]['name'] = (string)$person->personId;
			$j = 0;
			foreach($rule->Person as $person)
			{
				$arr['Rules'][(string)$rule->attributes()->id][$j] = array();
				$arr['Rules'][(string)$rule->attributes()->id][$j][$idCol] = (string)$person->attributes()->id;
				$arr['Rules'][(string)$rule->attributes()->id][$j][$nameCol] = (string)$person->attributes()->name;
				$j++;
			}
			$i++;
		}
		$resultId[$k] = $arr;
		$k++;
	}

	$result = $resultId;
	//$result = getConfidence(getNameFromId($resultId),$textAnalaysed);

	//TODO : handle return false on failure
	socket_close($socket);

	return $resultId;
}

function analayzeFile(){
    return getAnalysis();
}

function searchListOfEntity($searchtext,$textAnalaysed, $type, $wlSelected, $serverIp="127.0.0.1", $v2 = false)
{
    $idCol = $v2 ? "ID" : 'person_input_id';
    $nameCol = $v2 ? "Name" : 'person_input_name';
    
	$query = "/IVEnvelope/Request/LoadWatchList/InputParameters/WatchList";
	//$filePath = "I:/apps/entitymatcher/tmp/";
	$filePath = __DIR__.DIRECTORY_SEPARATOR."upload_file".DIRECTORY_SEPARATOR;

	$listName = $wlSelected;//getWatchListName($filePath. "Watchlist.xml",$query);

	$out = fileToXmlData($searchtext,$listName, $v2);

	$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

	if ($socket === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);

		return false;
	}

	$result = socket_connect($socket, $serverIp, 40000);
	socket_set_nonblock($socket);
	
	if ($result === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);
		return false;
	}
	//Dosen't work on windows platform
	//$result = socket_send($socket, $out, strlen($out), MSG_EOF);
	$result = socket_write($socket, $out, strlen($out));
	if ($result === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);
		return false;
	}

	$rval = socket_set_option($socket,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>5, "usec"=>0));
	$output="";
	while (true){
		//$rval = socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 5, 'usec' => 0));
		$output = $output . socket_read($socket, 1024);
		$ending = strpos($output, "</IVEnvelope>");

		if ($ending !== false) //|| strlen($output) == 0)
			break;
	}
	//print_r($output);

	//check if load successed
	$xml = simplexml_load_string($output);

	$mainReplyElement = $xml->Reply->MatchEntity;
	if (empty($mainReplyElement))
	    $mainReplyElement = $xml->Reply->MatchEntityListData;

	$ExecutionStatus = $mainReplyElement->ExecutionStatus;
	$ExecutionCode = (string)$ExecutionStatus->ExecutionCode;
	$ExecutionMessage = (string)$ExecutionStatus->ExecutionMessage;

	if ($ExecutionCode != "0" || $ExecutionMessage != "OK")
		return false;

	$resultId = array();
	$Matches = $mainReplyElement->OutputParameters->Matches->Match;
	$k = 0;

	foreach ($Matches as $match)
	{
		$arr = array();

		$person_input_id = (string)$match->attributes()->id;
		$person_input_name = (string)$match->attributes()->name;

	
		
		$arr[$idCol] = $person_input_id;
		$arr[$nameCol] = $person_input_name;
		$arr['Rules'] = array();

		$i = 0;
		#obsolete code

		foreach($match->Rule as $rule)
		{
			$arr['Rules'][(string)$rule->attributes()->id] = array();
			#$arr[$i]['name'] = (string)$person->personId;
			$j = 0;
			foreach($rule->Person as $person)
			{
				$arr['Rules'][(string)$rule->attributes()->id][$j] = array();
				$arr['Rules'][(string)$rule->attributes()->id][$j][$idCol] = (string)$person->attributes()->id;
				$arr['Rules'][(string)$rule->attributes()->id][$j][$nameCol] = (string)$person->attributes()->name;
				$j++;
			}
			$i++;
		}
		$resultId[$person_input_id] = $arr;
		$k++;
	}

	$result = $resultId;
	//die(print_r($resultId));

	//$result = getConfidence(getNameFromId($resultId),$textAnalaysed);


	$out = print_r($result, true);
	/*$myFile = "c:/testFile.txt";
	$fh = fopen($myFile, 'w');
	fwrite($fh, $out);
	fclose($fh);*/
	//TODO : handle return false on failure
	socket_close($socket);

	return $result;
}

function getConfidence($searchResult, $searchName)
{
	#first, remember how many different GN, FN etc we have in the input search name
	$inputCounts = array();
	foreach ($searchName['Name Alternatives'] as $name)
	{
		foreach ($name as $k => $v)
		{
			if (!array_key_exists($v, $inputCounts[$k]))
				$inputCounts[$k]['count']++;

			$inputCounts[$k][$v] = '1';
		}
	}

	#go over all alternatives (input and results) and calc the maximal confidence
	foreach ($searchResult as &$arr)
	{
		foreach ($arr as &$value)
		{
			$maxConf = 0;
			foreach ($value['slot']['Name Alternatives'] as $naI => &$naKV)
			{
				$naMaxConf = 0;
				foreach ($searchName['Name Alternatives'] as $name)
				{
					#for each name part (GN, FN...) remember the input value and the person (search result) value
					$naArr = array();
					foreach ($name as $k => $v)
					{
						$naArr[$k]['input'] = $v;
					}
					foreach ($naKV as $naK => $naV)
					{
						$naArr[$naK]['person'] = $naV;
					}
					#count how many name components we have, and how many of them matched (divided by count of different values of input component)
					$numComponents = 0;
					$matchcomponents = 0;
					foreach ($naArr as $naArrK => $naArrV)
					{
						$numComponents++;
						if ($naArrV['person'] != null && $naArrV['input'] != null && $naArrV['person'] == $naArrV['input'])
							$matchcomponents+= (1 / $inputCounts[$naArrK]['count']);
					}
					$currConf = 0;
					if ($numComponents > 0) $currConf = $matchcomponents * 100 / $numComponents;
					if ($currConf > $naMaxConf)
						$naMaxConf = $currConf;

					if ($currConf > $maxConf)
						$maxConf = $currConf;
				}
				$naKV['Confidence'] = intval($naMaxConf);
			}

			$value['slot']['Confidence'] = intval($maxConf);
		}
	}
	return $searchResult;
}

function mergeResultNAs($searchResult)
{
	#go over all alternatives
	foreach ($searchResult as &$arr)
	{
		foreach ($arr as &$value)
		{
			uasort($value['slot']['Name Alternatives'], "confidenceComp");

			$numMerged = 1;
			while ($numMerged > 0)
			{
				$numMerged = mergeNAs($value['slot']['Name Alternatives']);
			}
		}
	}
	return $searchResult;
}

function mergeEthnicitySlot($left, $right) : string
{
    $list= str_replace(array("(",")"), "%", "$left $right");
    $expl= explode('%', $list);
    $merged = [];
    $key = null;
    foreach($expl as $value) {
        $cvalue= trim($value);
        if(!empty($cvalue)) {
            if(empty($key)) {
                $key = $cvalue;
            } else {
                $merged[$key]= isset($merged[$key])? max($merged[$key], $cvalue) : $cvalue; //merge by taking the max
                $key= null;
            }
        }
    }
    $result = "";
    foreach($merged as $key => $value) {
        $result.= sprintf("%s (%d%%) ", $key, $value);
    }
    return $result;
}

//obs - function to merge array to another same caption array in array of arrays - return the index of the 2th one
function findAndMerge($test_index, &$test_arr, $arr_arrays){
    $index = 0;
    foreach($arr_arrays as $curr_arr){
        if($test_index == $index){
            $index++;
            continue;
        }
        if($curr_arr["caption"] == $test_arr["caption"]){
           $test_arr = array_merge($curr_arr, $test_arr);
           return $index;
        }
        $index++;
    }
    return -1;
}

function mergeNAs(&$NAs)
{
	$numMerged = 0;
	$nameAlts = array();
	$changedNaKeys = array();
	$commonSlots2NA = array();
	foreach ($NAs as $naI => &$naKV)
	{
		$naMerged = false;
		$commonSlots = array();
		foreach ($naKV as $naK => $naV)
		{
			#create a common slot key - containing keys/values of all slots, except value of current slot
			$commonSlotKey = "";
			foreach ($naKV as $naK1 => $naV1)
			{
				$commonSlotKey .= $naK1 . ":";
				if ($naK1 != $naK)
					$commonSlotKey .= $naV1;

				$commonSlotKey .= ";";
			}
			#if found similar NA (except for one slot) - concatenate the different slot
			$targetNaI = array_key_exists($commonSlotKey, $commonSlots2NA)? $commonSlots2NA[$commonSlotKey] : null;
			if ((string)$targetNaI!=null &&
				((!array_key_exists($targetNaI, $changedNaKeys)) || ($changedNaKeys[$targetNaI] == $commonSlotKey)))
			{
				$changedNaKeys[$targetNaI] = $commonSlotKey;
                                if($naK != "ethnicity") {
                                    $nameAlts[$targetNaI][$naK] .= " <br/> " . $naV;
                                } else {
                                    $nameAlts[$targetNaI][$naK] = " <br/> " . mergeEthnicitySlot($nameAlts[$targetNaI][$naK], $naV);
                                }
				//$commonSlots2NA[$commonSlotKey][$naK]
				#echo "merged:".$naI." into:".$targetNaI.",common key:".$commonSlotKey.","."key:".$naK.",target key:".$nameAlts[$targetNaI][$naK]."<BR/>";
				$naMerged = true;
				$numMerged++;
				break;
			}
			else
			{
				//echo "na not merged yet<br/>";
				array_push($commonSlots, $commonSlotKey);
			}

		}
		if (!$naMerged)
		{
			#echo "not merged: ".$naI."<br/>";
			#add new name alternative and remember its common slots
			$nameAlts[$naI] = $naKV;
			foreach ($commonSlots as $slot)
				$commonSlots2NA[$slot] = $naI;
		}

	}
	if ($numMerged == 0)
		return 0;

	#re-create name alternatives using merged NAs
	$NAs = array();
	$i = 1;
	foreach ($nameAlts as $naI => $na)
	{
		#echo "hey";
		$NAs[$i++] = $na;
	}
	return $numMerged;
}

function confidenceComp($a, $b) {
	#echo "b conf: ";
	return $a['Confidence'] < $b['Confidence'] ? 1 : -1;
}

function getNameFromId($resultId)
{
    global $ivEntityMatcherService;
    $actionXml = new DOMDocument();
	$actionXml->load(__DIR__.DIRECTORY_SEPARATOR."upload_file".DIRECTORY_SEPARATOR."Watchlist.xml");
	$actionXPathXml = new DOMXpath($actionXml);

	foreach ($resultId as &$arr)
	{
		foreach ($arr as &$value)
		{
			$id = $value['name'];
			$nameValue = $value['personName'];
			if ($nameValue == null)
			{
				$actionElements = $actionXPathXml->query("/IVEnvelope/Request/LoadWatchList/InputParameters/WatchList/Entities/Entity[@id=\"$id\"]/Names/Name");

				if ($actionElements->length == 1)
				{
					$element = $actionElements->item(0);
					$nameValue = $element->nodeValue;
				}
			}
			if ($nameValue != null)
			{
				$value['name'] = $nameValue;
				$anl = getAnalysis($nameValue,$ivEntityMatcherService);
				$value['slot'] = array();
				//$value['slot'][$language] = $languageVal;
				$value['slot']['Caption'] = $anl['caption'];
				$value['slot']['Ethnicity'] = $anl['ethnicity'];
				$value['slot']['Name Alternatives'] = array();

				$i = 0;
				foreach ($anl['Name Alternatives'] as $name)
				{
					foreach ($name as $k => $v)
					{
						$value['slot']['Name Alternatives'][$i][$k] = $v;
					}
					$i++;
				}
			}
		}
	}

	return $resultId;
}

function getValueOfKey($key, $analysis, $value)
{
    $conf = "";
	//handle the ethnicity of an unknown_name_role separately
	if($key === "unknown_name_role" && array_key_exists('ethnicity', $analysis)) {
		$n = sscanf($analysis['ethnicity'], "[__Instance:%s _Statistical-confidence:%d]", $value, $conf);
		$conf=" ($conf%)";
	}
	return rtrim($value,',') . $conf;
}

function printAnalysis($analysis, $name="")
{
	global $returnRawResults;
	if ($returnRawResults)
	{
		echo $analysis;
		exit();
	}

	if (!empty($analysis)){
		echo "<b>Analysis of " . $name . "</b><br>";
		echo "<table>";
		$i = 1;
		$numMerged = 1;
		while ($numMerged > 0)
		{
			$numMerged = mergeNAs($analysis['Name Alternatives']);
			//break;
		}
		foreach ($analysis['Name Alternatives'] as $na)
		{
			echo "<tr>";
			echo "<td style=\"color:red;\">";
					echo "Name Alternative ";// . $i++;
				echo "</td>";
				echo "<td>";
				echo "</td>";
			echo "</tr>";
				$na = arrangeSlots($na);
				foreach ($na as $key=>$value) {
					echo "<tr>";
						echo isWarning($key);//"<td>";
						echo getDisplayableName($key);
						echo "</td>";
						echo isWarning($key);//"<td>";
						echo getValueOfKey($key, $analysis, $value);
						if ($key === "ethnicity" || $key === "unknown_name_role") {
							echo " <small style='color:red;cursor:pointer' class=\"mapEthnicityClick\" data-ethnicity=\"" . getValueOfKey($key, $analysis, $value) ."\">MAP</small>";
						}
						echo "</td>";
					echo "</tr>";
				}
		}
		echo "<table>";
	}
}

function isWarning($key){  
    $isWarning = strcmp("warning",$key);
    if($isWarning == 0){
      return  "<td style=\"color:mediumvioletred;\">";
    }
    return "<td>";
}

function getAnalysis($name, $serverIp="127.0.0.1", $resultType="xml")
{
	global $errorcode;
	global $errormsg;
        global $error;
	$errorcode = $errormsg = $error = NULL;

	if (empty($name))
		return array();

	if (empty($resultType))
		$resultType = "xml";

	$out = "<IVEnvelope><Request id=\"3\"><GetAnalysis><InputParameters><ResultType value=\"$resultType\"/><Name>";
	$out .= "<value>$name</value></Name></InputParameters></GetAnalysis></Request></IVEnvelope>";

	$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

	if ($socket === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);

		return false;
	}

	$result = socket_connect($socket, $serverIp, 40000);
	socket_set_nonblock($socket);
	
	if ($result === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);
		return false;
	}
	//Dosen't work on windows platform
	//$result = socket_send($socket, $out, strlen($out), MSG_EOF);
	$result = socket_write($socket, $out, strlen($out));
	if ($result === false)
	{
		$errorcode = socket_last_error();
		$errormsg = socket_strerror($errorcode);
		return false;
	}

	$rval = socket_set_option($socket,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>5, "usec"=>0));
	$output="";
	$startReadingResponse = time();
	while (true){
		//$rval = socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 5, 'usec' => 0));
		$output = $output . socket_read($socket, 1024);
		$ending = strpos($output, "</IVEnvelope>");
		if ($ending !== false) //|| strlen($output) == 0)
			break;

		if (time() > $startReadingResponse + 25)
			return false;
	}

	socket_close($socket);

	//check if load successed

	//STAB - TODELETE
	//$output = file_get_contents("C:/xampp/htdocs/iventitymatcherhtm/upload_file/analysis/get_analysis_reply.txt");
	global $returnRawResults;
	if ($returnRawResults)
	{
		return $output;
	}

	$xml = simplexml_load_string($output);

	$ExecutionStatus = $xml->Reply->GetAnalysis->ExecutionStatus;
	$ExecutionCode = (string)$ExecutionStatus->ExecutionCode;
	$ExecutionMessage = (string)$ExecutionStatus->ExecutionMessage;
        $NameValidationsError =(string)$xml->Reply->GetAnalysis->NameValidationsError;
	if ($ExecutionCode != "0" || $ExecutionMessage != "OK")
		return false;  
		//TODO : handle return false on failure
        
	$res = array();
    if($NameValidationsError != ""){
        $res['error'] = $NameValidationsError;
        $error = $NameValidationsError;
    }
	$analysis = $xml->Reply->GetAnalysis->OutputParameters->Analysis;
	$res['caption'] = (string)$analysis->caption;
	$res['ethnicity'] = (string)$analysis->ethnicity;
	$nameAlternatives = $analysis->name_alternatives;
	$res['Name Alternatives'] = array();
		
	$i = 0;
	foreach ($nameAlternatives as $nameAlternative)
	{
		$res['Name Alternatives'][$i] = array();
		foreach ($nameAlternatives->name_alternative as $key => $value)
		{
		  	foreach ($value as $element) {
		    	$tag = $element->getName();
		    	if($tag == 'unknown_name_role'){
		    	    $res['Name Alternatives'][$i]['warning'] =  "No Analysis";
		    	}
		    	$res['Name Alternatives'][$i][$tag] =  trim($element);
		  	}
		  	
		  	$res['Name Alternatives'][$i]['caption-ic'] = (string)$analysis->{'transliteration-ic'};
		  	
		  	$i++;
		}
	}

	return $res;
}

function nameToXml($value,$listName, $type)
{
	$xml = "<IVEnvelope><Request id=\"3\"><MatchEntity><InputParameters><WatchList name=\"$listName\"/>";
	$xml .= "<Entity type=\"$type\" id=\"0\"><Names><Name>";
	$xml .= "<value>$value</value>";
	$xml .= "</Name></Names></Entity>";
	$xml .= "</InputParameters></MatchEntity></Request></IVEnvelope>";
	return $xml;
}

function fileToXml($value,$listName)
{
	$xml = "<IVEnvelope><Request id=\"4\"><MatchEntityList><InputParameters><WatchList name=\"$listName\"/>";
		$xml .= "<SourceFile>$value</SourceFile>";
	$xml .= "</InputParameters></MatchEntityList></Request></IVEnvelope>";
	return $xml;
}

function fileToXmlData($value,$listName, $v2 = null)
{
    $data = $v2 ? $value : base64_encode (file_get_contents($value));
    $xml = "<IVEnvelope><Request id=\"4\"><MatchEntityListData><InputParameters><WatchList name=\"$listName\"/>";
    $xml .= "<SourceData>$data</SourceData>";
    $xml .= "</InputParameters></MatchEntityListData></Request></IVEnvelope>";
    return $xml;
}

function getWatchListName($watchListfile,$query)
{
	$actionXml = new DOMDocument();
	$actionXml->load($watchListfile);
	$actionXPathXml = new DOMXpath($actionXml);
	$actionElements = $actionXPathXml->query($query);

	$name = "NA";
	if ($actionElements)
		if ($actionElements->item(0))
			if ($actionElements->item(0)->hasAttributes())
				$name = $actionElements->item(0)->getAttribute("name");

	return $name;
}

/*function convertTsvToXml($filePath,$listFile)
{
	$ret = explode( '.', $listFile);
	$cmd = "C:/xampp/htdocs/iventitymatcherhtm/upload_file/convertTsvToXml.exe " . $filePath . $listFile .  " " . $ret[0];
	exec($cmd,$output,$res);
	return $res;
}*/


function escapeXml($string) {
    return strtr(
        $string,
        array(
            "<" => "&lt;",
            ">" => "&gt;",
            '"' => "&quot;",
            "'" => "&apos;",
            "&" => "&amp;",
        )
    );
}

/*function escapeXml($str)
{
	$doc = new DOMDocument();
	$fragment = $doc->createDocumentFragment();

	// adding XML verbatim:
	//$xml = "Test &amp; <b> and encode </b> :)\n";
	//$fragment->appendXML($xml);

	// adding text:
	//$text = $xml;
	$fragment->appendChild($doc->createTextNode($str));

	// output the result
	return $doc->saveXML($fragment);
}*/

function convertTsvToXml($filePath,$listFile,$isAppend=FALSE)
{
	return convertTsvAndDigestRdfToXml($filePath, $listFile, NULL, NULL, $isAppend);
}

function convertTsvAndDigestRdfToXml($filePath,$listFile, $digestRdf, $data_compressed = false, $isAppend=FALSE, $maxId = null)
{

	$listName = explode(".",$listFile);
	$fixed_name = str_replace(' ', '_', $listName[0]);

	$xml_begin = "<IVEnvelope><Request id=\"1\"><LoadWatchList><InputParameters>";
	$xml_end = "</Entities>$digestRdf</WatchList></InputParameters></LoadWatchList></Request></IVEnvelope>";

	$xml = $xml_begin. "<WatchList id=\"0\" name=\"$fixed_name\">";
	if ($isAppend)
		$xml .= "<Parameters><Parameter name=\"appendToWatchList\" value=\"yes\"/></Parameters>";

	$xml .= "<Entities>";

	if(!empty($data_compressed)){
	    $data = base64_decode($data_compressed);
	    $i = $maxId ? $maxId+1 :  0;
	    $entities_data = "";
	    foreach(preg_split("/((\r?\n)|(\r\n?))/", $data) as $line_of_text){ 
	        $entities_data .= getEntityXmlData($line_of_text, $i);
	    }
	    $compressed_xml = gzencode($entities_data); //gzcompress
	    $base64_xml = base64_encode($compressed_xml); //base64 encode
	    $xml .= "<compressed><xml>".$base64_xml."</xml></compressed>";
	}
	else{
	    $file_handle = fopen($filePath.$listFile, "r");
	    $i = 1;
	    while ($file_handle && !feof($file_handle) ) {
	        $line_of_text = trim(fgets($file_handle,1024), "\r\n");        
	        $xml .= getEntityXmlData($line_of_text, $i);
	    }
 
	    fclose($file_handle);
	}
	
	$xml .= $xml_end;
	return $xml;

}

function getEntityXmlData($line_of_text, &$i){
    $xml = "";
    $line_arr = explode("\t", $line_of_text);
    if (sizeof($line_arr) == 1) {
        $xml .= "<Entity type=\"person\" id=\"$i\"><Names><Name>";
        $xml .= "<value>".htmlspecialchars($line_of_text)."</value>";
    }
    else {
        //in case digest instance name is known
        $instNameAttrStr = sizeof($line_arr)==2? "" : " instanceName=\"$line_arr[2]\"";
        $xml .= "<Entity type=\"person\" id=\"$line_arr[0]\"" . $instNameAttrStr . "><Names><Name>";
        $xml .= "<value>".htmlspecialchars($line_arr[1])."</value>";
    }
    
    $xml .= "</Name></Names></Entity>";
    $i++;
    return $xml;
}

function isUserDefinedPackage($package){
	if (substr($package, 0, 1) == '@')
		return true;
	else
		return false;
}

//$slotNames = array(
//	'caption' => "Full Name",
//	'kunya' => null,
//	'nickname' => null,
//	'given_name' => null,
//	'middle_name' => null,
//	'middle_name_second' => null,
//	'middle_name_third' => null,
//	'western_maiden_name' => 'Maiden Name',
//	'father_patrimonyal_name' => 'Patronymic',
//	'grandfather_patrimonyal_name' => 'Patronymic (Grandfather)',
//	'great_grandfather_patronymic_name' => 'Patronymic (Great Grandfather)',
//	'great_great_grandfather_patronymic_name' => 'Patronymic (Great Great Grandfather)',
//	'matronymic_name' => 'Middle Name (Possible Matronymic)',
//	'maiden_name' => null,
//	'family_name' => null,
//	'hispanic_maternal_name' => 'Hispanic Matronymic',
//	'chinese_family_name' => null,
//	'chinese_given_name' => null,
//	'tribal_name' => null,
//	'city_origin' => null,
//	'nisba' => null,
//	'ethnicity' => null,
//	'gender' => null,
//	'indicator_generational' => 'Generational Title',
//	'error_description' => 'Error Description',
//	'confidence' => null
//);


$slotNames = array(
	'caption' => "Full Name",
        'ethnicity' => null,
        'unknown-name-role'=>null,
	'given_name' => null,
        'family_name' => null,
        'son'=>null,
        'nisba' => null,
        'nisba-source'=>null,
        'father_patrimonyal_name' => 'Patronymic',
        'slavic-patronymic' =>null,
        'hispanic-maternal-name'=>null,
        'middle_name' => null,
        'middle_name_second' => null,
        'middle_name_third' => null,
        'grandfather_patrimonyal_name' => 'Patronymic (Grandfather)',
        'great_grandfather_patronymic_name' => 'Patronymic (Great Grandfather)',
	'great_great_grandfather_patronymic_name' => 'Patronymic (Great Great Grandfather)',
        'maiden_name' => null,
        'matronymic_name' => 'Middle Name (Possible Matronymic)',
        'indicator_generational' => 'Generational Title',
        'kunya' => null,
	'nickname' => null,
	'western_maiden_name' => 'Maiden Name',
	'father_patrimonyal_name' => 'Patronymic',
	'hispanic_maternal_name' => 'Hispanic Matronymic',
	'chinese_family_name' => null,
	'chinese_given_name' => null,
	'tribal_name' => null,
	'city_origin' => null,
	'gender' => null,
	'error_description' => 'Error Description',
	'confidence' => null,
        'warning'=>null
);
$slotKeys = array_keys($slotNames);

function getDisplayableName($key)
{
	global $slotNames;
	$displayName = $slotNames[$key];
	if (!empty($displayName)) return $displayName;

	return ucwords(str_replace("_", " ", $key));
}

function compareSlotNamesOrder($a, $b)
{
	global $slotKeys;
	return array_search($a, $slotKeys) - array_search($b, $slotKeys);
}

function arrangeSlots($slots)
{
	//if ($slots['ethnicity'] == 'Hispanic' && array_key_exists('matronymic_name', $slots))
	//{
	//	$slots['hispanic_maternal_name'] = $slots['matronymic_name'];
	//	unset($slots['matronymic_name']);
	//}
	uksort($slots, "compareSlotNamesOrder");
	return $slots;
}

function getRuleToolTip($key)
{
	if (strcasecmp($key,'Possible Sibling Relationship') == 0) return "Siblings will frequently have the same patronymic (father and grandfather) and same family name.";
	if (strcasecmp($key,'Possible Son-Father Relationship') == 0) return "A person will can bear his grandfather's name as his patronymic (first middle name) and his great grandfather's name as a second patronymic.
	Father-son relationships are reflected in the order of the patronymics and the given names.";
	if (strcasecmp($key,'Possible Father-Son Relationship') == 0) return "A person will can bear his grandfather's name as his patronymic (first middle name) and his great grandfather's name as a second patronymic.
	Father-son relationships are reflected in the order of the patronymics and the given names.";
	if (strcasecmp($key,'Possible Same Person (Kunya)') == 0) return "In Arab naming conventions, a person may be  named \"Abu\" (father of) followed by the name of his eldest son which is also the name of his
	father and the second component (patronymic) in his own name. Hence a person whose name is XYZ will be Abu Y.";
	if (strcasecmp($key,'Possible Family/Clan Relationship') == 0) return "a common surname may indicate a family or clan relationship";
	if (strcasecmp($key,'Possible First Cousins') == 0) return "Two people may be first cousins if they have the same grandfather's patronymic and family name.";
	if (strcasecmp($key,'Possible Same Person') == 0) return "Matched on the basis of possible identity of given name, family name and other common features.";
	if (strcasecmp($key,'Possible Same Person (Western)') == 0) return "Matched on the basis of possible identity of given name, family name and other common features.";
	return $key;
}

function getEthnicityToolTip($key)
{
	if (strcasecmp($key,'German') == 0) return "Germany, Austria, Switzerland";
	if (strcasecmp($key,'Dutch') == 0) return "Netherlands, Belgium, South Africa";
	if (strcasecmp($key,'Hebrew') == 0) return "Israel, Jews outside of Israel";
	if (strcasecmp($key,'Anglo-Saxon') == 0) return "USA, UK, Australia, South Africa, Canada, Carribean English speaking islands, etc";
	if (strcasecmp($key,'Arab') == 0) return " Iraq, Jordan, Kuwait, Lebanon, Oman, Palestine, Qatar, Saudi Arabia, Syria, UAE";
	if (strcasecmp($key,'Maghreb') == 0) return "Morocco, Tunisia, Algeria, Mauritania, Libya";
	if (strcasecmp($key,'Maghrebi') == 0) return "Morocco, Tunisia, Algeria, Mauritania, Libya";
	if (strcasecmp($key,'Arab Gulf') == 0) return "Saudi Arabai, Bahrain, Yemen, Qatar, UAE, Oman";
	if (strcasecmp($key,'Levant') == 0) return "Syria, Lebanon, Jordan, Palestine";
	if (strcasecmp($key,'Indonesian') == 0) return "Indonesia, Malaysia";
	if (strcasecmp($key,'Albanian') == 0) return "Albania, Cosovo";
	if (strcasecmp($key,'French') == 0) return "France, Belgium, French speaking Carribean and African countries.";
	if (strcasecmp($key,'Hispanic') == 0) return "Spain, Latin American countries.";
	if (strcasecmp($key,'Portuguese') == 0) return "Portugal, Brazil";
	if (strcasecmp($key,'Scandinavian') == 0) return "Denmark, Sweden, Norway";
	if (strcasecmp($key,'Serb-Croation') == 0) return "Serbia, Croatia";
	if (strcasecmp($key,'Czech') == 0) return "Czech Republic, Slovakia";
	if (strcasecmp($key,'Russian') == 0) return "Russia, Baltic states.";
	if (strcasecmp($key,'Greek') == 0) return "Greece, Cyprus";
	if (strcasecmp($key,'Armenian') == 0) return "Armenia, Iran, Lebanon";
	if (strcasecmp($key,'Central-Asian Muslim') == 0) return "Chechnya, Dagestan, Uzbekistan, Tadjikistan, Ingushetia, Xinjiang";
	if (strcasecmp($key,'Chinese') == 0) return "PRC, Taiwan";
	if (strcasecmp($key,'Slavic') == 0) return "Russian, Polish, Slovak, Ukrainian, ";
	if (strcasecmp($key,'Pashto') == 0) return "Pakistan, Afghanistan, India";
	if (strcasecmp($key,'Urdu') == 0) return "Pakistan, India";
	if (strcasecmp($key,'Tadjik') == 0) return "Tadjikistan, Afghanistan, Uzbek";
	if (strcasecmp($key,'Turkish') == 0) return "Turkey, Turkemistan,  Azerbaijan, Kazakhstan, Kyrgyzstan, Uzbekistan";
	return $key;
}


?>