<?php

// By Rom


require_once('../application/nicewebpage.class.inc.php');
require_once('../application/dialogstack.class.inc.php');

require_once('../application/startup.inc.php');

// #@# not used, but... require_once('../classes/usercontext.class.inc.php');
$oPage = new nice_web_page("ITop finder");
$oPage->no_cache();


MetaModel::CheckDefinitions();
// new API - MetaModel::DBCheckFormat();
// not necessary, and time consuming!
// MetaModel::DBCheckIntegrity();


function ReadParam($sName, $defaultValue = "")
{
	return isset($_REQUEST[$sName]) ? $_REQUEST[$sName] : $defaultValue;
}



function Page1_AskClass($oPage)
{
    $oPage->add("<form method=\"post\" action=\"\">\n");
	//$oPage->add("<input type=\"hidden\" name=\"tnut\" value=\"blah\">");
	$oPage->p("Please select the type of object that you want to look for:");
    $oPage->MakeClassesSelect("class", "", 50, UR_ACTION_READ);
    $oPage->add("<input type=\"submit\" name=\"userconfig\" value=\"Configure filters\">\n");
	$oPage->add("</form>\n");
}


function Page2_ConfigFilters($oPage, $oFilter)
{
	$sClass = $oFilter->GetClass();

	$oPage->p("Objects of class <em>$sClass</em>");
    $oPage->add("<form method=\"post\" action=\"\">\n");
	$oPage->add("<input type=\"hidden\" name=\"class\" value=\"$sClass\">\n"); 

	// Full text input
	//
	$oPage->add("<div>\n");
	$oPage->add("Full text: ");
	$sFullText = "";
	foreach($oFilter->GetCriteria_FullText() as $sFullText)
	{
		// #@# Known limitation: do not consider other full text conditions...
		continue;
	}
	
	$oPage->add("<input type=\"text\" name=\"flt_fulltext\" value=\"$sFullText\">\n"); 
	$oPage->add("</div>\n");

	// Attribute-related criteria
	//
	foreach (MetaModel::GetClassFilterDefs($sClass) as $sFltCode => $oFltDef)
	{
		// Set its current values
		$sOpCode = "__none__";
		$sValue = "";
		foreach($oFilter->GetCriteria() as $aCritInfo)
		{
			if ($aCritInfo["filtercode"] == "pkey")
			{
				// ???
			}
			elseif ($aCritInfo["filtercode"] == $sFltCode)
			{
				$sOpCode = $aCritInfo["opcode"];
				$sValue = $aCritInfo["value"];
				break;
			}
		}

		$oPage->add("<div>\n");
		//$oPage->add($oFltDef->GetType()." (".$oFltDef->GetTypeDesc().")");
		$oPage->add(" ".$oFltDef->GetLabel()." ");

		$aOperators = array_merge(array("__none__" => ""), $oFltDef->GetOperators());
		$oPage->add_select($aOperators, "flt_ops[$sFltCode]", $sOpCode, 100);
		$oPage->add("\n");

		$oPage->add("<input type=\"text\" name=\"flt_values[$sFltCode]\" value=\"$sValue\">\n"); 
		$oPage->add("</div>\n");
	}

	// Ext key criteria
	//
	foreach (MetaModel::EnumReferencedClasses($sClass) as $sExtKeyAttCode => $sRemoteClass)
	{
		// Set its current values
		$oSubFilter = $oFilter->GetCriteria_PointingTo($sExtKeyAttCode);
		if (!$oSubFilter)
		{
			$oSubFilter = new CMDBSearchFilter($sRemoteClass);
		}

		$oPage->add("<div>\n");
		$oAtt = MetaModel::GetAttributeDef($oFilter->GetClass(), $sExtKeyAttCode);
		$oPage->add($oAtt->GetLabel()." having ({$oSubFilter->DescribeConditions()})");
		//$oPage->add("having $oFilter->DescribeConditionPointTo($sExtKeyAttCode));
		$oPage->add("\n");

		$oPage->add(dialogstack::RenderEditableField("Edit...", "flt_pointto[$sExtKeyAttCode]", $oSubFilter->serialize(), true));
		$oPage->add("</div>\n");
	}

	// Ext key criteria, the other way
	//
	foreach (MetaModel::EnumReferencingClasses($sClass, true) as $sRemoteClass => $aRemoteKeys)
	{
		foreach ($aRemoteKeys as $sExtKeyAttCode => $oExtKeyAttDef)
		{
			// Set its current values
			$oSubFilter = $oFilter->GetCriteria_ReferencedBy($sRemoteClass, $sExtKeyAttCode);
			if (!$oSubFilter)
			{
				$oSubFilter = new CMDBSearchFilter($sRemoteClass);
			}

			$oPage->add("<div>\n");
			//$oPage->add($oFilter->DescribeConditionRefBy($sRemoteClass, $sExtKeyAttCode));
			$oAtt = MetaModel::GetAttributeDef($sRemoteClass, $sExtKeyAttCode);
			$oPage->add("being ".$oAtt->GetLabel()." for ".$sRemoteClass."(e)s in ({$oSubFilter->DescribeConditions()})");
			$oPage->add("\n");
	
			$oPage->add(dialogstack::RenderEditableField("Edit...", "flt_refedby[$sRemoteClass][$sExtKeyAttCode]", $oSubFilter->serialize(), true));
			$oPage->add("</div>\n");
		}
	}

	// Ext key criteria -> link objects
	//
	foreach (MetaModel::EnumLinkingClasses($sClass) as $sLinkClass => $aRemoteClasses)
	{
		foreach($aRemoteClasses as $sExtKeyAttCode => $sRemoteClass)
		{
			// Set its current values
			//$oSubFilter = $oFilter->GetCriteria_PointingTo($sExtKeyAttCode);
			$oSubFilter = null;
			if (!$oSubFilter)
			{
				$oSubFilter = new CMDBSearchFilter($sRemoteClass);
			}
			$oPage->add("<div>\n");
			//$oPage->add(" ".MetaModel::GetName($sRemoteClass)." ");
			$oPage->add(" Linked to '".MetaModel::GetLinkLabel($sLinkClass, $sExtKeyAttCode)."' by ");
			$oSubFilter = new CMDBSearchFilter($sRemoteClass);
			$oPage->add($oSubFilter->__DescribeHTML());
			$oPage->add("\n");

			$oPage->add(dialogstack::RenderEditableField("Edit...", "flt_linkedwith[$sRemoteClass][$sExtKeyAttCode]", $oSubFilter->serialize(), true));
			$oPage->add("</div>\n");
		}
	}

    $oPage->add("<input type=\"submit\" name=\"makeit\" value=\"Search\">\n");
	$oPage->add("</form>\n");
}

function MakeFilterFromArgs()
{
	$sClass = ReadParam("class");
	$sFilterFullText = ReadParam("flt_fulltext", "");
	$aFilterOps = ReadParam("flt_ops", array());
	$aFilterValues = ReadParam("flt_values", array());
	$aPointTo = ReadParam("flt_pointto", array());
	$aRefedBy = ReadParam("flt_refedby", array());
	$aLinkedWith = ReadParam("flt_linkedwith", array());

	$oFilter = new CMDBSearchFilter($sClass);

	if (!empty($sFilterFullText))
	{
		$oFilter->AddCondition_FullText($sFilterFullText);
	}

	foreach($aFilterOps as $sFltCode=>$sOpCode)
	{
		if ($sOpCode == "__none__") continue;
		$oFilter->AddCondition($sFltCode, $aFilterValues[$sFltCode], $sOpCode);
	}

	foreach($aPointTo as $sExtKeyAttCode=>$sFilterShortcut)
	{
		$oSubFilter = CMDBSearchFilter::unserialize($sFilterShortcut);
		$oFilter->AddCondition_PointingTo($oSubFilter, $sExtKeyAttCode);
	}

	foreach($aRefedBy as $sForeignClass=>$aExtKeys)
	{
		foreach($aExtKeys as $sForeignExtKey=>$sFilterShortcut)
		{
			//MyHelpers::var_dump_html("$sForeignClass / $sForeignExtKey / $sFilterShortcut");
			$oSubFilter = CMDBSearchFilter::unserialize($sFilterShortcut);
			//MyHelpers::var_dump_html($oSubFilter);
			$oFilter->AddCondition_ReferencedBy($oSubFilter, $sForeignExtKey);
		}
	}

//	$oFilter->AddCondition_LinkedTo(DBObjectSearch $oLinkFilter, $sExtKeyAttCodeToMe, $sExtKeyAttCodeTarget, DBObjectSearch $oFilterTarget);

	return $oFilter;
}

function Page3_ViewResults($oPage, $oFilter)
{
	// Output results in various forms...
	//
	if ($oFilter->IsAny())
	{
		$oPage->p("You are considering the ENTIRE set of objects...");
	}
	else
	{
		$oPage->p($oFilter->__DescribeHTML());
		
		$oSet = new CMDBObjectSet($oFilter);
		$oPage->p("Found ".$oSet->Count()." items");
	
		$sFilterPhrase = $oFilter->serialize();
		$oPage->p("<a href=\"/pages/index.php?operation=direct&filter=$sFilterPhrase\">See detailed results</a>"); 
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//
//  M a i n   P r o g r a m
//
///////////////////////////////////////////////////////////////////////////////////////////////////


$oPage->p("<h1>Advanced search</h1>");


// Page 1 - Ask class
//
// Page 2 - Class is given, enum existing filters/possible links
//
// Page 3 - Interpret user choices, create a filter and render its string representation
//

//MyHelpers::arg_dump_html();
//MyHelpers::var_dump_html($_SESSION);

if (ReadParam('userconfig', false))
{
	$sTodo = 'userconfig';
}
if (ReadParam('makeit', false))
{
	$sTodo = 'makeit';
}
else
{
	if (dialogstack::IsDialogStartup())
	{
		$sInit = dialogstack::StartDialog();
		$oFilter = CMDBSearchFilter::unserialize($sInit);
		$sTodo = 'userconfig';
	}
	else
	{
		$sClass = ReadParam('class', '');
		if (empty($sClass))
		{
			$sTodo = 'selectclass';
		}
		else
		{
			$oFilter = MakeFilterFromArgs();
			$sTodo = 'userconfig';
		}
	}
}

switch ($sTodo)
{
case "selectclass":
	Page1_AskClass($oPage);
	break;

case "userconfig":
	dialogstack::DeclareCaller("Define filter for ".$oFilter->GetClass());
	$oPage->add(implode(" / ", dialogstack::GetCurrentStack()));
	Page2_ConfigFilters($oPage, $oFilter);
	break;

case "makeit":
	$oFilter = MakeFilterFromArgs();
	Page3_ViewResults($oPage, $oFilter);
	$oPage->add(dialogstack::RenderEndDialogForm(DLGSTACK_OK, "Use filter", $oFilter->serialize()));
	$oPage->add(dialogstack::RenderEndDialogForm(DLGSTACK_CANCEL, "Annuler"));
	break;

default:
	trigger_error("Wrong value for arg <em>todo</em> ($sTodo)", E_USER_ERROR);
}

$oPage->output();

?>
