#**************************************************************
#  
#  Licensed to the Apache Software Foundation (ASF) under one
#  or more contributor license agreements.  See the NOTICE file
#  distributed with this work for additional information
#  regarding copyright ownership.  The ASF licenses this file
#  to you under the Apache License, Version 2.0 (the
#  "License"); you may not use this file except in compliance
#  with the License.  You may obtain a copy of the License at
#  
#    http://www.apache.org/licenses/LICENSE-2.0
#  
#  Unless required by applicable law or agreed to in writing,
#  software distributed under the License is distributed on an
#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
#  KIND, either express or implied.  See the License for the
#  specific language governing permissions and limitations
#  under the License.
#  
#**************************************************************



package par2script::module;

use par2script::converter;
use par2script::exiter;

###########################################
# Removing undefined gids 
# from modules
###########################################

sub remove_from_modules
{
	my ($gid, $item) = @_;

	my $counter = 0;

	if ( ! exists($par2script::globals::searchkeys{$item}) ) { par2script::exiter::exit_program("ERROR: Unknown type \"$item\" at modules.", "remove_from_modules"); }
	my $searchkey = $par2script::globals::searchkeys{$item};

	my $allmodules = $par2script::globals::definitions{'Module'};

	my $onemodule;
	foreach $onemodule (keys %{$allmodules})
	{
		if (( exists($allmodules->{$onemodule}->{$searchkey}) ) && ( $allmodules->{$onemodule}->{$searchkey} =~ /\b$gid\b/ ))
		{
			my $infoline = "WARNING: Removing $gid because of missing definition\n";
			# print $infoline;
			push(@par2script::globals::logfileinfo, $infoline);

			$allmodules->{$onemodule}->{$searchkey} =~ s/\b$gid\b//;
			$allmodules->{$onemodule}->{$searchkey} =~ s/\,\s*\,/\,/;
			$allmodules->{$onemodule}->{$searchkey} =~ s/\(\s*\,\s*/\(/;
			$allmodules->{$onemodule}->{$searchkey} =~ s/\s*\,\s*\)/\)/;
					
			if (( $allmodules->{$onemodule}->{$searchkey} =~ /\(\s*\,\s*\)/ ) || 
				( $allmodules->{$onemodule}->{$searchkey} =~ /\(\s*\)/ ))
			{
				delete($allmodules->{$onemodule}->{$searchkey});
			}
			
			$counter++;			
		}
	}
	
	return $counter;	
}

###########################################
# Removing undefined gids automatically
# from modules
###########################################

sub remove_undefined_gids_from_modules
{
	# If assigned gids for "File", "Directory" or "Unixlink" are not defined, 
	# they are automatically removed from the module

	foreach $item ( @par2script::globals::items_assigned_at_modules )
	{
		my $assignedgids = $par2script::globals::assignedgids{$item};
		my $definedgids = $par2script::globals::definitions{$item};

		my $gid;
		foreach $gid ( keys %{$assignedgids} )
		{
			if ( ! exists( $definedgids->{$gid} ))
			{
				# deleting entry in module definition
				my $number_of_removals = remove_from_modules($gid, $item);
				# decreasing counter in assignments
				if ( $assignedgids->{$gid} > $number_of_removals ) { $assignedgids->{$gid} = $assignedgids->{$gid} - $number_of_removals; }
				else { delete($assignedgids->{$gid}); }								
			}
		}
	}
}

############################################
# Getting the gid of the root module. The 
# root module has no ParentID or an empty
# ParentID.
############################################

sub get_rootmodule_gid
{
	my $rootgid = "";
	my $foundroot = 0;

	my $allmodules = $par2script::globals::definitions{'Module'};
	
	my $modulegid = "";
	foreach $modulegid (keys %{$allmodules} )
	{
		# print "Module $modulegid\n";
		# my $content = "";
		# foreach $content (sort keys %{$allmodules->{$modulegid}}) { print "\t$content = $allmodules->{$modulegid}->{$content};\n"; }
		# print "End\n";
		# print "\n";

		if (( ! exists($allmodules->{$modulegid}->{'ParentID'})) || ( $allmodules->{$modulegid}->{'ParentID'} eq "" ))
		{
			if ( $foundroot ) { par2script::exiter::exit_program("ERROR: More than one Root module. Only one module without ParentID or with empty ParentID allowed ($rootgid and $modulegid).", "get_rootmodule_gid"); }
			$rootgid = $modulegid;
			$foundroot = 1;
		}
	}
	
	if ( ! $foundroot ) { par2script::exiter::exit_program("ERROR: Could not find Root module. Did not find module without ParentID or with empty ParentID.", "get_rootmodule_gid"); }
	
	return $rootgid;	
}

####################################
# Adding defined items without 
# assignment to the root module.
####################################

sub add_to_root_module
{
	# If defined gids for "File", "Directory" or "Unixlink" are not assigned, 
	# they are automatically assigned to the root module
	
	my $rootmodulegid = get_rootmodule_gid();

	my $item;
	foreach $item ( @par2script::globals::items_assigned_at_modules )
	{
		my $assignedgids = $par2script::globals::assignedgids{$item};
		my $definedgids = $par2script::globals::definitions{$item};

		my $gidstring = "";
		
		# Perhaps there are already items assigned to the root
		if ( ! exists($par2script::globals::searchkeys{$item}) ) { par2script::exiter::exit_program("ERROR: Unknown type \"$item\" at modules.", "remove_from_modules"); }
		my $modulekey = $par2script::globals::searchkeys{$item};
		if ( exists($par2script::globals::definitions{'Module'}->{$rootmodulegid}->{$modulekey}) )
		{
			$gidstring = $par2script::globals::definitions{'Module'}->{$rootmodulegid}->{$modulekey};
			$gidstring =~ s/\(//;
			$gidstring =~ s/\)//;
		}

		my $gid;
		foreach $gid ( keys %{$definedgids} )
		{
			if ( ! exists( $assignedgids->{$gid} ))
			{
				if ( $gidstring eq "" )
				{
					$gidstring = $gid;
				}
				else
				{
					$gidstring = "$gidstring,$gid";
				}
				
				$assignedgids->{$gid} = 1;
			}
		}

		if ( $gidstring ne "" )
		{
			$gidstring = "\($gidstring\)";
			$par2script::globals::definitions{'Module'}->{$rootmodulegid}->{$modulekey} = $gidstring;
		}
	}	
}

###################################################
# Including \n in a very long string
###################################################

sub include_linebreaks
{
	my ($allgidstring) = @_;

	my $newline = "";
	my $newlength = 0;

	$allgidstring =~ s/\(//;
	$allgidstring =~ s/\)//;
	
	my $allgids = par2script::converter::convert_stringlist_into_array_2($allgidstring, ",");

	if ( $#{$allgids} > -1 )
	{
		my $onegid;
		foreach $onegid ( @{$allgids} )
		{
			$newline = "$newline$onegid,";
			$newlength = $newlength + length($onegid) + 1; # +1 for the comma

			if ( $newlength > 80 )
			{
				$newline = $newline . "\n\t\t\t\t";
				$newlength = 0;	
			}
		}
	}	

	$newline =~ s/,\s*$//;
	$newline = "($newline)";

	return $newline;
}

###################################################
# Shorten the lines that belong to modules, if
# the length of the line is greater 100
###################################################

sub shorten_lines_at_modules
{
	my $item;
	foreach $item ( @par2script::globals::items_assigned_at_modules )
	{
		if ( ! exists($par2script::globals::searchkeys{$item}) ) { par2script::exiter::exit_program("ERROR: Unknown type \"$item\" at modules.", "shorten_lines_at_modules"); }
		my $searchkey = $par2script::globals::searchkeys{$item};

		my $allmodules = $par2script::globals::definitions{'Module'};

		my $onemodule;
		foreach $onemodule (keys %{$allmodules})
		{
			if (( exists($allmodules->{$onemodule}->{$searchkey}) ) && 
				( length($allmodules->{$onemodule}->{$searchkey}) > 100 ))
			{
				# including "\n\t\t\t\t"
				my $newstring = include_linebreaks($allmodules->{$onemodule}->{$searchkey});
				$allmodules->{$onemodule}->{$searchkey} = $newstring;
			}
		}
	}
}

1;