/***********************************************************************************
 * Copyright (c) 2024 /// Project SWG /// www.projectswg.com                       *
 *                                                                                 *
 * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on          *
 * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
 * Our goal is to create an emulator which will provide a server for players to    *
 * continue playing a game similar to the one they used to play. We are basing     *
 * it on the final publish of the game prior to end-game events.                   *
 *                                                                                 *
 * This file is part of Holocore.                                                  *
 *                                                                                 *
 * --------------------------------------------------------------------------------*
 *                                                                                 *
 * Holocore is free software: you can redistribute it and/or modify                *
 * it under the terms of the GNU Affero General Public License as                  *
 * published by the Free Software Foundation, either version 3 of the              *
 * License, or (at your option) any later version.                                 *
 *                                                                                 *
 * Holocore is distributed in the hope that it will be useful,                     *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of                  *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                   *
 * GNU Affero General Public License for more details.                             *
 *                                                                                 *
 * You should have received a copy of the GNU Affero General Public License        *
 * along with Holocore.  If not, see <http://www.gnu.org/licenses/>.               *
 ***********************************************************************************/
package com.projectswg.holocore.resources.support.data.server_info.loader.npc

import com.projectswg.common.data.location.Terrain
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet
import com.projectswg.holocore.resources.support.data.server_info.loader.*
import com.projectswg.holocore.resources.support.npc.spawn.SpawnInfo
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureDifficulty
import com.projectswg.holocore.resources.support.objects.swg.custom.AIBehavior
import me.joshlarson.jlcommon.log.Log
import java.io.File
import java.io.IOException
import java.util.*
import java.util.stream.Collectors
import kotlin.collections.ArrayList

class NpcStaticSpawnLoader : DataLoader() {
	private val _spawns: MutableList<StaticSpawnInfo> = ArrayList()
	val spawns: List<StaticSpawnInfo>
		get() = Collections.unmodifiableList(_spawns)

	@Throws(IOException::class)
	override fun load() {
		SdbLoader.load(File("serverdata/spawn/static.msdb")).use { set ->
			_spawns.addAll(set.parallelStream { StaticSpawnInfo(it) }.collect(Collectors.toList()))
		}
	}

	enum class SpawnerFlag {
		AGGRESSIVE,
		ATTACKABLE,
		INVULNERABLE,
		QUEST
	}

	class StaticSpawnInfo(set: SdbResultSet) : SpawnInfo {
		override val id: String = set.getText("spawn_id")
		override val terrain = Terrain.valueOf(set.getText("terrain"))
		override val x = set.getReal("x")
		override val y = set.getReal("y")
		override val z = set.getReal("z")
		override val heading = set.getInt("heading").toInt()
		override val cellId = set.getInt("cell_id").toInt()
		override var spawnerFlag: SpawnerFlag = SpawnerFlag.INVULNERABLE
		override var difficulty: CreatureDifficulty = CreatureDifficulty.NORMAL
		override val minLevel: Int
		override val maxLevel: Int
		override val spawnerType = set.getText("spawner_type").intern()
		override val npcId = set.getText("npc_id").intern()
		override val buildingId: String
		override val mood: String
		override val behavior: AIBehavior
		override val patrolId: String
		override val patrolFormation: PatrolFormation
		override val loiterRadius: Int
		override val minSpawnTime: Int
		override val maxSpawnTime: Int
		override val amount: Int
		override val conversationId: String
		override val equipmentId: Long?

		init {
			run {
				var flag: SpawnerFlag
				try {
					flag = SpawnerFlag.valueOf(set.getText("attackable"))
				} catch (e: IllegalArgumentException) {
					Log.w("Unknown attackable flag for spawn_id '%s': '%s'", id, set.getText("attackable"))
					flag = SpawnerFlag.INVULNERABLE
				}
				this.spawnerFlag = flag
			}
			this.minLevel = set.getInt("min_cl").toInt()
			this.maxLevel = set.getInt("max_cl").toInt()
			this.buildingId = set.getText("building_id").intern()
			this.mood = parseMood(set.getText("mood")).intern()
			this.behavior = AIBehavior.valueOf(set.getText("behaviour"))
			this.patrolId = set.getText("patrol_id")
			this.patrolFormation = parsePatrolFormation(set.getText("patrol_formation"))
			this.loiterRadius = set.getInt("loiter_radius").toInt()
			val spawnTime = set.getInt("respawn").toInt()
			this.minSpawnTime = (spawnTime * 0.9).toInt()
			this.maxSpawnTime = (spawnTime * 1.1).toInt()
			this.amount = set.getInt("amount").toInt()

			when (set.getText("difficulty")) {
				"N"  -> this.difficulty = CreatureDifficulty.NORMAL
				"E"  -> this.difficulty = CreatureDifficulty.ELITE
				"B"  -> this.difficulty = CreatureDifficulty.BOSS
				else -> {
					Log.w("Unknown difficulty: %s", set.getText("difficulty"))
					this.difficulty = CreatureDifficulty.NORMAL
				}
			}
			this.conversationId = set.getText("conversation_id")
			this.equipmentId = parseEquipmentId(set)
		}

		companion object {
			private fun parseEquipmentId(set: SdbResultSet): Long? {
				val equipmentIdText = set.getText("equipment_id")

				if (equipmentIdText.isBlank()) {
					return null
				}

				return equipmentIdText.toLong()
			}

			private fun parsePatrolFormation(str: String): PatrolFormation {
				return when (str.uppercase()) {
					"COLUMN" -> PatrolFormation.COLUMN
					"WEDGE"  -> PatrolFormation.WEDGE
					"LINE"   -> PatrolFormation.LINE
					"BOX"    -> PatrolFormation.BOX
					""       -> PatrolFormation.NONE
					else     -> PatrolFormation.NONE
				}
			}

			private fun parseMood(mood: String): String {
				return if (mood == "idle") "neutral" else mood
			}
		}
	}

	enum class PatrolFormation {
		NONE,
		COLUMN,
		WEDGE,
		LINE,
		BOX
	}
}
