### ----------------------------------------------------
### -- XHTML::Writer
### -- Licenses: 
### -- Authors: Wenzel P. P. Peppmeyer
### -- File: bin/generate-function-definition.p6
### ----------------------------------------------------
use v6;
use XML;

sub MAIN($schema-file?) {

	my $doc = from-xml-file($schema-file // '3rd-party/xhtml1-strict.xsd');

	my %attr-group;

	multi sub walk(XML::Text, *%named){} # NOOP

	multi sub walk(XML::Element $_ where .name ~~ <xs:attributeGroup>){
		.nodes>>.&walk(group-name=>.attribs<name>);
	}

	multi sub walk(XML::Element $_ where .name ~~ <xs:attributeGroup>, :$group-name){
		my $ref = .attribs<ref> // Failure.new;
		%attr-group{$group-name}.push: |%attr-group{$ref};
		.nodes>>.&walk(group-name=>.attribs<name>);
	}

	multi sub walk(XML::Element $_ where .name ~~ <xs:attribute>, :$group-name!){
		my $name = .attribs<name> // .attribs<ref> // Failure.new;
		%attr-group.push($group-name=>$name);
		.nodes>>.&walk(:$group-name);
	}

	my %elements;
	put 'my $indent = 0;' ~ "\n";
	put 'constant NL = "\n";';
	put 'my Bool $shall-indent = False;';
	multi sub walk(XML::Element $_ where .name ~~ <xs:element> && (.attribs<name>:exists)) {
		my $name := .attribs<name> // Failure.new;
		%elements{$name} = Any;
		.nodes>>.&walk(element-name=>$name);		

		my Str $named-arguments = (':$' xx * Z~ %elements{$name}>>.subst(':', '-').list Z~ '?,' xx * ).Str;
		my Str $attributes-switch = %elements{$name}.list.map({
			"   (\${$_.subst(':', '-')} ?? ' $_' ~ '=' ~ \"\\\"\${$_.subst(':', '-')}\\\"\" !! Empty) ~\n" 	
		}).Str;

		# workaround for #127226
        constant $indent = '$indent';
		constant $indentor = '$indentor';
		constant $index = '$index';
		constant $shall-indent = '$shall-indent';
        put qq:to/EOH/;
        sub $name ( $named-arguments *\@c ) is export(:ALL :$name) \{
            (temp $indent)+=2;
			my $indentor;
			my method indent()\{ my $index = 0; $index += 2 while self.subst-eq('  ', $index); $indentor = '  ' x $index+2; \}
            '<$name' ~ 
         $attributes-switch 
            ( +\@c ?? ('>' ~ NL ~ ($shall-indent ?? \@c>>.Str>>.indent($indent).join(NL) !! \@c>>.Str.join(NL)) ~ (+\@c ?? NL !! "") ~ '</$name>') 
            !! '/>' ) 
        \}
        
        EOH
	}

	multi sub walk(XML::Element $_ where .name ~~ <xs:attribute>, :$element-name!) {
		my $name = .attribs<name> // .attribs<ref> // Failure.new;
		%elements{$element-name}.push: |$name;
	}

	multi sub walk(XML::Element $_ where .name ~~ <xs:attributeGroup>, :$element-name!) {
		%elements{$element-name}.push: |%attr-group{.attribs<ref>};
	}

	multi sub walk(XML::Element $_, *%named){
		.nodes>>.&walk(|%named);
	}

	multi sub walk(*@_, *%named) {
		.nodes>>.&walk(|%named);
	}

	$doc.root.nodes>>.&walk;
	put 'sub writer-shall-indent(Bool $shall-it) is export(:ALL :writer-shall-indent) { $shall-indent = $shall-it }';

}


