 		name = "#{nameHint}#{i += 1}"
 	name
 
-register = (type, hint) ->
+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
+declare = (type) -> if not type.declared and type.pub
 	type.declared = true
 	if deps = type.dependencies?()
 		for n, t of deps
 			declare t
-	noDeps = type instanceof bw.Enum or type instanceof bw.Scaled
-	decl = type.declaration?() ? (type.spec and type.name != type.spec and "using #{type.name} = #{type.spec};" or "")
-	decls[if noDeps then 'forward' else 'other'].push decl
+	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
 

bw = require '.'

publicTypes = require path.resolve process.argv[2]
allTypes = {}

decls =
	forward: []
	other: []

newName = (nameHint) ->
	name = nameHint

	delete @inStack
	deps

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

cppValue = (value) ->
	if value instanceof Array
		"{ #{value.map((v) -> cppValue v).join ', '} }"
	else if value instanceof String
		'"' + value + '"'
	else
		value

valueAssignment = (value) ->
	if value?
		" = #{cppValue value}"
	else
		""

bw.Struct::declaration = (ident = '') ->
	members = @members.map ([name, type, value]) ->
		"#{if type.pub or not type.declaration? then type.name else type.declaration ident + '\t'} #{name}#{valueAssignment value};"
	params = @members.map ([name]) -> name
	"""
	struct#{if @pub then ' ' + @name else ''}
	#{ident}{
	#{ident}	#{members.join '\n\t' + ident}
	#{ident}	auto operator~() const { return std::forward_as_tuple(#{params.join ', '}); }
	#{ident}	auto operator~() { return std::forward_as_tuple(#{params.join ', '}); }
	#{ident}}
	"""

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

for name, type of publicTypes
	register type, name, true

for name, type of allTypes
	declare type

for name, type of allTypes when type.pub and type instanceof bw.Struct
	decls.forward.push "struct #{name}"

for t in ['forward', 'other']
	decls[t] = decls[t].filter (x) -> x

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

	#{if namespace then 'namespace ' + namespace + '\n{' else ''}
	#{decls.forward.join ';\n'};

	#{decls.other.join ';\n\n'};
	#{if namespace then '}' else ''}

	namespace bw
	{
	#{decls.adapters.join '\n'}
	}

	"""
