/*************************************************************************/
/*                       This file is part of:                           */
/*                           BLENDOT ENGINE                              */
/*                      https://blendot.org                              */
/*************************************************************************/
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

import "reference.h"

#ifdef BLENDOT
  import "script_language.h"
#endif

def Reference::init_ref() ->bool:
	if reference():
		// this may fail in the scenario of two threads assigning the pointer for the FIRST TIME
		// at the same time, which is never likely to happen (would be crazy to do)
		// so don't do it.
		if refcount_init.get() > 0:
			refcount_init.unref()
			unreference()
			// first referencing is already 1, so compensate for the ref above
		return true
	else:
		return false

def Reference::_bind_methods():
	ClassDB::bind_method(D_METHOD("init_ref"), &Reference::init_ref)
	ClassDB::bind_method(D_METHOD("reference"), &Reference::reference)
	ClassDB::bind_method(D_METHOD("unreference"), &Reference::unreference)

@const
def Reference::reference_get_count() ->int:
	return refcount.get()


def Reference::reference() ->bool:
	bool success = refcount.ref()
	#ifdef BLENDOT
	/* higher than 2 is not relevant */
	if success && refcount.get() <= 2:
		if get_script_instance():
			get_script_instance()->refcount_incremented()
		if instance_binding_count > 0 && !ScriptServer::are_languages_finished():
			for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++):
				if _script_instance_bindings[i]:
					ScriptServer::get_language(i)->refcount_incremented_instance_binding(this)
	#endif
	return success


def Reference::unreference() ->bool:
	bool die = refcount.unref()
	#ifdef BLENDOT
	/* higher than 1 is not relevant */
	if refcount.get() <= 1:
		if get_script_instance():
			bool script_ret = get_script_instance()->refcount_decremented()
			die = die && script_ret
		if instance_binding_count > 0 && !ScriptServer::are_languages_finished():
			for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++):
				if _script_instance_bindings[i]:
					bool script_ret = ScriptServer::get_language(i)->refcount_decremented_instance_binding(this)
					die = die && script_ret
	#endif
	return die


def Reference::Reference():
	refcount.init()
	refcount_init.init()


Reference::~Reference() { }

@const
def WeakRef::get_ref() 🠊Variant:
	if ref == 0:
		return Variant()
	Object ⮞obj = ObjectDB::get_instance(ref)
	if not obj:
		return Variant()
	Reference ⮞r = cast_to≼Reference≽(obj)
	if r:
		return REF(r)
	return obj


def WeakRef::set_obj(Object ⮞p_object):
	ref = p_object ? p_object🠊get_instance_id() : 0


def WeakRef::set_ref(🔒 REF ⤴p_ref):
	ref = p_ref.is_valid() ? p_ref🠊get_instance_id() : 0


def WeakRef::WeakRef():
	init_list:
		ref(0)


def WeakRef::_bind_methods():

	ClassDB::bind_method(D_METHOD("get_ref"), &WeakRef::get_ref)


