#include "ShipInitialStatusDialogModel.h"

#include "mission/object.h"

#include <globalincs/linklist.h>
#include <localization/localize.h>

#include <QtWidgets>
#include <object/objectdock.cpp>

namespace fso::fred::dialogs {
void reset_arrival_to_false(int shipnum, bool reset_wing, EditorViewport* _viewport)
{
	char buf[256];
	ship* shipp = &Ships[shipnum];

	// falsify the ship cue
	if (set_cue_to_false(&shipp->arrival_cue)) {
		sprintf(buf, "Setting arrival cue of ship %s\nto false for initial docking purposes.", shipp->ship_name);
		// MessageBox(NULL, buf, "", MB_OK | MB_ICONEXCLAMATION);
		_viewport->dialogProvider->showButtonDialog(DialogType::Information, "Notice", buf, {DialogButton::Ok});
	}

	// falsify the wing cue and all ships in that wing
	if (reset_wing && shipp->wingnum >= 0) {
		int i;
		wing* wingp = &Wings[shipp->wingnum];

		if (set_cue_to_false(&wingp->arrival_cue)) {

			sprintf(buf, "Setting arrival cue of wing %s\nto false for initial docking purposes.", wingp->name);
			// MessageBox(NULL, buf, "", MB_OK | MB_ICONEXCLAMATION);
			_viewport->dialogProvider->showButtonDialog(DialogType::Information, "Notice", buf, {DialogButton::Ok});
		}

		for (i = 0; i < wingp->wave_count; i++)
			reset_arrival_to_false(wingp->ship_index[i], false, _viewport);
	}
}
bool set_cue_to_false(int* cue)
{
	// if the cue is not false, make it false.  Be sure to set all ship editor dialog functions
	// to update data before and after we modify the cue.
	// Comment Above Prbably not nesscary due to new model
	if (*cue != Locked_sexp_false) {

		free_sexp2(*cue);
		*cue = Locked_sexp_false;

		return true;
	} else
		return false;
}

// self-explanatory, really
void initial_status_unmark_dock_handled_flag(object* objp)
{
	objp->flags.remove(Object::Object_Flags::Docked_already_handled);
}
void initial_status_mark_dock_leader_helper(object* objp, dock_function_info* infop, EditorViewport* viewport)
{
	ship* shipp = &Ships[objp->instance];
	int cue_to_check;

	// if this guy is part of a wing, he uses his wing's arrival cue
	if (shipp->wingnum >= 0) {
		cue_to_check = Wings[shipp->wingnum].arrival_cue;
	}
	// check the ship's arrival cue
	else {
		cue_to_check = shipp->arrival_cue;
	}

	// all ships except the leader should have a locked false arrival cue
	if (cue_to_check != Locked_sexp_false) {
		object* existing_leader;

		// increment number of leaders found
		infop->maintained_variables.int_value++;

		// see if we already found a leader
		existing_leader = infop->maintained_variables.objp_value;
		if (existing_leader != nullptr) {
			ship* leader_shipp = &Ships[existing_leader->instance];

			// keep existing leader if he has a higher priority than us
			if (ship_class_compare(shipp->ship_info_index, leader_shipp->ship_info_index) >= 0) {
				// set my arrival cue to false
				reset_arrival_to_false(SHIP_INDEX(shipp), true, viewport);
				return;
			}

			// otherwise, unmark the existing leader and set his arrival cue to false
			leader_shipp->flags.remove(Ship::Ship_Flags::Dock_leader);
			reset_arrival_to_false(SHIP_INDEX(leader_shipp), true, viewport);
		}

		// mark and save me as the leader
		shipp->flags.set(Ship::Ship_Flags::Dock_leader);
		infop->maintained_variables.objp_value = objp;
	}
}
ShipInitialStatusDialogModel::ShipInitialStatusDialogModel(QObject* parent, EditorViewport* viewport, bool multi)
	: AbstractDialogModel(parent, viewport)
{
	initializeData(multi);
}

void ShipInitialStatusDialogModel::initializeData(bool multi)
{
	m_multi_edit = multi;
	int vflag, sflag, hflag;
	object* objp = nullptr;
	m_ship = _editor->cur_ship;
	if (m_ship == -1) {
		Assert(
			(Objects[_editor->currentObject].type == OBJ_SHIP) || (Objects[_editor->currentObject].type == OBJ_START));
		m_ship = get_ship_from_obj(_editor->currentObject);
		Assert(m_ship >= 0);
	}

	// initialize dockpoint stuff
	if (!m_multi_edit) {
		num_dock_points = model_get_num_dock_points(Ship_info[Ships[m_ship].ship_info_index].model_num);
		dockpoint_array = new dockpoint_information[num_dock_points];
		objp = &Objects[Ships[m_ship].objnum];
		for (int i = 0; i < num_dock_points; i++) {
			object* docked_objp = dock_find_object_at_dockpoint(objp, i);
			if (docked_objp != nullptr) {
				dockpoint_array[i].dockee_shipnum = docked_objp->instance;
				dockpoint_array[i].dockee_point = dock_find_dockpoint_used_by_object(docked_objp, objp);
			} else {
				dockpoint_array[i].dockee_shipnum = -1;
				dockpoint_array[i].dockee_point = -1;
			}
		}
	}
	vflag = sflag = hflag = 0;
	m_velocity = static_cast<int>(Objects[_editor->currentObject].phys_info.speed);
	m_shields = static_cast<int>(Objects[_editor->currentObject].shield_quadrant[0]);
	m_hull = static_cast<int>(Objects[_editor->currentObject].hull_strength);
	guardian_threshold = Ships[m_ship].ship_guardian_threshold;
	if (Objects[_editor->currentObject].flags[Object::Object_Flags::No_shields])
		m_has_shields = 0;
	else
		m_has_shields = 1;

	if (Ships[m_ship].flags[Ship::Ship_Flags::Force_shields_on])
		m_force_shields = 1;
	else
		m_force_shields = 0;

	if (Ships[m_ship].flags[Ship::Ship_Flags::Ship_locked])
		m_ship_locked = 1;
	else
		m_ship_locked = 0;

	if (Ships[m_ship].flags[Ship::Ship_Flags::Weapons_locked])
		m_weapons_locked = 1;
	else
		m_weapons_locked = 0;
	// Lock primaries
	if (Ships[m_ship].flags[Ship::Ship_Flags::Primaries_locked]) {
		m_primaries_locked = 1;
	} else {
		m_primaries_locked = 0;
	}
	// Lock secondaries
	if (Ships[m_ship].flags[Ship::Ship_Flags::Secondaries_locked]) {
		m_secondaries_locked = 1;
	} else {
		m_secondaries_locked = 0;
	}

	// Lock turrets
	if (Ships[m_ship].flags[Ship::Ship_Flags::Lock_all_turrets_initially]) {
		m_turrets_locked = 1;
	} else {
		m_turrets_locked = 0;
	}

	if (Ships[m_ship].flags[Ship::Ship_Flags::Afterburner_locked]) {
		m_afterburner_locked = 1;
	} else {
		m_afterburner_locked = 0;
	}

	if (m_multi_edit) {
		objp = GET_FIRST(&obj_used_list);
		while (objp != END_OF_LIST(&obj_used_list)) {
			if (((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) &&
				(objp->flags[Object::Object_Flags::Marked])) {
				if (objp->phys_info.speed != m_velocity)
					vflag = 1;
				if (static_cast<int>(objp->shield_quadrant[0]) != m_shields)
					sflag = 1;
				if (static_cast<int>(objp->hull_strength) != m_hull)
					hflag = 1;
				if (objp->flags[Object::Object_Flags::No_shields]) {
					if (m_has_shields)
						m_has_shields = 1;

				} else {
					if (!m_has_shields)
						m_has_shields = 1;
				}

				Assert((objp->type == OBJ_SHIP) || (objp->type == OBJ_START));

				if (Ships[get_ship_from_obj(objp)].flags[Ship::Ship_Flags::Force_shields_on]) {
					if (!m_force_shields)
						m_force_shields = Qt::PartiallyChecked;

				} else {
					if (m_force_shields)
						m_force_shields = Qt::PartiallyChecked;
				}

				if (Ships[get_ship_from_obj(objp)].flags[Ship::Ship_Flags::Ship_locked]) {
					if (!m_ship_locked)
						m_ship_locked = Qt::PartiallyChecked;

				} else {
					if (m_ship_locked)
						m_ship_locked = Qt::PartiallyChecked;
				}

				if (Ships[get_ship_from_obj(objp)].flags[Ship::Ship_Flags::Weapons_locked]) {
					if (!m_weapons_locked)
						m_weapons_locked = Qt::PartiallyChecked;

				} else {
					if (m_weapons_locked)
						m_weapons_locked = Qt::PartiallyChecked;
				}

				if (Ships[get_ship_from_obj(objp)].flags[Ship::Ship_Flags::Primaries_locked]) {
					if (!m_primaries_locked)
						m_primaries_locked = Qt::PartiallyChecked;
				} else {
					if (m_primaries_locked)
						m_primaries_locked = Qt::PartiallyChecked;
				}

				if (Ships[get_ship_from_obj(objp)].flags[Ship::Ship_Flags::Secondaries_locked]) {
					if (!m_secondaries_locked)
						m_secondaries_locked = Qt::PartiallyChecked;
				} else {
					if (m_secondaries_locked)
						m_secondaries_locked = Qt::PartiallyChecked;
				}

				if (Ships[get_ship_from_obj(objp)].flags[Ship::Ship_Flags::Lock_all_turrets_initially]) {
					if (!m_turrets_locked)
						m_turrets_locked = Qt::PartiallyChecked;
				} else {
					if (m_turrets_locked)
						m_turrets_locked = Qt::PartiallyChecked;
				}

				if (Ships[get_ship_from_obj(objp)].flags[Ship::Ship_Flags::Afterburner_locked]) {
					if (!m_afterburner_locked)
						m_afterburner_locked = Qt::PartiallyChecked;
				} else {
					if (m_afterburner_locked)
						m_afterburner_locked = Qt::PartiallyChecked;
				}
			}

			objp = GET_NEXT(objp);
		}
	}

	if (objp != nullptr) {
		if (objp->type == OBJ_SHIP || objp->type == OBJ_START) {
			ship* shipp = &Ships[objp->instance];

			if (Ship_info[shipp->ship_info_index].uses_team_colors) {
				m_use_teams = true;
			}
		}
	}
	change_subsys(0);

	if (vflag) {
		m_velocity = BLANKFIELD;
	}
	if (vflag) {
		m_velocity = BLANKFIELD;
	}
	if (vflag) {
		m_velocity = BLANKFIELD;
	}
	modelChanged();
}

void ShipInitialStatusDialogModel::update_docking_info()
{
	int i;
	object* objp = &Objects[Ships[m_ship].objnum];
	for (i = 0; i < num_dock_points; i++) {
		// see if the object at this point is no longer there
		object* dockee_objp = dock_find_object_at_dockpoint(objp, i);
		if (dockee_objp != nullptr) {
			// check if the dockee ship thinks that this ship is docked to this dock point
			if (objp != dock_find_object_at_dockpoint(dockee_objp, dockpoint_array[i].dockee_point)) {
				// undock it
				undock(objp, dockee_objp);
			}
		}
	}
	// add new info
	for (i = 0; i < num_dock_points; i++) {
		// see if there is an object at this point that wasn't there before
		if (dockpoint_array[i].dockee_shipnum >= 0) {
			if (dock_find_object_at_dockpoint(objp, i) == nullptr) {
				object* dockee_objp = &Objects[Ships[dockpoint_array[i].dockee_shipnum].objnum];
				int dockee_point = dockpoint_array[i].dockee_point;

				// dock it
				dock(objp, i, dockee_objp, dockee_point);
			}
		}
	}

	_editor->missionChanged();
}
void ShipInitialStatusDialogModel::undock(object* objp1, object* objp2)
{
	vec3d v;
	int ship_num, other_ship_num;
	if (objp1 == nullptr || objp2 == nullptr)
		return;
	vm_vec_sub(&v, &objp2->pos, &objp1->pos);
	vm_vec_normalize(&v);
	ship_num = get_ship_from_obj(OBJ_INDEX(objp1));
	other_ship_num = get_ship_from_obj(OBJ_INDEX(objp2));

	if (_viewport->Move_ships_when_undocking) {
		if (ship_class_compare(Ships[ship_num].ship_info_index, Ships[other_ship_num].ship_info_index) <= 0) {
			vm_vec_scale_add2(&objp2->pos,
				&v,
				ship_class_get_length(&Ship_info[Ships[objp2->instance].ship_info_index]));
		} else {
			vm_vec_scale_add2(&objp1->pos,
				&v,
				ship_class_get_length(&Ship_info[Ships[objp1->instance].ship_info_index]) * -1.0f);
		}
	}

	ai_do_objects_undocked_stuff(objp1, objp2);

	// check to see if one of these ships has an arrival cue of false.  If so, then
	// reset it back to default value of true.  be sure to correctly update before
	// and after setting data.
	// Goober5000 - but don't reset it if it's part of a wing!

	if (Ships[ship_num].arrival_cue == Locked_sexp_false && Ships[ship_num].wingnum < 0) {
		Ships[ship_num].arrival_cue = Locked_sexp_true;
	} else if (Ships[other_ship_num].arrival_cue == Locked_sexp_false && Ships[other_ship_num].wingnum < 0) {
		Ships[other_ship_num].arrival_cue = Locked_sexp_true;
	}
	// if this ship is no longer docked, ensure its dock leader flag is clear
	if (!object_is_docked(&Objects[Ships[ship_num].objnum]))
		Ships[ship_num].flags.remove(Ship::Ship_Flags::Dock_leader);

	// same for the other ship
	if (!object_is_docked(&Objects[Ships[other_ship_num].objnum]))
		Ships[other_ship_num].flags.remove(Ship::Ship_Flags::Dock_leader);
}
void ShipInitialStatusDialogModel::dock(object* objp, int dockpoint, object* other_objp, int other_dockpoint)
{
	if (objp == nullptr || other_objp == nullptr) {
		return;
	}

	if (dockpoint < 0 || other_dockpoint < 0) {
		return;
	}

	dock_function_info dfi;

	// do the docking (do it in reverse so that the current object stays put)
	ai_dock_with_object(other_objp, other_dockpoint, objp, dockpoint, AIDO_DOCK_NOW);

	// unmark the handled flag in preparation for the next step
	dock_evaluate_all_docked_objects(objp, &dfi, initial_status_unmark_dock_handled_flag);

	// move all other objects to catch up with it
	dock_move_docked_objects(objp);

	// set the dock leader
	dock_evaluate_all_docked_objects(objp, &dfi, initial_status_mark_dock_leader_helper);

	// if no leader, mark me
	if (dfi.maintained_variables.int_value == 0)
		Ships[objp->instance].flags.set(Ship::Ship_Flags::Dock_leader);
}
// Duplicated from objectdock to handle scope errors
void ShipInitialStatusDialogModel::dock_evaluate_all_docked_objects(object* objp,
	dock_function_info* infop,
	void (*function)(object*, dock_function_info*, EditorViewport*))
{
	Assertion((objp != nullptr) && (infop != nullptr) && (function != nullptr),
		"dock_evaluate_all_docked_objects, invalid argument(s)");

	// not docked?
	if (!object_is_docked(objp)) {
		// call the function for just the one object
		function(objp, infop, _viewport);
		return;
	}

	// we only have two objects docked
	if (dock_check_docked_one_on_one(objp)) {
		// call the function for the first object, and return if instructed
		function(objp, infop, _viewport);
		if (infop->early_return_condition)
			return;

		// call the function for the second object, and return if instructed
		function(objp->dock_list->docked_objp, infop, _viewport);
		if (infop->early_return_condition)
			return;
	}

	// we have multiple objects docked and we're treating them as a hub
	else if (dock_check_assume_hub()) {
		// get the hub
		object* hub_objp = dock_get_hub(objp);

		// call the function for the hub, and return if instructed
		function(hub_objp, infop, _viewport);
		if (infop->early_return_condition)
			return;

		// iterate through all docked objects
		for (dock_instance* ptr = hub_objp->dock_list; ptr != nullptr; ptr = ptr->next) {
			// call the function for this object, and return if instructed
			function(ptr->docked_objp, infop, _viewport);
			if (infop->early_return_condition)
				return;
		}
	}

	// we have multiple objects docked and we must treat them as a tree
	else {
		// create a bit array to mark the objects we check
		auto visited_bitstring = (ubyte*)vm_malloc(calculate_num_bytes(MAX_OBJECTS));

		// clear it
		memset(visited_bitstring, 0, calculate_num_bytes(MAX_OBJECTS));

		// start evaluating the tree
		dock_evaluate_tree(objp, infop, function, visited_bitstring);

		// destroy the bit array
		vm_free(visited_bitstring);
		visited_bitstring = nullptr;
	}
}

void ShipInitialStatusDialogModel::dock_evaluate_all_docked_objects(object* objp,
	dock_function_info* infop,
	void (*function)(object*))
{
	Assertion((objp != nullptr) && (infop != nullptr) && (function != nullptr),
		"dock_evaluate_all_docked_objects, invalid argument(s)");

	// not docked?
	if (!object_is_docked(objp)) {
		// call the function for just the one object
		function(objp);
		return;
	}

	// we only have two objects docked
	if (dock_check_docked_one_on_one(objp)) {
		// call the function for the first object, and return if instructed
		function(objp);
		if (infop->early_return_condition)
			return;

		// call the function for the second object, and return if instructed
		function(objp->dock_list->docked_objp);
		if (infop->early_return_condition)
			return;
	}

	// we have multiple objects docked and we're treating them as a hub
	else if (dock_check_assume_hub()) {
		// get the hub
		object* hub_objp = dock_get_hub(objp);

		// call the function for the hub, and return if instructed
		function(hub_objp);
		if (infop->early_return_condition)
			return;

		// iterate through all docked objects
		for (dock_instance* ptr = hub_objp->dock_list; ptr != nullptr; ptr = ptr->next) {
			// call the function for this object, and return if instructed
			function(ptr->docked_objp);
			if (infop->early_return_condition)
				return;
		}
	}

	// we have multiple objects docked and we must treat them as a tree
	else {
		// create a bit array to mark the objects we check
		auto visited_bitstring = (ubyte*)vm_malloc(calculate_num_bytes(MAX_OBJECTS));

		// clear it
		memset(visited_bitstring, 0, calculate_num_bytes(MAX_OBJECTS));

		// start evaluating the tree
		dock_evaluate_tree(objp, infop, function, visited_bitstring);

		// destroy the bit array
		vm_free(visited_bitstring);
		visited_bitstring = nullptr;
	}
}

void ShipInitialStatusDialogModel::dock_evaluate_tree(object* objp,
	dock_function_info* infop,
	void (*function)(object*, dock_function_info*, EditorViewport*),
	ubyte* visited_bitstring)
{
	// make sure we haven't visited this object already
	if (get_bit(visited_bitstring, OBJ_INDEX(objp)))
		return;

	// mark as visited
	set_bit(visited_bitstring, OBJ_INDEX(objp));

	// call the function for this object, and return if instructed
	function(objp, infop, _viewport);
	if (infop->early_return_condition)
		return;

	// iterate through all docked objects
	for (dock_instance* ptr = objp->dock_list; ptr != nullptr; ptr = ptr->next) {
		// start another tree with the docked object as the root, and return if instructed
		dock_evaluate_tree(ptr->docked_objp, infop, function, visited_bitstring);
		if (infop->early_return_condition)
			return;
	}
}

void ShipInitialStatusDialogModel::dock_evaluate_tree(object* objp,
	dock_function_info* infop,
	void (*function)(object*),
	ubyte* visited_bitstring)
{
	// make sure we haven't visited this object already
	if (get_bit(visited_bitstring, OBJ_INDEX(objp)))
		return;

	// mark as visited
	set_bit(visited_bitstring, OBJ_INDEX(objp));

	// call the function for this object, and return if instructed
	function(objp);
	if (infop->early_return_condition)
		return;

	// iterate through all docked objects
	for (dock_instance* ptr = objp->dock_list; ptr != nullptr; ptr = ptr->next) {
		// start another tree with the docked object as the root, and return if instructed
		dock_evaluate_tree(ptr->docked_objp, infop, function, visited_bitstring);
		if (infop->early_return_condition)
			return;
	}
}

bool ShipInitialStatusDialogModel::apply()
{
	object* objp;

	change_subsys(0);
	if (m_multi_edit) {
		objp = GET_FIRST(&obj_used_list);
		while (objp != END_OF_LIST(&obj_used_list)) {
			if (((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) &&
				(objp->flags[Object::Object_Flags::Marked])) {
				modify(objp->phys_info.speed, (float)m_velocity);

				modify(objp->shield_quadrant[0], (float)m_shields);

				modify(objp->hull_strength, (float)m_hull);

				if (m_has_shields == 1) {
					objp->flags.remove(Object::Object_Flags::No_shields);
				} else if (m_has_shields == 0) {
					objp->flags.set(Object::Object_Flags::No_shields);
				}
				auto shipp = &Ships[get_ship_from_obj(objp)];
				shipp->ship_guardian_threshold = guardian_threshold;
				// We need to ensure that we handle the inconsistent "boolean" value correctly
				handle_inconsistent_flag(shipp->flags, Ship::Ship_Flags::Force_shields_on, m_force_shields);
				handle_inconsistent_flag(shipp->flags, Ship::Ship_Flags::Ship_locked, m_ship_locked);
				handle_inconsistent_flag(shipp->flags, Ship::Ship_Flags::Weapons_locked, m_weapons_locked);
				handle_inconsistent_flag(shipp->flags, Ship::Ship_Flags::Primaries_locked, m_primaries_locked);
				handle_inconsistent_flag(shipp->flags, Ship::Ship_Flags::Secondaries_locked, m_secondaries_locked);
				handle_inconsistent_flag(shipp->flags, Ship::Ship_Flags::Lock_all_turrets_initially, m_turrets_locked);
				handle_inconsistent_flag(shipp->flags, Ship::Ship_Flags::Afterburner_locked, m_afterburner_locked);
			}

			objp = GET_NEXT(objp);
		}

	} else {
		modify(Objects[_editor->currentObject].phys_info.speed, (float)m_velocity);
		modify(Objects[_editor->currentObject].shield_quadrant[0], (float)m_shields);
		modify(Objects[_editor->currentObject].hull_strength, (float)m_hull);

		Objects[_editor->currentObject].flags.set(Object::Object_Flags::No_shields, m_has_shields == 0);
		Ships[m_ship].ship_guardian_threshold = guardian_threshold;
		// We need to ensure that we handle the inconsistent "boolean" value correctly. Not strictly needed here but
		// just to be safe...
		handle_inconsistent_flag(Ships[m_ship].flags, Ship::Ship_Flags::Force_shields_on, m_force_shields);
		handle_inconsistent_flag(Ships[m_ship].flags, Ship::Ship_Flags::Ship_locked, m_ship_locked);
		handle_inconsistent_flag(Ships[m_ship].flags, Ship::Ship_Flags::Weapons_locked, m_weapons_locked);
		handle_inconsistent_flag(Ships[m_ship].flags, Ship::Ship_Flags::Primaries_locked, m_primaries_locked);
		handle_inconsistent_flag(Ships[m_ship].flags, Ship::Ship_Flags::Secondaries_locked, m_secondaries_locked);
		handle_inconsistent_flag(Ships[m_ship].flags, Ship::Ship_Flags::Lock_all_turrets_initially, m_turrets_locked);
		handle_inconsistent_flag(Ships[m_ship].flags, Ship::Ship_Flags::Afterburner_locked, m_afterburner_locked);
	}
	Ships[m_ship].team_name = m_team_color_setting;
	update_docking_info();
	_editor->missionChanged();
	return true;
}

void ShipInitialStatusDialogModel::reject() {}

void ShipInitialStatusDialogModel::setVelocity(const int value)
{
	modify(m_velocity, value);
}

int ShipInitialStatusDialogModel::getVelocity() const
{
	return m_velocity;
}

void ShipInitialStatusDialogModel::setHull(const int value)
{
	modify(m_hull, value);
}

int ShipInitialStatusDialogModel::getHull() const
{
	return m_hull;
}

void ShipInitialStatusDialogModel::setHasShield(const int state)
{
	modify(m_has_shields, state);
}

int ShipInitialStatusDialogModel::getHasShield() const
{
	return m_has_shields;
}

void ShipInitialStatusDialogModel::setShieldHull(const int value)
{
	modify(m_shields, value);
}

int ShipInitialStatusDialogModel::getShieldHull() const
{
	return m_shields;
}

void ShipInitialStatusDialogModel::setForceShield(const int state)
{
	modify(m_force_shields, state);
}

int ShipInitialStatusDialogModel::getForceShield() const
{
	return m_force_shields;
}

void ShipInitialStatusDialogModel::setShipLocked(const int state)
{
	modify(m_ship_locked, state);
}

int ShipInitialStatusDialogModel::getShipLocked() const
{
	return m_ship_locked;
}

void ShipInitialStatusDialogModel::setWeaponLocked(const int state)
{
	modify(m_weapons_locked, state);
}

int ShipInitialStatusDialogModel::getWeaponLocked() const
{
	return m_weapons_locked;
}

void ShipInitialStatusDialogModel::setPrimariesDisabled(const int state)
{
	modify(m_primaries_locked, state);
}

int ShipInitialStatusDialogModel::getPrimariesDisabled() const
{
	return m_primaries_locked;
}

void ShipInitialStatusDialogModel::setSecondariesDisabled(const int state)
{
	modify(m_secondaries_locked, state);
}

int ShipInitialStatusDialogModel::getSecondariesDisabled() const
{
	return m_secondaries_locked;
}

void ShipInitialStatusDialogModel::setTurretsDisabled(const int state)
{
	modify(m_turrets_locked, state);
}

int ShipInitialStatusDialogModel::getTurretsDisabled() const
{
	return m_turrets_locked;
}

void ShipInitialStatusDialogModel::setAfterburnerDisabled(const int state)
{
	modify(m_afterburner_locked, state);
}

int ShipInitialStatusDialogModel::getAfterburnerDisabled() const
{
	return m_afterburner_locked;
}

void ShipInitialStatusDialogModel::setDamage(const int value)
{
	modify(m_damage, value);
}

int ShipInitialStatusDialogModel::getDamage() const
{
	return m_damage;
}

SCP_string ShipInitialStatusDialogModel::getCargo() const
{
	return m_cargo_name;
}

void ShipInitialStatusDialogModel::setCargo(const SCP_string& text)
{
	modify(m_cargo_name, text);
}

SCP_string ShipInitialStatusDialogModel::getColour() const
{
	return m_team_color_setting;
}

void ShipInitialStatusDialogModel::setColour(const SCP_string& text)
{
	modify(m_team_color_setting, text);
}

void ShipInitialStatusDialogModel::change_subsys(const int new_subsys)
{
	int z, cargo_index;
	ship_subsys* ptr;
	// Goober5000
	ship_has_scannable_subsystems = Ship_info[Ships[m_ship].ship_info_index].is_huge_ship();
	if (Ships[m_ship].flags[Ship::Ship_Flags::Toggle_subsystem_scanning]) {
		ship_has_scannable_subsystems = ~ship_has_scannable_subsystems;
	}

	if (cur_subsys != -1) {
		ptr = GET_FIRST(&Ships[m_ship].subsys_list);
		while (cur_subsys--) {
			Assert(ptr != END_OF_LIST(&Ships[m_ship].subsys_list));
			ptr = GET_NEXT(ptr);
		}

		ptr->current_hits = 100.0f - (float)m_damage;

		// update cargo name
		if (!m_cargo_name.empty()) { //-V805
			lcl_fred_replace_stuff(m_cargo_name);
			cargo_index = string_lookup(m_cargo_name.c_str(), Cargo_names, Num_cargo);
			if (cargo_index == -1) {
				if (Num_cargo < MAX_CARGO) {
					cargo_index = Num_cargo++;
					strcpy(Cargo_names[cargo_index], m_cargo_name.c_str());
					ptr->subsys_cargo_name = cargo_index;
				} else {
					SCP_string str;
					sprintf(str, "Maximum number of cargo names %d reached.\nIgnoring new name.\n", MAX_CARGO);
					_viewport->dialogProvider->showButtonDialog(DialogType::Warning,
						"Cargo Error",
						str,
						{DialogButton::Ok});
					ptr->subsys_cargo_name = 0;
				}
			} else {
				ptr->subsys_cargo_name = cargo_index;
			}
		}
	}

	cur_subsys = z = new_subsys;
	if (z == -1) {
		m_damage = 100;

	} else {
		ptr = GET_FIRST(&Ships[m_ship].subsys_list);
		while (z--) {
			Assert(ptr != END_OF_LIST(&Ships[m_ship].subsys_list));
			ptr = GET_NEXT(ptr);
		}

		m_damage = 100 - static_cast<int>(ptr->current_hits);
		if (ship_has_scannable_subsystems) {
			if (ptr->subsys_cargo_name > 0) {
				m_cargo_name = Cargo_names[ptr->subsys_cargo_name];
			} else {
				m_cargo_name = "";
			}
		} else {
			m_cargo_name = "";
		}
	}
	set_modified();
	modelChanged();
}

int ShipInitialStatusDialogModel::getShip() const
{
	return m_ship;
}

int ShipInitialStatusDialogModel::getnum_dock_points() const
{
	return num_dock_points;
}

int ShipInitialStatusDialogModel::getShip_has_scannable_subsystems() const
{
	return ship_has_scannable_subsystems;
}

dockpoint_information* ShipInitialStatusDialogModel::getdockpoint_array() const
{
	return dockpoint_array;
}

void ShipInitialStatusDialogModel::setDockee(const int point, const int ship)
{
	modify(dockpoint_array[point].dockee_shipnum, ship);
	modify(dockpoint_array[point].dockee_point, -1);
}

void ShipInitialStatusDialogModel::setDockeePoint(const int dockPoint, const int dockeePoint)
{
	modify(dockpoint_array[dockPoint].dockee_point, dockeePoint);
}

bool ShipInitialStatusDialogModel::getUseTeamcolours() const
{
	return m_use_teams;
}

bool ShipInitialStatusDialogModel::getIfMultpleShips() const
{
	return m_multi_edit;
}

int ShipInitialStatusDialogModel::getGuardian() const
{
	return guardian_threshold;
}

void ShipInitialStatusDialogModel::setGuardian(int value)
{
	modify(guardian_threshold, value);
}

} // namespace fso::fred::dialogs