<?php

	namespace Mocha\Oms;
	
	use Mocha\Core\InstanceReference;
	use Mocha\Core\TenantReference;

	class OmsAttributeValue
	{
		public ?\DateTime $EffectiveDate;
		public mixed $Value;
		
		public function __construct(?\DateTime $effectiveDate, mixed $value)
		{
			$this->EffectiveDate = $effectiveDate;
			$this->Value = $value;
		}

	}
	class OmsRelationshipValue
	{
		public ?\DateTime $EffectiveDate;
		public array $TargetInstances;
		
		public function __construct(?\DateTime $effectiveDate, array $targetInstances)
		{
			$this->EffectiveDate = $effectiveDate;
			$this->TargetInstances = $targetInstances;
		}

	}
	class OmsInstanceReferenceCache
	{
		private InstanceReference $instanceReference;

		private array $attributes;
		private array $relationships;
		public function __construct(InstanceReference $instanceReference)
		{
			$this->instanceReference = $instanceReference;
			$this->attributes = array();
			$this->relationships = array();
		}
		
		public function hasAttribute(InstanceReference $attributeInstance)
		{
			return array_key_exists($attributeInstance->GlobalIdentifier->__toStringFormat(false, "", ""), $this->attributes);
		}
		public function hasRelationship(InstanceReference $relationshipInstance)
		{
			return array_key_exists($relationshipInstance->GlobalIdentifier->__toStringFormat(false, "", ""), $this->relationships);
		}
		public function getRelatedInstances(InstanceReference $relationshipInstance, ?\DateTime $effectiveDate = null)
		{
			if (!$this->hasRelationship($relationshipInstance))
			{
				$this->relationships[$relationshipInstance->GlobalIdentifier->__toStringFormat(false, "", "")] = array();
			}

			$ary = $this->relationships[$relationshipInstance->GlobalIdentifier->__toStringFormat(false, "", "")];
			$retval = array();
			foreach ($ary as $val)
			{
				// if less than or eqal to eff date
				foreach ($val->TargetInstances as $inst)
				{
					$retval[] = $inst;
				}
			}
			return $retval;
		}
		public function assignRelationship(InstanceReference $relationshipInstance, array $targetInstances, ?\DateTime $effectiveDate = null)
		{
			$key = $relationshipInstance->GlobalIdentifier->__toStringFormat(false, "", "");
			if (!$this->hasRelationship($relationshipInstance))
			{
				$this->relationships[$key] = array();
			}
			$this->relationships[$key][] = new OmsRelationshipValue($effectiveDate, $targetInstances);
		}

		public function getAttributeValue(InstanceReference $attributeInstance, ?\DateTime $effectiveDate = null) : mixed
		{
			if (!$this->hasAttribute($attributeInstance))
			{
				$this->attributes[$attributeInstance->GlobalIdentifier->__toStringFormat(false, "", "")] = array();
			}

			$ary = $this->attributes[$attributeInstance->GlobalIdentifier->__toStringFormat(false, "", "")];
			$retval = array();
			foreach ($ary as $val)
			{
				// if less than or eqal to eff date
				return $val->Value;
			}
			return null;
		}
		public function setAttributeValue(InstanceReference $attributeInstance, mixed $value, ?\DateTime $effectiveDate = null)
		{
			$key = $attributeInstance->GlobalIdentifier->__toStringFormat(false, "", "");
			if (!$this->hasAttribute($attributeInstance))
			{
				$this->attributes[$key] = array();
			}
			$this->attributes[$key][] = new OmsAttributeValue($effectiveDate, $value);
		}
	}

	class OmsInstanceCache
	{
		private array $array;

		public function __construct()
		{
			$this->array = array();
		}

		public function has(InstanceReference $instance)
		{
			return array_key_exists($instance->GlobalIdentifier->__toStringFormat(false, "", ""),  $this->array);
		}
		public function get(InstanceReference $instance) : OmsInstanceReferenceCache
		{
			if (!$this->has($instance))
			{
				$this->array[$instance->GlobalIdentifier->__toStringFormat(false, "", "")] = new OmsInstanceReferenceCache($instance);
			}
			return $this->array[$instance->GlobalIdentifier->__toStringFormat(false, "", "")];
		}
	}

	class OmsCache
	{
		private array $array;
		public function __construct()
		{
			$this->array = array();
		}

		public function has(TenantReference $tenant) : bool
		{
			return array_key_exists($tenant->ID, $this->array);
		}
		public function get(TenantReference $tenant) : OmsInstanceCache
		{
			if (!$this->has($tenant))
			{
				$this->array[$tenant->ID] = new OmsInstanceCache();
			}
			return $this->array[$tenant->ID];
		}

		public function hasRelationship(TenantReference $tenant, InstanceReference $sourceInstance, InstanceReference $relationshipInstance)
		{
			return $this->get($tenant)->get($sourceInstance)->hasRelationship($relationshipInstance);
		}
		public function getRelatedInstances(TenantReference $tenant, InstanceReference $sourceInstance, InstanceReference $relationshipInstance, ?\DateTime $effectiveDate = null)
		{
			return $this->get($tenant)->get($sourceInstance)->getRelatedInstances($relationshipInstance, $effectiveDate);
		}
		public function assignRelationship(TenantReference $tenant, InstanceReference $sourceInstance, InstanceReference $relationshipInstance, array $targetInstances)
		{
			$cache = $this->get($tenant)->get($sourceInstance);
			$cache->assignRelationship($relationshipInstance, $targetInstances);
		}

		public function hasAttributeValue(TenantReference $tenant, InstanceReference $sourceInstance, InstanceReference $attributeInstance)
		{
			return $this->get($tenant)->get($sourceInstance)->hasAttribute($attributeInstance);
		}
		public function getAttributeValue(TenantReference $tenant, InstanceReference $sourceInstance, InstanceReference $attributeInstance, ?\DateTime $effectiveDate = null)
		{
			return $this->get($tenant)->get($sourceInstance)->getAttributeValue($attributeInstance, $effectiveDate);
		}
		public function setAttributeValue(TenantReference $tenant, InstanceReference $sourceInstance, InstanceReference $attributeInstance, mixed $value, ?\DateTime $effectiveDate = null)
		{
			$cache = $this->get($tenant)->get($sourceInstance);
			$cache->setAttributeValue($attributeInstance, $value, $effectiveDate);
		}

	}

?>