use strict;
use UNIVERSAL;

#
#			Interface Definition Language (OMG IDL CORBA v3.0)
#

package indexVisitor;

sub new {
	my $proto = shift;
	my $class = ref($proto) || $proto;
	my $self = {};
	bless($self, $class);
	my($parser) = @_;
	$self->{symbtab} = $parser->YYData->{symbtab};
	my $filename = $parser->YYData->{srcname};
	$filename =~ s/^([^\/]+\/)+//;
	$filename =~ s/\.idl$//i;
	$self->{file_html} = '__' . $filename . '.html';
	$self->{done_hash} = {};
	$self->{save_module} = {};
	return $self;
}

sub _get_name {
	my $self = shift;
	my($node) = @_;
	my @list_name = split /::/, $node->{full};
	my @list_scope = split /::/, $self->{scope};
	shift @list_name;
	shift @list_scope;
	while (@list_scope) {
		last if ($list_scope[0] ne $list_name[0]);
		shift @list_name;
		shift @list_scope;
	}
	my $name = join '::', @list_name;
	return $name;
}

sub _get_defn {
	my $self = shift;
	my($defn) = @_;
	if (ref $defn) {
		return $defn;
	} else {
		return $self->{symbtab}->Lookup($defn);
	}
}

#
#	3.5		OMG IDL Specification
#

sub visitSpecification {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{scope} = '::';
	# init
	$self->{index_module} = {};
	$self->{index_interface} = {};
	$self->{index_operation} = {};
	$self->{index_attribute} = {};
	$self->{index_constant} = {};
	$self->{index_exception} = {};
	$self->{index_type} = {};
	$self->{index_value} = {};
	$self->{index_boxed_value} = {};
	$self->{index_state_member} = {};
	$self->{index_initializer} = {};
	$self->{index_event} = {};
	$self->{index_component} = {};
	$self->{index_provides} = {};
	$self->{index_uses} = {};
	$self->{index_publishes} = {};
	$self->{index_emits} = {};
	$self->{index_consumes} = {};
	$self->{index_home} = {};
	$self->{index_factory} = {};
	$self->{index_finder} = {};
	foreach (@{$node->{list_export}}) {
		$self->{symbtab}->Lookup($_)->visit($self);
	}
	# save
	$node->{index_module} = $self->{index_module};
	$node->{index_interface} = $self->{index_interface};
	$node->{index_operation} = $self->{index_operation};
	$node->{index_attribute} = $self->{index_attribute};
	$node->{index_constant} = $self->{index_constant};
	$node->{index_exception} = $self->{index_exception};
	$node->{index_type} = $self->{index_type};
	$node->{index_value} = $self->{index_value};
	$node->{index_boxed_value} = $self->{index_boxed_value};
	$node->{index_state_member} = $self->{index_state_member};
	$node->{index_initializer} = $self->{index_initializer};
	$node->{index_event} = $self->{index_event};
	$node->{index_component} = $self->{index_component};
	$node->{index_provides} = $self->{index_provides};
	$node->{index_uses} = $self->{index_uses};
	$node->{index_publishes} = $self->{index_publishes};
	$node->{index_emits} = $self->{index_emits};
	$node->{index_consumes} = $self->{index_consumes};
	$node->{index_home} = $self->{index_home};
	$node->{index_factory} = $self->{index_factory};
	$node->{index_finder} = $self->{index_finder};
}

#
#	3.7		Module Declaration
#

sub visitModules {
	my $self = shift;
	my($node) = @_;
	$self->{scope} = $node->{full};
	my $filename = $node->{full};
	$filename =~ s/::/_/g;
	$filename .= '.html';
	$self->{index_module}->{$node->{idf}} = $node;
	$self->{save_module}->{$node->{full}} = {}
			unless (exists $self->{save_module}->{$node->{full}});
	# local save
	my $file_html = $self->{file_html};
	my $module = $self->{index_module};
	my $interface = $self->{index_interface};
	my $operation = $self->{index_operation};
	my $attribute = $self->{index_attribute};
	my $constant = $self->{index_constant};
	my $exception = $self->{index_exception};
	my $type = $self->{index_type};
	my $value = $self->{index_value};
	my $boxed_value = $self->{index_boxed_value};
	my $state_member = $self->{index_state_member};
	my $initializer = $self->{index_initializer};
	my $event = $self->{index_event};
	my $component = $self->{index_component};
	my $provides = $self->{index_provides};
	my $uses = $self->{index_uses};
	my $publishes = $self->{index_publishes};
	my $emits = $self->{index_emits};
	my $consumes = $self->{index_consumes};
	my $home = $self->{index_home};
	my $factory = $self->{index_factory};
	my $finder = $self->{index_finder};
	# re init
	$self->{file_html} = $filename;
	$self->{index_module} = $self->{save_module}->{$node->{full}}->{index_module} || {};
	$self->{index_interface} = $self->{save_module}->{$node->{full}}->{index_interface} || {};
	$self->{index_operation} = $self->{save_module}->{$node->{full}}->{index_operation} || {};
	$self->{index_attribute} = $self->{save_module}->{$node->{full}}->{index_attribute} || {};
	$self->{index_constant} = $self->{save_module}->{$node->{full}}->{index_constant} || {};
	$self->{index_exception} = $self->{save_module}->{$node->{full}}->{index_exception} || {};
	$self->{index_type} = $self->{save_module}->{$node->{full}}->{index_type} || {};
	$self->{index_value} = $self->{save_module}->{$node->{full}}->{index_value} || {};
	$self->{index_boxed_value} = $self->{save_module}->{$node->{full}}->{index_boxed_value} || {};
	$self->{index_state_member} = $self->{save_module}->{$node->{full}}->{index_state_member} || {};
	$self->{index_initializer} = $self->{save_module}->{$node->{full}}->{index_initializer} || {};
	$self->{index_event} = $self->{save_module}->{$node->{full}}->{index_event} || {};
	$self->{index_component} = $self->{save_module}->{$node->{full}}->{index_component} || {};
	$self->{index_provides} = $self->{save_module}->{$node->{full}}->{index_provides} || {};
	$self->{index_uses} = $self->{save_module}->{$node->{full}}->{index_uses} || {};
	$self->{index_publishes} = $self->{save_module}->{$node->{full}}->{index_publishes} || {};
	$self->{index_emits} = $self->{save_module}->{$node->{full}}->{index_emits} || {};
	$self->{index_consumes} = $self->{save_module}->{$node->{full}}->{index_consumes} || {};
	$self->{index_home} = $self->{save_module}->{$node->{full}}->{index_home} || {};
	$self->{index_factory} = $self->{save_module}->{$node->{full}}->{index_factory} || {};
	$self->{index_finder} = $self->{save_module}->{$node->{full}}->{index_finder} || {};
	foreach (@{$node->{list_export}}) {
		$self->{symbtab}->Lookup($_)->visit($self);
	}
	$node->{file_html} = $self->{file_html};
	$node->{index_module} = $self->{index_module};
	$node->{index_interface} = $self->{index_interface};
	$node->{index_operation} = $self->{index_operation};
	$node->{index_attribute} = $self->{index_attribute};
	$node->{index_constant} = $self->{index_constant};
	$node->{index_exception} = $self->{index_exception};
	$node->{index_type} = $self->{index_type};
	$node->{index_value} = $self->{index_value};
	$node->{index_boxed_value} = $self->{index_boxed_value};
	$node->{index_state_member} = $self->{index_state_member};
	$node->{index_initializer} = $self->{index_initializer};
	$node->{index_event} = $self->{index_event};
	$node->{index_component} = $self->{index_component};
	$node->{index_provides} = $self->{index_provides};
	$node->{index_uses} = $self->{index_uses};
	$node->{index_publishes} = $self->{index_publishes};
	$node->{index_emits} = $self->{index_emits};
	$node->{index_consumes} = $self->{index_consumes};
	$node->{index_home} = $self->{index_home};
	$node->{index_factory} = $self->{index_factory};
	$node->{index_finder} = $self->{index_finder};
	#
	$self->{save_module}->{$node->{full}}->{file_html} = $self->{file_html};
	$self->{save_module}->{$node->{full}}->{index_module} = $self->{index_module};
	$self->{save_module}->{$node->{full}}->{index_interface} = $self->{index_interface};
	$self->{save_module}->{$node->{full}}->{index_operation} = $self->{index_operation};
	$self->{save_module}->{$node->{full}}->{index_attribute} = $self->{index_attribute};
	$self->{save_module}->{$node->{full}}->{index_constant} = $self->{index_constant};
	$self->{save_module}->{$node->{full}}->{index_exception} = $self->{index_exception};
	$self->{save_module}->{$node->{full}}->{index_type} = $self->{index_type};
	$self->{save_module}->{$node->{full}}->{index_value} = $self->{index_value};
	$self->{save_module}->{$node->{full}}->{index_boxed_value} = $self->{index_boxed_value};
	$self->{save_module}->{$node->{full}}->{index_state_member} = $self->{index_state_member};
	$self->{save_module}->{$node->{full}}->{index_initializer} = $self->{index_initializer};
	$self->{save_module}->{$node->{full}}->{index_event} = $self->{index_event};
	$self->{save_module}->{$node->{full}}->{index_component} = $self->{index_component};
	$self->{save_module}->{$node->{full}}->{index_provides} = $self->{index_provides};
	$self->{save_module}->{$node->{full}}->{index_uses} = $self->{index_uses};
	$self->{save_module}->{$node->{full}}->{index_publishes} = $self->{index_publishes};
	$self->{save_module}->{$node->{full}}->{index_emits} = $self->{index_emits};
	$self->{save_module}->{$node->{full}}->{index_consumes} = $self->{index_consumes};
	$self->{save_module}->{$node->{full}}->{index_home} = $self->{index_home};
	$self->{save_module}->{$node->{full}}->{index_factory} = $self->{index_factory};
	$self->{save_module}->{$node->{full}}->{index_finder} = $self->{index_finder};
	# restore
	$self->{file_html} = $file_html;
	$self->{index_module} = $module;
	$self->{index_interface} = $interface;
	$self->{index_operation} = $operation;
	$self->{index_attribute} = $attribute;
	$self->{index_constant} = $constant;
	$self->{index_exception} = $exception;
	$self->{index_type} = $type;
	$self->{index_value} = $value;
	$self->{index_boxed_value} = $boxed_value;
	$self->{index_state_member} = $state_member;
	$self->{index_initializer} = $initializer;
	$self->{index_event} = $event;
	$self->{index_component} = $component;
	$self->{index_provides} = $provides;
	$self->{index_uses} = $uses;
	$self->{index_publishes} = $publishes;
	$self->{index_emits} = $emits;
	$self->{index_consumes} = $consumes;
	$self->{index_home} = $home;
	$self->{index_factory} = $factory;
	$self->{index_finder} = $finder;
}

#
#	3.8		Interface Declaration
#

sub _visitBaseInterface {
	my $self = shift;
	my($node) = @_;
	$self->{scope} = $node->{full};
	my $filename = $node->{full};
	$filename =~ s/::/_/g;
	$filename .= '.html';
	$node->{file_html} = $filename;
	# local save
	my $file_html = $self->{file_html};
	my $module = $self->{index_module};
	my $interface = $self->{index_interface};
	my $operation = $self->{index_operation};
	my $attribute = $self->{index_attribute};
	my $constant = $self->{index_constant};
	my $exception = $self->{index_exception};
	my $type = $self->{index_type};
	my $value = $self->{index_value};
	my $boxed_value = $self->{index_boxed_value};
	my $state_member = $self->{index_state_member};
	my $initializer = $self->{index_initializer};
	my $event = $self->{index_event};
	my $component = $self->{index_component};
	my $provides = $self->{index_provides};
	my $uses = $self->{index_uses};
	my $publishes = $self->{index_publishes};
	my $emits = $self->{index_emits};
	my $consumes = $self->{index_consumes};
	my $home = $self->{index_home};
	my $factory = $self->{index_factory};
	my $finder = $self->{index_finder};
	# init
	$self->{file_html} = $filename;
	$self->{index_module} = {};
	$self->{index_interface} = {};
	$self->{index_operation} = {};
	$self->{index_attribute} = {};
	$self->{index_constant} = {};
	$self->{index_exception} = {};
	$self->{index_type} = {};
	$self->{index_value} = {};
	$self->{index_boxed_value} = {};
	$self->{index_state_member} = {};
	$self->{index_initializer} = {};
	$self->{index_event} = {};
	$self->{index_component} = {};
	$self->{index_provides} = {};
	$self->{index_uses} = {};
	$self->{index_publishes} = {};
	$self->{index_emits} = {};
	$self->{index_consumes} = {};
	$self->{index_home} = {};
	$self->{index_factory} = {};
	$self->{index_finder} = {};
	foreach (@{$node->{list_export}}) {
		$self->{symbtab}->Lookup($_)->visit($self);
	}
	$node->{file_html} = $self->{file_html};
	$node->{index_module} = $self->{index_module};
	$node->{index_interface} = $self->{index_interface};
	$node->{index_operation} = $self->{index_operation};
	$node->{index_attribute} = $self->{index_attribute};
	$node->{index_constant} = $self->{index_constant};
	$node->{index_exception} = $self->{index_exception};
	$node->{index_type} = $self->{index_type};
	$node->{index_value} = $self->{index_value};
	$node->{index_boxed_value} = $self->{index_boxed_value};
	$node->{index_state_member} = $self->{index_state_member};
	$node->{index_initializer} = $self->{index_initializer};
	$node->{index_event} = $self->{index_event};
	$node->{index_component} = $self->{index_component};
	$node->{index_provides} = $self->{index_provides};
	$node->{index_uses} = $self->{index_uses};
	$node->{index_publishes} = $self->{index_publishes};
	$node->{index_emits} = $self->{index_emits};
	$node->{index_consumes} = $self->{index_consumes};
	$node->{index_home} = $self->{index_home};
	$node->{index_factory} = $self->{index_factory};
	$node->{index_finder} = $self->{index_finder};
	# restore
	$self->{file_html} = $file_html;
	$self->{index_module} = $module;
	$self->{index_interface} = $interface;
	$self->{index_operation} = $operation;
	$self->{index_attribute} = $attribute;
	$self->{index_constant} = $constant;
	$self->{index_exception} = $exception;
	$self->{index_type} = $type;
	$self->{index_value} = $value;
	$self->{index_boxed_value} = $boxed_value;
	$self->{index_state_member} = $state_member;
	$self->{index_initializer} = $initializer;
	$self->{index_event} = $event;
	$self->{index_component} = $component;
	$self->{index_provides} = $provides;
	$self->{index_uses} = $uses;
	$self->{index_publishes} = $publishes;
	$self->{index_emits} = $emits;
	$self->{index_consumes} = $consumes;
	$self->{index_home} = $home;
	$self->{index_factory} = $factory;
	$self->{index_finder} = $finder;
}

sub visitRegularInterface {
	my $self = shift;
	my($node) = @_;
	$self->{index_interface}->{$node->{idf}} = $node;
	$self->_visitBaseInterface($node);
}

sub visitAbstractInterface {
	my $self = shift;
	my($node) = @_;
	$self->{index_interface}->{$node->{idf}} = $node;
	$self->_visitBaseInterface($node);
}

sub visitLocalInterface {
	my $self = shift;
	my($node) = @_;
	$self->{index_interface}->{$node->{idf}} = $node;
	$self->_visitBaseInterface($node);
}

#
#	3.9		Value Declaration
#

sub visitRegularValue {
	my $self = shift;
	my($node) = @_;
	$self->{index_value}->{$node->{idf}} = $node;
	$self->_visitBaseInterface($node);
}

sub visitStateMember {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{index_state_member}->{$node->{idf}} = $node;
}

sub visitInitializer {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{index_initializer}->{$node->{idf}} = $node;
}

sub visitBoxedValue {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{index_boxed_value}->{$node->{idf}} = $node;
}

sub visitAbstractValue {
	my $self = shift;
	my($node) = @_;
	$self->{index_value}->{$node->{idf}} = $node;
	$self->_visitBaseInterface($node);
}

#
#	3.10	Constant Declaration
#

sub visitConstant {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{index_constant}->{$node->{idf}} = $node;
}

#
#	3.11	Type Declaration
#

sub visitTypeDeclarator {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{index_type}->{$node->{idf}} = $node;
	return if (exists $node->{modifier});	# native
	my $type = $self->_get_defn($node->{type});
	if (	   $type->isa('StructType')
			or $type->isa('UnionType')
			or $type->isa('EnumType') ) {
		$type->visit($self);
	}
}

#	3.11.2	Constructed Types
#

sub visitStructType {
	my $self = shift;
	my($node) = @_;
	return if (exists $self->{done_hash}->{$node->{full}});
	$self->{done_hash}->{$node->{full}} = 1;
	my $name = $self->_get_name($node);
	$self->{index_type}->{$name} = $node;
	$node->{html_name} = $name;
	$node->{file_html} = $self->{file_html};
	foreach (@{$node->{list_expr}}) {
		my $type = $self->_get_defn($_->{type});
		if (	   $type->isa('StructType')
				or $type->isa('UnionType') ) {
			$type->visit($self);
		}
	}
	foreach (@{$node->{list_value}}) {
		$self->_get_defn($_)->visit($self);		# single or array
	}
}

sub visitArray {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$node->{html_name} = $self->_get_name($node);
}

sub visitSingle {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$node->{html_name} = $self->_get_name($node);
}

sub visitUnionType {
	my $self = shift;
	my($node) = @_;
	return if (exists $self->{done_hash}->{$node->{full}});
	$self->{done_hash}->{$node->{full}} = 1;
	my $name = $self->_get_name($node);
	$self->{index_type}->{$name} = $node;
	$node->{html_name} = $name;
	$node->{file_html} = $self->{file_html};
	my $type = $self->_get_defn($node->{type});
	if ($type->isa('EnumType')) {
		$type->visit($self);
	}
	foreach (@{$node->{list_expr}}) {	# case
		$type = $self->_get_defn($_->{element}->{type});
		if (	   $type->isa('StructType')
				or $type->isa('UnionType') ) {
			$type->visit($self);
		}
		$self->_get_defn($_->{element}->{value})->visit($self);		# single or array
	}
}

sub visitEnumType {
	my $self = shift;
	my($node) = @_;
	my $name = $self->_get_name($node);
	$self->{index_type}->{$name} = $node;
	$node->{html_name} = $name;
	$node->{file_html} = $self->{file_html};
	foreach (@{$node->{list_expr}}) {
		$_->visit($self);				# enum
	}
}

sub visitEnum {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$node->{html_name} = $self->_get_name($node);
}

#
#	3.12	Exception Declaration
#

sub visitException {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{index_exception}->{$node->{idf}} = $node;
	foreach (@{$node->{list_value}}) {
		$self->_get_defn($_)->visit($self);		# single or array
	}
}

#
#	3.13	Operation Declaration
#

sub visitOperation {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{index_operation}->{$node->{idf}} = $node;
}

#
#	3.14	Attribute Declaration
#

sub visitAttribute {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{index_attribute}->{$node->{idf}} = $node;
}

#
#	3.16	Event Declaration
#

sub visitRegularEvent {
	my $self = shift;
	my($node) = @_;
	$self->{index_event}->{$node->{idf}} = $node;
	$self->_visitBaseInterface($node);
}

sub visitAbstractEvent {
	my $self = shift;
	my($node) = @_;
	$self->{index_event}->{$node->{idf}} = $node;
	$self->_visitBaseInterface($node);
}

#
#	3.17	Component Declaration
#

sub visitComponent {
	my $self = shift;
	my($node) = @_;
	$self->{index_component}->{$node->{idf}} = $node;
	$self->_visitBaseInterface($node);
}

sub visitProvides {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{index_provides}->{$node->{idf}} = $node;
}

sub visitUses {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{index_uses}->{$node->{idf}} = $node;
}

sub visitPublishes {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{index_publishes}->{$node->{idf}} = $node;
}

sub visitEmits {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{index_emits}->{$node->{idf}} = $node;
}

sub visitConsumes {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{index_consumes}->{$node->{idf}} = $node;
}

#
#	3.18	Home Declaration
#

sub visitHome {
	my $self = shift;
	my($node) = @_;
	$self->{index_home}->{$node->{idf}} = $node;
	$self->_visitBaseInterface($node);
}

sub visitFactory {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{index_factory}->{$node->{idf}} = $node;
}

sub visitFinder {
	my $self = shift;
	my($node) = @_;
	$node->{file_html} = $self->{file_html};
	$self->{index_finder}->{$node->{idf}} = $node;
}

1;

