/*

CLASS {NATIVE_Thread|_CSharp},
UNTESTED, NATIVE:

IMPORT, ANYWAY: {Thread} .

NATIVE: "///COPY NATIVE_Thread.*" .
NATIVE: "using System.Threading;" .

*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
//using Microsoft.Win32;
using AL4;
using AL4_project;

public class AL4_thread
{

public int C11;

public static List<AL4_thread> All_threads = new List<AL4_thread>();

// Id of the main thread, set in the	\ИД главной нити, устанавливается в секции
// initialization section, used to		\инициализации, используется для проверки
// check if the currect thread is main	\того, что текущая нить является главной
public static int mainThreadId = 0;

//The lock object to protect code	\Объект блокировки для защиты секций кода, в\
//sections working with the list	\которых идет работа со списком всех нитей
//of threads used
public static object lock_All_threads = new object();

	public Thread thread = null;
	
	public static int Total_count_running_threads = 0;
	
	public bool started_in_thread;

/*

FUNCTION Total_count_of_running_threads ==> INT, NATIVE : @
	"RESULT = AL4_thread.Total_count_running_threads;" .

FUNCTION Create_thread(
{Thread} Thread|_object) ==> INT, NATIVE:
@	"if (AL4_thread.mainThreadId == 0)"
	"	AL4_thread.mainThreadId = Thread.CurrentThread.ManagedThreadId;"	
	"AL4_thread t = new AL4_thread();"
	"t.C11 = 2;"
	"t.ref_C_Thread = (C_Thread)X_Thread.Obj;"
	"t.thread = new Thread(t.Execute_routine);"
	"t.thread.IsBackground = true;"
	"lock(AL4_thread.lock_All_threads)"
	"{"
		"int i = AL4_thread.All_threads.IndexOf(null);"
		"if (i >= 0) {"
		"	AL4_thread.All_threads[i] = t;"
		"	t.Thread_handle = i+1;"
		"}"
		"else"
		"{"
		"	AL4_thread.All_threads.Add(t);"
		"	t.Thread_handle = AL4_thread.All_threads.Count;"
		"}"
	"}"
	"return t.Thread_handle;"
	.
	
FUNCTION Destroy_thread_handle(
{Thread} T|hread_to_destroy), NATIVE :
	//CASE T.Is_controller ? ==> ;
	INT handle|_to_destroy = T.Handle
	CASE handle == 0 ? ==> ;
	NATIVE @
	"AL4_thread t;"	
	"lock(AL4_thread.lock_All_threads)"
	"{"
    "	t = AL4_thread.All_threads[(int)X_handle - 1];"
	"	if (t == null) return;"
	"       t.thread_started = null;"
	"       t.data_arrive = null;"
	"       t.Thread_handle = 0;" 
	"       t.thread = null;" 
	"	t.C11 --;"
	"	if (t.C11 > 0) return;"
	"	AL4_thread.All_threads[(int)X_handle - 1] = null;"
	"}" .	
	
FUNCTION Thread_is_main ==> BOOL, NATIVE :
@	"RESULT = AL4_thread.mainThreadId == Thread.CurrentThread.ManagedThreadId;"
	.
	
FUNCTION Thread_run({Thread} Thread|_object), NATIVE :
	CASE Thread.Handle <= 0 ? ==> ;
	NATIVE
@	"AL4_thread t;"	
	"lock(AL4_thread.lock_All_threads)"
	"{"
	"	t = AL4_thread.All_threads["
	"		(int)((C_Thread)X_Thread.Obj).F_Handle - 1];"
	"}"
	"if (t == null) return;"
	"		t.thread.Name = ((C_Thread)X_Thread.Obj).F_Handle.ToString();"
	
    //"//-----------------------------------------------------------"
    //"Console.WriteLine("#QU"thread running: "#QU" + t.thread.Name +"
    //#QU" ThreadState:"#QU" + t.thread.ThreadState.ToString());"
    //"//-----------------------------------------------------------"
	"if ((t.thread.ThreadState & ThreadState.Unstarted) == 0) return;"

	"t.thread.Start();"
	"if (t.thread_started != null)" 
	"	t.thread_started.WaitOne();" .
	
FUNCTION Thread_ended(INT Handle|_thread) ==> BOOL, NATIVE :
	CASE Handle <= 0 ? ==> ;
	NATIVE
@	"AL4_thread t;"	
	"lock(AL4_thread.lock_All_threads)"
	"{"
	"	t = AL4_thread.All_threads[(int)X_Handle - 1];"
	"}"	
    //"RESULT = t.thread.ThreadState == ThreadState.Stopped ||"
    //"		  t.thread.ThreadState == ThreadState.StopRequested ||"
    //"		  t.thread.ThreadState == ThreadState.Aborted ||"
    //"		  t.thread.ThreadState == ThreadState.AbortRequested"
    //"		|| !t.ref_C_Thread.F_Running;"
	"RESULT = t == null || "
	"		  t.thread.ThreadState == ThreadState.Stopped ||"
	"		  t.thread.ThreadState == ThreadState.Aborted;"
	.
	
FUNCTION Thread_stop(
INT Handle|_thread, BOOL Terminate), NATIVE:
	CASE Handle <= 0 ? ==> ;
	NATIVE
@	"AL4_thread t;"	
	"lock(AL4_thread.lock_All_threads)"
	"{"
	"	t = AL4_thread.All_threads[(int)X_Handle - 1];"
	"}"	
	"if (t.thread.ThreadState == ThreadState.Stopped ||"
	"	 t.thread.ThreadState == ThreadState.StopRequested ||"
	"	 t.thread.ThreadState == ThreadState.Aborted ||"
	"	 t.thread.ThreadState == ThreadState.AbortRequested)"
	"	 return;"
	"t.thread.Abort();" .
	
CONST STR :
	Native_import = @
	"using System.Threading;"	

	Native_wait_threads = @
    "int start_at = Environment.TickCount;"
    "while(true) {"
    "    RESULT = true;"
    "    for (int i = 0; i < X_A.Count; i++)"
    "    {"
    "         C_Thread cT = (C_Thread)X_A.get_obj(i).Obj;"
    "         AL4_thread t = AL4_thread.All_threads[(int)cT.F_Handle - 1];"
    "         bool ended = t.thread.ThreadState == ThreadState.Stopped ||"
    "                      t.thread.ThreadState == ThreadState.Aborted;"
    "         if (!ended) RESULT = false;"
    "	 }"
    "    if (RESULT) break;"
    "	 if (X_Max > 0 && Environment.TickCount - start_at > X_Max) break;"
    "    Thread.Sleep(1);"
    "}"
	.

FUNCTION Thread_priority(
INT Handle|_thread) ==> {Thread}.{priority}, NATIVE:
	CASE Handle <= 0 ? ==> ;
	NATIVE
@	"AL4_thread t;"
	"lock(AL4_thread.lock_All_threads)"
	"{"
	"	t = AL4_thread.All_threads[(int)X_Handle - 1];"
	"}"	
	"RESULT = t == null ? (byte)0 : (byte)t.thread.Priority;" .
	
FUNCTION Thread_set_priority(
INT Handle|_thread, {priority} Priority), NATIVE:
	CASE Handle <= 0 ? ==> ;
	NATIVE
@	"AL4_thread t;"	
	"lock(AL4_thread.lock_All_threads)"
	"{"
	"	t = AL4_thread.All_threads[(int)X_Handle - 1];"
	"}"	
	"if (t == null) return;"
	"switch(X_Priority)"
	"{"
	"case 0: t.thread.Priority = ThreadPriority.Lowest; break;"
	"case 1: t.thread.Priority = ThreadPriority.BelowNormal; break;"
	"case 2: t.thread.Priority = ThreadPriority.Normal; break;"
	"case 3: t.thread.Priority = ThreadPriority.AboveNormal; break;"
	"case 4: t.thread.Priority = ThreadPriority.Highest; break;"
	"}" .
	
FUNCTION Thread_take_objects(
INT Handle|_thread, {Object} A|rray_of_objects_passed[*],
BOOL Together|_with_hard_linked), NATIVE:
	CASE Handle <= 0 ? ==> ;
	NATIVE
@	"AL4_thread t;"	
	"lock(AL4_thread.lock_All_threads)"
	"{"
	"	t = AL4_thread.All_threads[(int)X_Handle - 1];"
	"}"
	"if (t == null) return;"	
	"t.take_objects(X_A, X_Together);" .
	
FUNCTION Thread_receive_objects(
INT Handle|_thread, {Object} A|rray_of_objects_received[], BOOL Wait|_for_take),
NATIVE:
	CASE Handle <= 0 ? ==> ;
	NATIVE
@	"AL4_thread t;"	
	"lock(AL4_thread.lock_All_threads)"
	"{"
	"	t = AL4_thread.All_threads[(int)X_Handle - 1];"
	"}"
	"if (t == null) return;"	
	"t.receive_objects(X_A, X_Wait);" .
	
FUNCTION Thread_yield_objects(
INT Handle|_thread, {Object} A|rray_of_objects_returned[*]), NATIVE:
	CASE Handle <= 0 ? ==> ;
	NATIVE
@	"AL4_thread t;"	
	"lock(AL4_thread.lock_All_threads)"
	"{"
	"	t = AL4_thread.All_threads[(int)X_Handle - 1];"
	"}"	
	"if (t == null) return;"	
	"t.yield_objects(X_A);" .
	
FUNCTION Is_thread_running(
INT Handle|_thread) ==> BOOL, NATIVE
	:
	CASE Handle <= 0 ? ==> ;
	NATIVE
@	"AL4_thread t;"	
	"lock(AL4_thread.lock_All_threads)"
	"{"
	"	t = AL4_thread.All_threads[(int)X_Handle - 1];"
	"}"	
	"if (t == null) return false;"
	"C_Thread ct = (C_Thread)t.ref_C_Thread;"
	"RESULT = ct.F_running;" .

*/

	public int Thread_handle;
	public C_Thread ref_C_Thread;
	private object protect_take_yield = new object();
	public AutoResetEvent thread_started = null; // new AutoResetEvent(false);

	//____________________________________________________
	// {Thread}.execute --> Thread_run --> Execute_routine
	
	public void Execute_routine(object data)
	{
		Total_count_running_threads += 1;
		try {
	
		//simulate here Take					\симулируем здесь передачу Take 
		//for the ref_C_Thread object itself	\самого объекта нити ref_C_Thread
		Ref_obj X;
		lock(protect_take_yield)
		{
			X = take_single_object(ref_C_Thread.hard_link, true, false);
			receive_single_object(X);
			//here X.Count == 0	\ здесь должно быть X.Count == 0
			X.Count += 2;
		}
		
		if (thread_started == null)
			thread_started = new AutoResetEvent(false);
		thread_started.Set();
		//---------------------- 'set Running flag on the started thread side'
		((C_Thread)X.Obj).F_running = true;
		started_in_thread = true;
		//---------- 'the same in the controller visible from the parent side'
		//C_Thread controller = (C_Thread)ref_controller.Obj; 
		//controller.F_Running = true;
		//call executing the user defined			\вызываем пользовательскую
		//function which is running in the thread	\функцию для исполнения нити
		((C_Thread)X.Obj).Do.M_execute();
		((C_Thread)X.Obj).F_running = false;
		
		//return back the ref_C_Thread object	\возвращаем назад сам объект
		//itself onto the side of the parent	\нити ref_C_Thread, в родитель-
		//thread								\скую нить
		lock(protect_take_yield)
		{
			if (X.Count == 2)
		 	{
		 		// still Count -= 2 --> 0		\т.к. Count -= 2 --> 0,
		 		// X is returned automatically	\то возврат будет автоматический
		 		X.Ref_dec_hard();
		 	}
		 	else yield_single_object(X);
		}
		
		}
		finally {
		Total_count_running_threads -= 1;
		}
	}
	
	//_______________________________________________________
	// {Thread}.Take --> Thread_take_objects --> take_objects
	// taking objects from the parent	\передача объектов от родительской нити
	// thread to the running thread		\к исполняющейся дочерней нити
	//[diagram:Object_isolation]
	public void take_objects(ArrayObjHard A, bool Together)
	{
		//lock(protect_take_yield)
		{
			for (int i = 0; i < A.Count; i++)
			{
				Ref_obj Ai = A.get_obj(i);
				if (Ai.Obj.Is_NONE_object) continue;
				
				take_single_object(Ai, Together, true);
			}
			if (queue_input_objects.Count > 0)
			{
				//there are received objects:	\есть принятые объекты в очереди
				//set the flag to end waiting	\установка флага для прекращения
				//receiving object event		\ожидания принятых объектов
				if (data_arrive == null)
					data_arrive = new AutoResetEvent(false);
				data_arrive.Set();
			}
		}
	}
	
	//____________________________________________________________________
	//take a single object to the thread	\передача единичного объекта в
	//started (from the parent thread)		\запущенную подчиненную нить
	public Ref_obj take_single_object(Ref_obj Ai, bool Together,
		   bool add_to_queue)
	{
		//_______________________________________________
		// separate hard_link	\отделение жесткой 
		//[diagram:Object_separate1]
		AL4_object Z = Ai.Obj;
		
		Ref_obj h = Z.hard_link;
		Ref_obj H = new Ref_obj_foreign(Z, 0); 
		Z.hard_link = H;
		H.Parent_ref = h;
		H.Thread_handle = Thread_handle;
		// add local reference to the queue \добавляется в очередь принятия
		if (add_to_queue)
			queue_input_objects.Add(H);
		Ref_obj result = H;
		
		// previous hard_link redirect to NONE	\прежний hard_link -> на NONE
		h.Migrated_ref = H;
		h.Obj = Z.NONE_obj_instance().Obj;
		//[diagram:Object_separate2]
	
		//_______________________________________________
		// separate weak_link	\отделение слабой ссылки
		Ref_obj w = Z.weak_link;
		Ref_obj W = new Ref_obj(Z, 1); 
		
		Z.weak_link = W; 
		W.Parent_ref = w;
		W.Thread_handle = Thread_handle;
		
		// previous weak_link redirect to NONE	\прежний weak_link -> на NONE
		w.Migrated_ref = W;
		w.Obj = h.Obj;
		
		// look at all the object fields	\просмотр объектных полей объекта
		//of the object migrating			\мигрирующего в нить при передаче
		int c_fields = Ai.Obj.RTTI_object_field_count();
		for (int j = 0; j < c_fields; j++)
		{
			//C_RTTI.Ob_field_data f_info = new C_RTTI.Ob_field_data();
			//Ai.Obj.RTTI_object_field_info(f_info, j, 0);
			int type_index = Ai.Obj.RTTI_object_info_field(j, 0);
			if (AL4_object.RTTI_type_kind(type_index) != 3)
				continue;
				
			bool is_weak = false;
			if (Together)
			{
				string f_name = Ai.Obj.RTTI_object_field_name(j);
				is_weak = f_name[f_name.Length-1] == '_';
			}				

			int last = 1;
			if (Ai.Obj.RTTI_object_info_field(j, 1) > 0)
				last = Ai.Obj.RTTI_object_info_field(j, 4);
			 
			if (is_weak || !Together)
			{
				//if the field is an array,	\для поля-массива, поэлементная
				//separate its items		\обработка
				for (int k = 0; k < last; k++)
				{
					Ref_obj Bk = Ai.Obj.RTTI_object_get_object(j, k);
					if (Bk.Count == 2 && !is_weak)
						//there is only a single	\есть только 1 жесткая ссылка
						//reference to Bk from Ai,	\на Bk из Ai, взять его с
						//take it together anyway	\собой при переносе в нить
						take_single_object(Bk, false, add_to_queue);
					else
					{
						Bk = break_object_ref(Bk);
						Ai.Obj.RTTI_object_set_object(j, Bk, k);
					}
				}
			}
			else // Together
			{
				//migrate all the objects,	\ режим отправки всех подчиненных
				//by the fields which are	\ объектов, на которые есть жесткие
				//hard links to the objects	\ ссылки из полей отпраяленного объекта
				for (int k = 0; k < last; k++)
				{
					Ref_obj Bk = Ai.Obj.RTTI_object_get_object(j, k);
					if (Bk.Obj.Is_NONE_object) continue;
					take_single_object(Bk, Together, add_to_queue);
				}
			}
		}
		return result;
	} 
	
	//_____________________________________________________________________
	// break a single link to the		\разрыв единичной ссылки на объект,
	// object left in previous thread	\который остается в адресном пространстве
	// address space					\исходной нити
	public Ref_obj break_object_ref(Ref_obj X)
	{
		Ref_obj X_new = new Ref_obj(X.Obj.NONE_obj_instance().Obj, -1);
		X_new.Thread_handle = Thread_handle;
		X_new.Migrated_ref = X;
		
		//return new reference to NONE	\возвращается новая ссылка на NONE,
		//replacing the broken link		\которая замещает разорванную ссылку
		return X_new;
	}
	
	//queue of objects passed to the thread	\очередь объектов, переданных в нить
	//by Take method from the parent thread	\из родительской нити методом Take
	//(together with hard-linked objects	\(вместе с объектами, на которые
	//referenced by object fields of passed	\жестко ссылаются поля переданных
	//objects, if this is an option or this	\объектов, при указании такой опции
	//is a single hard link field)			\или при единственности связи)
	public List<Ref_obj> queue_input_objects = new List<Ref_obj>();
	
	//the event to wait receiving objects	\событие для ожидания приемки объектов
	public AutoResetEvent data_arrive = null; // new AutoResetEvent(false);
	
	//____________________________________________________
	// receive objects --> \приемка отправленных объектов 
	public void receive_objects(ArrayObjHard A, bool Wait)
	{
		bool wait_and_try_again = false;
		lock(protect_take_yield)
		{
			if (queue_input_objects.Count == 0 && !Wait) return;
			if (queue_input_objects.Count == 0)
			{
				wait_and_try_again = true;
			}
			else
			for (int i = 0; i < queue_input_objects.Count; i++)
			{
				Ref_obj Di = queue_input_objects[i];
				if (Di == null) continue;
				if (Di.Obj.Is_NONE_object) continue;
				A.Add(Di);
				receive_single_object(Di);
			}
		}
		if (!wait_and_try_again) return;
		//second attempt, after wait	\повторная попытка, после ожидания
		lock(protect_take_yield)
		{
			//waiting	\ожидание
			if (data_arrive != null)
				data_arrive.WaitOne();
			for (int i = 0; i < queue_input_objects.Count; i++)
			{
				Ref_obj Di = queue_input_objects[i];
				A.Add(Di);
				receive_single_object(Di);
			}
		}
	}
	
	//_____________________________________________________
	//receiving a single object	\приемка единичного объекта
	public void receive_single_object(Ref_obj Di)
	{
		
		//if (Di.Parent_ref != null && 
		//	Di.Parent_ref.Thread_handle == Thread_handle
		//	)
		//	Di.Parent_ref.Obj = Di;
			
		//look at all the object fields of Di	\см. на все объектные поля Di
		int c_fields = Di.Obj.RTTI_object_field_count();
		for (int j = 0; j < c_fields; j++)
		{
			//C_RTTI.Ob_field_data f_info = new C_RTTI.Ob_field_data();
			//Di.Obj.RTTI_object_field_info(f_info, j, 0);
			int type_index = Di.Obj.RTTI_object_info_field(j, 0);
			if (AL4_object.RTTI_type_kind(type_index) != 3)
				continue;
				
			bool is_weak = false;
			string f_name = Di.Obj.RTTI_object_field_name(j);
			is_weak = f_name[f_name.Length-1] == '_';
			
			int last = 1;
			if (Di.Obj.RTTI_object_info_field(j, 0) > 0)
				last = Di.Obj.RTTI_object_info_field(j, 4);

			for (int k = 0; k < last; k++)
			{
				Ref_obj Bk = Di.Obj.RTTI_object_get_object(j, k);
				Bk = rejoin_object_ref(Di, Bk);
				Di.Obj.RTTI_object_set_object(j, Bk, k);
				if (!is_weak && !Bk.Obj.Is_NONE_object)
					receive_single_object(Bk);
			}
		}
	}
	
	//___________________________________________________________________
	//rejoin a single object migrated	\восстановление ссылок из одного объекта
	//to the thread resting a broken	\в случаях, когда они указывают на
	//link in case when it refers to	\объекты, находящиеся в той же нити 
	//an object also belonging to the	\в результате отправки нескольких объектов
	//same thread (together or separately)	\(вместе или последовательно)
	public Ref_obj rejoin_object_ref(Ref_obj S_ref_from_dummy, Ref_obj R)
	{
		if (R.Obj.Is_NONE_object &&
			R.Migrated_ref != null &&
			R.Migrated_ref.Parent_ref == R &&
			R.Migrated_ref.Thread_handle == Thread_handle
			) //[diagram:Object_separate2]
		{
			return R.Migrated_ref;
			//[diagram:Object_rejoin]
		}
		return R;
	}
	
	//______________________________________________________
	// yield_objects forced	\возврат объектов принудительный
	public void yield_objects(ArrayObjHard A)
	{
		 for (int i = 0; i < A.Count; i++)
		 {
		 	Ref_obj Ai = A.get_obj(i);
			if (Ai.Obj.hard_link.Parent_ref == null)
				//it is not possible to yield	\нельзя возвратить объект,
				//an object, which was created	\созданный в этой нити, в отличии
				//in the current thread rather	\от переданного из родительской
				//then taken from the parent	\нити
				continue;	 	
	
		 	if (Ai.Obj.hard_link.Count == 2)
		 	{
		 		// still Count -= 2 --> 0		\т.к. Count -= 2 --> 0,
		 		// Ai is returned automatically	\то возврат будет автоматический
		 		A.set_obj(i, Ai.Obj.NONE_obj_instance());
		 		continue;
		 	}
		 	
		 	yield_single_object(Ai);
		 	
		 	// actual yielding is performed here	\реально передача происходит
		 	// still an intermediate Ref_obj is		\здесь, т.к. на самом деле
		 	// actually of class Ref_obj_foreign	\промежуточная ссылка класса
		 	// and after setting Count-=2 --> 0,	\Ref_obj_foreign и при обну-
		 	// it performs re-linking of the object	\лении счетчика запускается
		 	// referencing back to the source thread\отправка объекта в исходную
		 	//										\нить
			A.set_obj(i, Ai.Obj.NONE_obj_instance());
		 }
	}
	
	//__________________________________________________
	// yield a single object	\ возврат одного объекта
	public void yield_single_object(Ref_obj Ai)
	{
		 	//[diagram:Object_separate2]
			Ref_obj h = Ai.Obj.hard_link;
			Ref_obj w = Ai.Obj.weak_link;
			
			AL4_object a = Ai.Obj;
			
			a.hard_link = new Ref_obj_foreign(a, 2);
			a.hard_link.Parent_ref = h.Parent_ref;
			h.Parent_ref.Migrated_ref = a.hard_link;
			h.Obj = a.NONE_obj_instance().Obj;
			h.Parent_ref = null;
			h.Count -= 2;
			a.hard_link.Migrated_ref = a.hard_link;
			//[diagram:Object_yield_forced]
			//[diagram:Object_yield_forced2]
			
			a.weak_link = new Ref_obj(a, 1);
			a.weak_link.Parent_ref = w.Parent_ref;
			w.Parent_ref.Migrated_ref = a.weak_link;
			w.Obj = a.NONE_obj_instance().Obj;
			w.Parent_ref = null;
			w.Count -= 2;
			a.weak_link.Migrated_ref = a.weak_link;
			
			a.hard_link.Ref_dec_hard();
	}
}



//_________________________________________________________________________
// class overriding Ref_obj to be used	\класс переопределяющий Ref_obj для
// as a temp reference while the object	\использования в подчиненном потоке
// lives in another thread				\взамен исходного ссылочного объекта
public class Ref_obj_foreign : Ref_obj
{
	//------------------------------------------------------------------------
	// the constructor does not change anything	\ конструктор ничего не меняет
 	public Ref_obj_foreign(AL4_object obj, int count) : base(obj, count)
 	{ }
	
 	//--------------------------------------------------------------------------
 	//redefining Ref_dec_hard, we use it	\переопределяем Ref_dec_hard, вместо
 	//not to destroy the object but to		\уничтожения объекта отправляем его
 	//return it to the sending (master)		\назад к нити-отправителю, когда его
 	//thread when its Count becomes == 0	\счетчик Count становится равен 0
	public override void Ref_dec_hard()
    {
        Obj.hard_link.Count -= 2;
        if (Obj.hard_link.Count == 0)
        {
        	if (Obj.hard_link.Parent_ref != null)
        	{
        	
				//still this is a migrant reference,	\ это все еще ссылка на
				//we just move it back to				\ мигрировавший объект,
				//the parent thread now					\ возвратим его домой
				
	        	//Thread.BeginCriticalRegion();
				try
				{
					AL4_object Z = Obj;
					
					Ref_obj w = Obj.weak_link;
					Z.weak_link = Obj.weak_link.Parent_ref;
					Z.weak_link.Obj = Z;
					Z.weak_link.Migrated_ref = null;
					
					//[diagram:Object_ref_dec_hard1]
					Ref_obj h = Obj.hard_link;
					Z.hard_link = Obj.hard_link.Parent_ref;
					Z.hard_link.Obj = Z;
					Z.hard_link.Migrated_ref = null;
					
					h.Obj = Obj.NONE_obj_instance().Obj;
					w.Obj = h.Obj;
					//[diagram:Object_ref_dec_hard2]
					
					rejoin_fields(Z.hard_link);
					
					if (Obj.hard_link.Count == 0)
					{
						//the object was created as		\ объект был создан как
						//an owned, and while it was	\ дочерний, и пока он
						//abroad its parent has died,	\ отсутствовал дома, его
						//so we should now rip the		\ хозяин умер, так что
						//returned object with him		\ он тоже должен умереть
						
						Obj.hard_link.Count+=2;
						base.Ref_dec_hard();
					
					}
					
			    }
	        	finally
	        	{
	        		//Thread.EndCriticalRegion();
	        	}
        	}
        	else
        	{
        		Obj.hard_link.Count += 2;
        		base.Ref_dec_hard();
        	}
        }
    }
    
	// handling fields of the X object	\ обработка полей объекта X
	// returning home					\ при возвращении его домой
	void rejoin_fields(Ref_obj X)
	{
		int c_fields = X.Obj.RTTI_object_field_count();
		for (int j = 0; j < c_fields; j++)
		{
			//C_RTTI.Ob_field_data f_info = new C_RTTI.Ob_field_data(); 
			//X.Obj.RTTI_object_field_info(f_info, j, 0);
			int type_index = X.Obj.RTTI_object_info_field(j, 0);
			if (AL4_object.RTTI_type_kind(type_index) != 3)
				continue; 
			// only object fields \ интересуют только объектные поля
			
			bool is_weak = false;
			string f_name = X.Obj.RTTI_object_field_name(j);
			is_weak = f_name[f_name.Length-1] == '_';

			int last = 1;
			if (X.Obj.RTTI_object_info_field(j, 0) > 0)
				last = X.Obj.RTTI_object_info_field(j, 4);
			
			//........... what if field				\что если поле было NONE при
			//was NONE but assigned in the thread ?	\отправке, но присвоено пока
			//see below.							\находилось в нити: см. ниже
			if (is_weak)
			{
				for (int k = 0; k < last; k++)
				{
					Ref_obj Bk = X.Obj.RTTI_object_get_object(j, k);
					Bk = rejoin_object_ref(X, Bk, false);
					X.Obj.RTTI_object_set_object(j, Bk, k);
				}
			}
			else
			{
				for (int k = 0; k < last; k++)
				{
					Ref_obj Bk = X.Obj.RTTI_object_get_object(j, k);
					Bk = rejoin_object_ref(X, Bk, true);
					X.Obj.RTTI_object_set_object(j, Bk, k);
					rejoin_fields(Bk);
				}
			}
		}
	}
	
	public Ref_obj rejoin_object_ref(Ref_obj S_ref_from_dummy, Ref_obj R,
		bool is_hard_link)
	{
		if (R.Obj.Is_NONE_object &&
			R.Migrated_ref != null &&
			R.Migrated_ref.Parent_ref == R
			) //[diagram:rejoin_object_ref]
		{
			R.Migrated_ref.Parent_ref = null;
			return R.Migrated_ref;
			//[diagram:rejoin_object_ref2] - after re-assign result to a field
		}
		if (!R.Obj.Is_NONE_object &&
			R.Migrated_ref != null &&
			R.Migrated_ref.Parent_ref == R
			) //[diagram:rejoin_object_ref_changed] -- object was changed
		{
			if (!is_hard_link || R.Count >= 4)
			{
				Ref_obj m = R.Migrated_ref;
				m.Parent_ref = null;
				R.Migrated_ref = null;
				R.Ref_dec_hard();
				return m;
			}
			Ref_obj M = R.Migrated_ref;
			M.Parent_ref = null;
			R.Migrated_ref = null;
			M.Ref_dec_hard();
		}
		return R;
	}
	
}

/*
END
*/
