import os
import posixpath
import json
from panda3d.core import VirtualFileSystem

class PackageNotFound(FileNotFoundError):
	pass

class PackageMetaNotFound(FileNotFoundError):
	pass

class PackageInvalid(FileNotFoundError):
	pass

class PackageDuplicate(FileNotFoundError):
	pass

class Package:
	def __init__(self, name, vfs_dir):
		self.name = name
		self.vfs_dir = vfs_dir

class Filesystem:
	def __init__(self):
		self.package_list = []
		self.package_map = {}
		self.vfs = VirtualFileSystem.getGlobalPtr()
		self.include('assets/')
		self.mdl_missing = loader.loadModel('/main-assets/models/missing.glb')
		self.mdl_missing.setTexture(loader.loadTexture('/main-assets/textures/missing_mdl.png'))
		self.tex_missing = loader.loadTexture('/main-assets/textures/missing_tex.png')

	def include(self, path):
		if not os.path.exists(path):
			raise PackageNotFound(path)
		gamepkg_path = os.path.join(path, 'gamepackage.json')
		if not os.path.exists(gamepkg_path):
			raise PackageMetaNotFound(path)
		meta = json.load(open(gamepkg_path))
		if 'name' not in meta:
			raise PackageInvalid(path)
		if meta['name'] in self.package_map:
			raise PackageDuplicate(meta['name'])
		vfs_path = f'/{meta["name"]}'
		vfs.mount(path, f'/{meta["name"]}', 0)   
		new_package = Package(meta["name"], vfs_path)
		self.package_map[meta['name']] = new_package
		self.package_list.insert(0, new_package)

	def find_texture(self, tex_path):
		try:
			if tex_path[0:2] == '$/':
				for package in self.package_list:
					path = posixpath.join('/', package.name, 'textures', tex_path[2:])
					if self.vfs.exists(path):
						return loader.loadTexture(path)
				return self.tex_missing
			else:
				resource_path = model_path.split('/')
				path = posixpath.join('/', resource_path[0], 'textures', '/'.join(resource_path[1:]))
				return loader.loadTexture(path)
		except IOError:
			return self.tex_missing

	def find_model(self, model_path):
		try:
			if model_path[0:2] == '$/':
				for package in self.package_list:
					path = posixpath.join('/', package.name, 'models', model_path[2:])
					if self.vfs.exists(path):
						return loader.loadModel(path)
				return self.mdl_missing
			else:
				resource_path = model_path.split('/')
				path = posixpath.join('/', resource_path[0], 'models', '/'.join(resource_path[1:]))
				return loader.loadModel(path)
		except IOError:
			return self.mdl_missing