abstract type 特殊结构 end
mutable struct 文件
	par::Union{特殊结构,Nothing}
	name::String
	content::String
end
mutable struct 目录<:特殊结构
	par::Union{目录,Nothing}
	name::String
	files::Dict{String,文件}
	dirs::Dict{String,目录}
end
目录(par::Union{目录,Nothing},name::String)=目录(par,name,Dict{String,文件}(),Dict{String,目录}())
mutable struct 文件系统
	root::目录
	current::目录
end
function 文件系统()
	rt=目录(nothing,"")
	cu=rt
	return 文件系统(rt,cu)
end

function getpath(dir::目录;full::Bool=false,relative::目录=dir)
	if full
		s=dir.name
		if dir.par===nothing
			return "/"
		end
		t=dir
		while true
			t=t.par
			if t.par===nothing
				return "/$s"
			end
			s="$(t.name)/$s"
		end
	else
		s=dir.name
		t=dir
		while true
			t=t.par
			if t===nothing
				return "/$s"
			elseif t==relative
				return s
			end
			s="$(t.name)/$s"
		end
	end
end
function getdir(dir::目录,path::Vector{T}) where T<:AbstractString
	res=dir
	for i in path
		if i==".."
			if res!==nothing
				res=res.par
			end
		elseif i!="."
			if haskey(res.dirs,i)
				res=@inbounds res.dirs[i]
			else
				throw("未在$(getpath(res))找到下一级目录")
			end
		end
	end
	return res
end
function getdir(fs::文件系统,path::AbstractString)
	v=splitpath(path)
	if isempty(v) throw("路径不能为空") end
	d=fs.current
	if v[1]=="/"
		d=fs.root
		popfirst!(v)
	end
	return getdir(d,v)
end
function getpardir(fs::文件系统,path::AbstractString)::Pair
	v=splitpath(path)
	if isempty(v)
		throw("路径不能为空")
	end
	d=fs.current
	if v[1]=="/"
		d=fs.root
		popfirst!(v)
		if isempty(v)
			throw("路径不能为空")
		end
	end
	last=pop!(v)
	return Pair(getdir(d,v),last)
end
function getfile(fs::文件系统,path::AbstractString)
	v=splitpath(path)
	if isempty(v)
		throw("路径不能为空")
	end
	fname=pop!(v)
	d=fs.current
	if v[1]=="/"
		d=fs.root
		popfirst!(v)
	end
	dir=getdir(d,v)
	if haskey(dir.files,fname)
		return @inbounds dir.files[fname]
	else
		throw("未找到该文件")
	end
end

_pwd(fs::文件系统)=getpath(fs.current;full=true)
function _ls(fs::文件系统,target::目录=fs.current)
	for i in target.dirs
		println(i.first,"/")
	end
	for i in target.files
		println(i.first)
	end
end
function _cd(fs::文件系统,path::AbstractString)
	fs.current=getdir(fs,path)
end
function _mkdir(fs::文件系统,path::AbstractString;force::Bool=false)
	pair=getpardir(fs,path)
	dir=pair.first
	name=pair.second
	if force
		dir.dirs[name]=目录(dir,name)
		return
	end
	if haskey(dir.dirs,name)
		throw("同名目录已存在")
	elseif haskey(dir.files,name)
		throw("同名文件已存在")
	else
		dir.dirs[name]=目录(dir,name)
	end
end
function _rmdir(fs::文件系统,path::AbstractString)
	pair=getpardir(fs,path)
	dir=pair.first
	name=pair.second
	q=fs.current
	while q!==nothing
		if q==dir
			throw("删除的目录不能包含当前目录")
		end
		q=q.par
	end
	delete!(dir.dirs,name)
end
function _rm(fs::文件系统,path::AbstractString)
	(dir,name)=getpardir(fs,path)
	if haskey(dir.dirs,name)
		delete!(dir.dirs,name)
	elseif haskey(dir.files,name)
		delete!(dir.files,name)
	else
		throw("未找到该资源")
	end
end
function _cp(fs::文件系统,from::AbstractString,to::AbstractString;force::Bool=false)
	(dir,name)=getpardir(fs,from)
	if haskey(dir.dirs,name)
		dirto=getdir(fs,to)
		ori=@inbounds(dir.dirs[name])
		if !force
			haskey(dirto.dirs,name) ? throw("同名目录已存在") :
			haskey(dirto.files,name) ? throw("同名文件已存在") : nothing
		end
		dirto.dirs[name]=目录(dirto,name,deepcopy(ori.files),deepcopy(ori.dirs))
	elseif haskey(dir.files,name)
		dirto=getdir(fs,to)
		content=@inbounds(dir.files[name].content)
		if !force
			haskey(dirto.dirs,name) ? throw("同名目录已存在") :
			haskey(dirto.files,name) ? throw("同名文件已存在") : nothing
		end
		dirto.files[name]=文件(dirto,deepcopy(name),deepcopy(content))
	else
		throw("未找到该资源")
	end
end
function _mv(fs::文件系统,from::AbstractString,to::AbstractString;force::Bool=false)
	(dir,name)=getpardir(fs,from)
	if haskey(dir.dirs,name)
		dirto=getdir(fs,to)
		ori=@inbounds(dir.dirs[name])
		if !force
			haskey(dirto.dirs,name) ? throw("同名目录已存在") :
			haskey(dirto.files,name) ? throw("同名文件已存在") : nothing
		end
		dirto.dirs[name]=目录(dirto,name,ori.files,ori.dirs)
		delete!(dir.dirs,name)
	elseif haskey(dir.files,name)
		dirto=getdir(fs,to)
		content=@inbounds(dir.files[name].content)
		if !force
			haskey(dirto.dirs,name) ? throw("同名目录已存在") :
			haskey(dirto.files,name) ? throw("同名文件已存在") : nothing
		end
		dirto.files[name]=文件(dirto,name,content)
		delete!(dir.files,name)
	else
		throw("未找到该资源")
	end
end
const simdata=Dict{String,Tuple{UnitRange,UInt8,Symbol}}(
	# "sim"=>(1:1,0x7,"")
	"pwd" => (0:0,0x5,:pwd),
	"chdir" => (0:0,0x2,:pwd),
	"ls" => (0:1,0x1,:ls),
	"dir" => (0:1,0x2,:ls),
	"readdir" => (0:1,0x4,:ls),
	"cd" => (1:1,0x7,:cd),
	"mkdir" => (1:1,0x7,:mkdir),
	"md" => (1:1,0x2,:mkdir),
	"rmdir" => (1:1,0x3,:rmdir),
	"rm" => (1:1,0x5,:rm),
	"del" => (1:1,0x2,:rm),
	"cp" => (2:2,0x5,:cp),
	"copy" => (2:2,0x2,:cp),
	"mv" => (2:2,0x7,:mv),
)
function init()
	fs=文件系统()
	_mkdir(fs,"home")
	_cd(fs,"home")
	fs.current.files["hello.txt"]=文件(fs.current,"hello.txt","你好")
	sim=0x0
	while true
		print("vfs> ")
		s=readline()
		try
			v=split(s)
			if isempty(v)
				continue
			end
			com=""
			if v[1]=="sim"
				sim=v[2]=="unix" ? 0x0 :
					v[2]=="windows" ? 0x1 :
					v[2]=="julia" ? 0x2 :
					printstyled("不支持的模拟对象";color=:light_yellow)
				println()
				continue
			elseif v[1]=="quit"
				return
			else
				name=String(v[1])
				if !haskey(simdata,name)
					throw("不支持的命令")
				end
				data=@inbounds simdata[name]
				vl=length(v)-1
				if !in(vl,data[1])
					throw("错误的参数个数")
				end
				if data[2]>>sim&0x1 != 0x1
					throw("该环境不支持该命令")
				end
				com=data[3]
			end
			com==:pwd ? println(_pwd(fs)) :
			com==:ls ? _ls(fs,vl==1 ? getdir(fs,v[2]) : fs.current) :
			com==:cd ? _cd(fs,v[2]) :
			com==:mkdir ? _mkdir(fs,v[2]) :
			com==:rmdir ? _rmdir(fs,v[2]) :
			com==:rm ? _rm(fs,v[2]) :
			com==:cp ? _cp(fs,v[2],v[3]) :
			com==:mv ? _mv(fs,v[2],v[3]) :
			throw("程序出错")
		catch er
			if isa(er,String)
				printstyled(er;color=:light_red)
				println()
			else
				throw(er)
			end
		end
		println()
	end
end
println("当前只支持命令格式,不支持额外参数\n使用\"sim 目标\"切换模拟环境")