/*

CLASS {NATIVE_Thread|_Android},
UNTESTED, NATIVE:

IMPORT, ANYWAY: {Thread} .

NATIVE: "///COPY NATIVE_Thread.*" .
NATIVE: "import java.lang.Thread;" .
NATIVE: "import android.os.SystemClock;" .
NATIVE: "import android.os.Looper;" .

*/

import java.lang.Thread;
import java.util.ArrayList;
import android.os.SystemClock;
import android.os.Looper;

public class NATIVE_Thread extends Thread
{

public int C11; 
public static ArrayList<NATIVE_Thread> All_threads = new ArrayList<NATIVE_Thread>();


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

	public static int Total_count_running_threads = 0;

/*

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

FUNCTION Create_thread(
{Thread} Thread|_object) ==> INT, NATIVE:
@	"NATIVE_Thread t = new NATIVE_Thread();"
	"t.C11 = 2;"
	"t.ref_C_Thread = (C_Thread)X_Thread.Obj;"
	"synchronized(NATIVE_Thread.All_threads)"
	"{"
		"int i = NATIVE_Thread.All_threads.indexOf(null);"
		"if (i >= 0) {"
		"	NATIVE_Thread.All_threads.set(i, t);"
		"	t.Thread_handle = i+1;"
		"}"
		"else"
		"{"
		"	NATIVE_Thread.All_threads.add(t);"
		"	t.Thread_handle = NATIVE_Thread.All_threads.size();"
		"}"
	"}"
	"RESULT = t.Thread_handle;"
	.
	
FUNCTION Destroy_thread_handle(
{Thread} Thread|_destroying), NATIVE :
	INT h|andle_of_thread = Thread.Handle
	CASE h == 0 ? ==> ;
	NATIVE @ 
	"NATIVE_Thread t;"	
	"synchronized(NATIVE_Thread.All_threads)"
	"{"
    "	t = NATIVE_Thread.All_threads.get(X_h - 1);"
	"   if (t != null) {"
	"      t.C11 --;"
	"      if (t.C11 == 0)"
	"		   NATIVE_Thread.All_threads.set(X_h - 1, null);"
	"	   else t = null;"
	"	}"
	"}"
	"if (t != null) {"
	"   t.data_arrive = null;"
	"   t.Thread_handle = 0;" 
	"}"
	.		
	
FUNCTION Thread_is_main ==> BOOL, NATIVE :
@	"RESULT = Looper.getMainLooper() == Looper.myLooper();"
	.
	
FUNCTION Thread_run({Thread} Thread|_object), NATIVE :
	CASE Thread.Handle <= 0 ? ==> ;
	NATIVE
@	"NATIVE_Thread t;"	
	"synchronized(NATIVE_Thread.All_threads)"
	"{"
	"	t = NATIVE_Thread.All_threads.get("
	"		((C_Thread)X_Thread.Obj).F_Handle - 1);"
	"}"
		
	//"		t.thread.Name = ((C_Thread)X_Thread.Obj).F_Handle.ToString();"
	
	"if (t.getState() != Thread.State.NEW) return;"
	"t.start();" 
	//"t.thread_started.WaitOne();" 
	.
	
FUNCTION Thread_ended(INT Handle|_thread) ==> BOOL, NATIVE :
	CASE Handle <= 0 ? ==> ;
	NATIVE
@	"NATIVE_Thread t;"	
	"synchronized(NATIVE_Thread.All_threads)"
	"{"
	"	t = NATIVE_Thread.All_threads.get(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.getState() == Thread.State.TERMINATED;"
	.
	
FUNCTION Thread_stop(
INT Handle|_thread, BOOL Terminate), NATIVE:
	CASE Handle <= 0 ? ==> ;
	NATIVE
@	"NATIVE_Thread t;"	
	"synchronized(NATIVE_Thread.All_threads)"
	"{"
	"	t = NATIVE_Thread.All_threads.get(X_Handle - 1);"
	"}"	
	"if (t.getState() == Thread.State.TERMINATED)"
	"	 return;"
	"t.interrupt();" .
	
CONST STR :
	Native_import = @
	"import java.lang.Thread;"	
	"import android.os.SystemClock;"

	Native_wait_threads = @
    "long start_at = SystemClock.uptimeMillis();"
    "while(true) {"
    "    RESULT = true;"
    "    for (int i = 0; i < X_A.Count(); i++)"
    "    {"
    "         C_Thread cT = (C_Thread)X_A.Get_item(i).Obj;"
    "         NATIVE_Thread t = NATIVE_Thread.All_threads.get("
    "			cT.F_Handle - 1);"
    "         boolean ended = t.getState() == Thread.State.TERMINATED;"
    "         if (!ended) RESULT = false;"
    "	 }"
    "    if (RESULT) break;"
    "	 if (X_Max > 0 && SystemClock.uptimeMillis() - start_at > X_Max) break;"
    "    Thread.sleep(1);"
    "}"
	.

FUNCTION Thread_priority(
INT Handle|_thread) ==> {Thread}.{priority}, NATIVE:
	CASE Handle <= 0 ? ==> ;
	NATIVE
@	"NATIVE_Thread t;"
	"synchronized(NATIVE_Thread.All_threads)"
	"{"
	"	t = NATIVE_Thread.All_threads.get(X_Handle - 1);"
	"}"	
	"RESULT = (byte)((t.getPriority() - 1) * 4 / 9);" .
	
FUNCTION Thread_set_priority(
INT Handle|_thread, {priority} Priority), NATIVE:
	CASE Handle <= 0 ? ==> ;
	NATIVE
@	"NATIVE_Thread t;"	
	"synchronized(NATIVE_Thread.All_threads)"
	"{"
	"	t = NATIVE_Thread.All_threads.get(X_Handle - 1);"
	"}"	
	"t.setPriority(X_Priority * 9 / 4 + 1);" .
	
FUNCTION Thread_take_objects(
INT Handle|_thread, {Object} A|rray_of_objects_passed[*],
BOOL Together|_with_hard_linked), NATIVE:
	CASE Handle <= 0 ? ==> ;
	NATIVE
@	"NATIVE_Thread t;"	
	"synchronized(NATIVE_Thread.All_threads)"
	"{"
	"	t = NATIVE_Thread.All_threads.get(X_Handle - 1);"
	"}"	
	"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
@	"NATIVE_Thread t;"	
	"synchronized(NATIVE_Thread.All_threads)"
	"{"
	"	t = NATIVE_Thread.All_threads.get(X_Handle - 1);"
	"}"	
	"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
@	"NATIVE_Thread t;"	
	"synchronized(NATIVE_Thread.All_threads)"
	"{"
	"	t = NATIVE_Thread.All_threads.get(X_Handle - 1);"
	"}"	
	"t.yield_objects(X_A);" .
	
FUNCTION Is_thread_running(
INT Handle|_thread) ==> BOOL, NATIVE
	:
	CASE Handle <= 0 ? ==> ;
	NATIVE
@	"NATIVE_Thread t;"	
	"synchronized(NATIVE_Thread.All_threads)"
	"{"
	"	t = NATIVE_Thread.All_threads.get(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 = new AutoResetEvent(false);

	//____________________________________________________
	// {Thread}.execute --> Thread_run --> Execute_routine
	@Override
	public void run()
	{
	  Total_count_running_threads += 1;
	  try {
		try {
	
		  //simulate here Take					\симулируем здесь передачу Take 
		  //for the ref_C_Thread object itself	\самого объекта нити ref_C_Thread
		  Ref_obj X;
		  synchronized(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;
		  }
		  
		  //thread_started.Set();
		  ((C_Thread)X.Obj).F_running = true;
		  //call executing the user defined			\вызываем пользовательскую
		  //function which is running in the thread	\функцию для исполнения нити
		  ((C_Thread)X.Obj).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								\скую нить
		  synchronized(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;
		}
	  }
	  catch(Exception ex) {}
	}
	
	//_______________________________________________________
	// {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, boolean Together)
	{
		//lock(protect_take_yield)
		{
			for (int i = 0; i < A.Count(); i++)
			{
				Ref_obj Ai = A.Get_item(i);
				if (Ai.Obj.Is_NONE_object) continue;
				
				take_single_object(Ai, Together, true);
			}
			if (queue_input_objects.size() > 0)
			{
				//there are received objects:	\есть принятые объекты в очереди
				//set the flag to end waiting	\установка флага для прекращения
				//receiving object event		\ожидания принятых объектов
				synchronized(data_arrive) {
					data_arrived = true;
				}
			}
		}
	}
	
	//____________________________________________________________________
	//take a single object to the thread	\передача единичного объекта в
	//started (from the parent thread)		\запущенную подчиненную нить
	public Ref_obj take_single_object(Ref_obj Ai, boolean Together,
		   boolean 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;

			boolean is_weak = false;
			if (Together)
			{
				String f_name = Ai.Obj.RTTI_object_field_name(j);
				is_weak = f_name.charAt(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 ArrayList<Ref_obj> queue_input_objects = new ArrayList<Ref_obj>();
	
	//the event to wait receiving objects	\событие для ожидания приемки объектов
	Object data_arrive = new Object();
	boolean data_arrived = false;
	
	//____________________________________________________
	// receive objects --> \приемка отправленных объектов 
	public void receive_objects(ArrayObjHard A, boolean Wait) throws Exception
	{
		boolean wait_and_try_again = false;
		synchronized(protect_take_yield)
		{
			if (queue_input_objects.size() == 0 && !Wait) return;
			if (queue_input_objects.size() == 0)
			{
				wait_and_try_again = true;
			}
			else
			for (int i = 0; i < queue_input_objects.size(); i++)
			{
				Ref_obj Di = queue_input_objects.get(i);
				A.Add(Di);
				receive_single_object(Di);
			}
		}
		if (!wait_and_try_again) return;
		//second attempt, after wait	\повторная попытка, после ожидания
		synchronized(protect_take_yield)
		{
			//waiting	\ожидание
			while (true) {
				synchronized(data_arrive) {
					if (data_arrived) break;
				}
				Thread.sleep(1);
			}
			for (int i = 0; i < queue_input_objects.size(); i++)
			{
				Ref_obj Di = queue_input_objects.get(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;
				
			boolean is_weak = false;
			String f_name = Di.Obj.RTTI_object_field_name(j);
			is_weak = f_name.charAt(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) throws Exception
	{
		 for (int i = 0; i < A.Count(); i++)
		 {
		 	Ref_obj Ai = A.Get_item(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_item(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_item(i, Ai.Obj.NONE_obj_instance());
		 }
	}
	
	//__________________________________________________
	// yield a single object	\ возврат одного объекта
	public void yield_single_object(Ref_obj Ai) throws Exception
	{
		 	//[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 static class Ref_obj_foreign extends Ref_obj
{
	//------------------------------------------------------------------------
	// the constructor does not change anything	\ конструктор ничего не меняет
 	public Ref_obj_foreign(AL4_object obj, int count) { 
 		super(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
 	@Override
	public void Ref_dec_hard() throws Exception
    {
        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;
						super.Ref_dec_hard();
					
					}
					
			    }
	        	finally
	        	{
	        		//Thread.EndCriticalRegion();
	        	}
        	}
        	else
        	{
        		Obj.hard_link.Count += 2;
        		super.Ref_dec_hard();
        	}
        }
    }
    
	// handling fields of the X object	\ обработка полей объекта X
	// returning home					\ при возвращении его домой
	void rejoin_fields(Ref_obj X) throws Exception
	{
		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 \ интересуют только объектные поля
			
			boolean is_weak = false;
			String f_name = X.Obj.RTTI_object_field_name(j);
			is_weak = f_name.charAt(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,
		boolean is_hard_link) throws Exception
	{
		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
*/
