 bw = require '.'
 
 publicTypes = require path.resolve process.argv[2]
+namespace = process.argv[3]
 allTypes = {}
 
 decls =
 	forward: []
 	other: []
+	adapters: []
 
 newName = (nameHint) ->
 	name = nameHint

	delete @inStack
	deps

bw.Enum::declaration = -> """
	enum class #{@name} : uint8_t { #{@members.join ', '} };
	namespace bw { template<> constexpr int EnumCount<#{@name}> = #{@members.length}; }
	"""

bw.Struct::declaration = ->
	members = @members.map ([name, type]) -> "#{type.name} #{name};"
	memberNames = @members.map ([name]) -> name
	"""
	struct #{@name} {
		#{members.join '\n\t'}
		auto operator~() const { return std::forward_as_tuple(#{memberNames.join ', '}); }
		auto operator~() { return std::forward_as_tuple(#{memberNames.join ', '}); }
	};
	"""

for name, type of publicTypes
	allTypes[type.name = name] = type

for name, type of publicTypes
	register type, name

for name, type of allTypes
	declare type

decls.structs = for name, type of allTypes when type instanceof bw.Struct
	"struct #{name};"

decls.forward = decls.forward.filter (x) -> x
decls.other = decls.other.filter (x) -> x

process.stdout.write """
	#pragma once
	#include <binarywheel.hpp>

	#{decls.forward.join '\n\n'}

	#{decls.structs.join '\n'}

	#{decls.other.join '\n\n'}

	"""

		name = "#{nameHint}#{i += 1}"
	name

register = (type, hint, pub = false) ->
	name = type.typename? hint
	if not type.name?
		allTypes[type.name = name] = type
	type.pub or= pub
	type.name

declare = (type) -> if not type.declared and type.pub
	type.declared = true
	if deps = type.dependencies?()
		for n, t of deps
			declare t
	decl = type.declaration?() ? (type.spec and type.name != type.spec and "using #{type.name} = #{type.spec}" or "")
	decls[if not deps then 'forward' else 'other'].push decl
	if adapt = type.adapter?()
		decls.adapters.push adapt

capitalizeFirstLetter = (s) -> s[0].toUpperCase() + s.substring 1

