#!/usr/bin/perl
package RegExArgvParser;

use strict;
use warnings;
use Data::Dumper;
use File::Basename;

my $defined_param										=		{	"script-name"				=>	"Name of the script",
																	"script-created-by"			=>	"Script owner name",
																	"script-created-date"		=>	"Script creation date",
																	"script-version-no"			=>	"Version number of the script over SVN",
																	"script-tag-no"				=>	"Script release tag number associated with SVN",
																	"script-description"		=>	"Description about the script",
																	"script-license-agreement"	=>	"End user license agreement of the script",
																	"short-name"				=>	"Short name for input option argument",
																	"full-name"					=>	"Full name for input option argument",
																	"description"				=>	"Description about the input option argument",
																	"option"					=>	"Input option is optional or required to check",
																	"type"						=>	"Input argument is scalar or array type",
																	"regex-check"				=>	"User spcific regex for input validation",
																	"default"					=>	"Default value for user input",
																	"error-message"				=>	"User defined error message to display"				
																};

sub new() {
    my $class																					=		shift;+
    my $self																					=		{	"script-details"	=>	__check_supported_param( @_ )	};
    return bless $self, $class;
}


sub __check_supported_param() {
	my $param																					=		{ @_ };
	foreach ( keys %{ $param } ) {
		die ( "ArgumentParser - \($_\) is not supported input argument !" ) if( not defined $defined_param->{ $_ } );
		if(not $param->{'script-name'}) {
			$param->{ 'script-name' }															=		basename($0);
		}
	}
	return $param;
}


sub add_argument() {
	my $self                  																	=		shift;
	my $param																					=		{ @_ };
	
	die "ArgumentParser - User input argument option name are required !" if not $param->{ 'short-name' } and not $param->{ 'full-name' };
	die "ArgumentParser - Variable name for user input argument are required !" if not $param->{ 'variable-name' };
	
	$self->{ 'argument' }{ 'short-name' }{ $param->{ 'short-name' } }							=		$param->{ 'variable-name' } if( $param->{ 'short-name' } );
	$self->{ 'argument' }{ 'full-name' }{ $param->{ 'full-name' } }								=		$param->{ 'variable-name' } if( $param->{ 'full-name' } );
	$self->{ 'argument' }{ 'detail' }{ $param->{ 'variable-name' } }{ 'short-name' }			=		$param->{ 'short-name' } if( $param->{ 'short-name' } );
	$self->{ 'argument' }{ 'detail' }{ $param->{ 'variable-name' } }{ 'full-name' }				=		$param->{ 'full-name' } if( $param->{ 'full-name' } );
	$self->{ 'argument' }{ 'detail' }{ $param->{ 'variable-name' } }{ 'description' }			=		$param->{ 'description' } if( $param->{ 'description' } );
	$self->{ 'argument' }{ 'detail' }{ $param->{ 'variable-name' } }{ 'option' }				=		$param->{ 'option' } if( $param->{ 'option' } );
	$self->{ 'argument' }{ 'detail' }{ $param->{ 'variable-name' } }{ 'regex-check' }			=		$param->{ 'regex-check' } if( $param->{ 'regex-check' } );
	$self->{ 'argument' }{ 'detail' }{ $param->{ 'variable-name' } }{ 'error-message' }			=		$param->{ 'error-message' } if( $param->{ 'error-message' } );
	$self->{ 'argument' }{ 'detail' }{ $param->{ 'variable-name' } }{ 'type' }					=		$param->{ 'type' } if( $param->{ 'type' } );
	$self->{ 'argument' }{ 'detail' }{ $param->{ 'variable-name' } }{ 'default' }				=		$param->{ 'default' } if( $param->{ 'default' } );
	$self->{ 'argument' }{ 'detail' }{ $param->{ 'variable-name' } }{ 'value' }					=		undef;
}


sub parse_argument() {
	my $self															=		shift;
	
	if ( scalar( @ARGV ) == 0 ) {
		print "Insufficient input parameters\n";
		defined $self->{ 'script-details' }{ 'script-name' } ? print "For more information, please type :>$self->{ 'script-details' }{ 'script-name' } -h or --help\n" : print "For more information, please type :>script-name -h or --help\n";
		exit();
	}
	
	#
	# assign user input into defined argument
	#
	foreach ( my $input_index=0; $input_index <= $#ARGV; $input_index++ ) {
		$self->help() if ( ( $ARGV[0] eq '-h' ) or ( $ARGV[0] eq '--help') );
		
		last if( $input_index >= scalar(@ARGV) );
		
		my $first_option																		=		__get_defined_option_name_type($self, $ARGV[$input_index]);
		my $second_option																		=		__get_defined_option_name_type($self, $ARGV[$input_index + 1]);
		
		if( $first_option ) {
			my $option_variable_name															=		$self->{ 'argument' }{ $first_option }{ $ARGV[$input_index] };
			
			if ( $second_option ){
				if ($self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'default' }) {
					if( $self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'type' } eq 'array' ) {
						$self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'value' }	=		[ split (/,/, $self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'default' }) ];
					}
					else {
						$self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'value' }	=		$self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'default' }
					}
				}
				next;	
			}
			
			if( $self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'type' } eq 'array' ) {
				$self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'value' }			=		[ split (/,/, $ARGV[$input_index + 1]) ] if(defined $ARGV[$input_index + 1]);
				if( ( not defined $self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'value' } ) && ( $self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'default' }) ) {
					$self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'value' }		=		[ split (/,/, $self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'default' }) ];
				}
			}	
			else {
				$self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'value' }			=		$ARGV[$input_index + 1] if(defined $ARGV[$input_index + 1]);
				if( ( not defined $self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'value' } ) && ( $self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'default' }) ) {
					$self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'value' }		=		$self->{ 'argument' }{ 'detail' }{ $option_variable_name }{ 'default' };
				}
			}
		} 
		else {
			print "Invalid input parameters\n";
			defined $self->{ 'script-details' }{ 'script-name' } ? print "For more information, please type :>$self->{ 'script-details' }{ 'script-name' } -h or --help\n" : print "For more information, please type :>script-name -h or --help\n";
			exit();
		}
		
		$input_index++;
	}
	
	#
	# check arugment constraints
	#
	my $result																					=		{};
	foreach ( keys %{ $self->{ 'argument' }{ 'detail' } } ) {
		#
		#Check required || optional input
		#
		if( $self->{ 'argument' }{ 'detail' }{ $_ }{ 'option' } eq 'required' ) {
			if( not $self->{ 'argument' }{ 'detail' }{ $_ }{ 'value' } ) {
				if( not $self->{ 'argument' }{ 'detail' }{ $_ }{ 'error-message' } ) {
					print "Option (";
					print " ".$self->{ 'argument' }{ 'detail' }{ $_ }{ 'short-name' } if( $self->{ 'argument' }{ 'detail' }{ $_ }{ 'short-name' } );
					print " ".$self->{ 'argument' }{ 'detail' }{ $_ }{ 'full-name' } if( $self->{ 'argument' }{ 'detail' }{ $_ }{ 'full-name' } );
					print " ) value is required\n";
					defined $self->{ 'script-details' }{ 'script-name' } ? print "For more information, please type :>$self->{ 'script-details' }{ 'script-name' } -h or --help\n" : print "For more information, please type :>script-name -h or --help\n";
					exit();
				}
				else {
						print $self->{ 'script-details' }{ 'script-name' }."\n";
						print "Option (";
						print " ".$self->{ 'argument' }{ 'detail' }{ $_ }{ 'short-name' } if( $self->{ 'argument' }{ 'detail' }{ $_ }{ 'short-name' } );
						print " ".$self->{ 'argument' }{ 'detail' }{ $_ }{ 'full-name' } if( $self->{ 'argument' }{ 'detail' }{ $_ }{ 'full-name' } );
						print " ), ";
						print $self->{ 'argument' }{ 'detail' }{ $_ }{ 'error-message' }."\n";
						exit();
				}
			}
		}
		
		
				
		#
		#Check for regex
		#
		if( ( $self->{ 'argument' }{ 'detail' }{ $_ }{ 'regex-check' } ) && ($self->{ 'argument' }{ 'detail' }{ $_ }{ 'value' }) ) {
			my $found_regex_error																=		undef;
			if( $self->{ 'argument' }{ 'detail' }{ $_ }{ 'type' } eq 'array' ) {
				foreach my $input_value ( @{$self->{ 'argument' }{ 'detail' }{ $_ }{ 'value' }} ) {
					
					my $regex_result															=		eval {
																											if( $input_value =~ m/$self->{ 'argument' }{ 'detail' }{ $_ }{ 'regex-check' }/gsi ) {
																												$found_regex_error	=	undef;
																											}
																											else {
																												$found_regex_error	=	"FOUND";
																											}
																										};
					last if( $found_regex_error );
				}
			}
			else {
				my $regex_result															=		eval {
																											if( $self->{ 'argument' }{ 'detail' }{ $_ }{ 'value' } =~ m/$self->{ 'argument' }{ 'detail' }{ $_ }{ 'regex-check' }/gsi ) {
																												$found_regex_error	=	undef;
																											}
																											else {
																												$found_regex_error	=	"FOUND";
																											}
																										};
			}
			if( $found_regex_error ) {
				if( $self->{ 'argument' }{ 'detail' }{ $_ }{ 'error-message' } ) {
					print $self->{ 'script-details' }{ 'script-name' }."\n";
					print "Option (";
					print " ".$self->{ 'argument' }{ 'detail' }{ $_ }{ 'short-name' } if( $self->{ 'argument' }{ 'detail' }{ $_ }{ 'short-name' } );
					print " ".$self->{ 'argument' }{ 'detail' }{ $_ }{ 'full-name' } if( $self->{ 'argument' }{ 'detail' }{ $_ }{ 'full-name' } );
					print " ), ";
					print $self->{ 'argument' }{ 'detail' }{ $_ }{ 'error-message' }."\n";
					exit();
				}
				else {
					print $self->{ 'script-details' }{ 'script-name' }."\n";
					print "Option (";
					print " ".$self->{ 'argument' }{ 'detail' }{ $_ }{ 'short-name' } if( $self->{ 'argument' }{ 'detail' }{ $_ }{ 'short-name' } );
					print " ".$self->{ 'argument' }{ 'detail' }{ $_ }{ 'full-name' } if( $self->{ 'argument' }{ 'detail' }{ $_ }{ 'full-name' } );
					print " ) - value is required\n";
					print $@;
					exit();
				}
			}
		}
		
		$result->{ $_ }																			=		$self->{ 'argument' }{ 'detail' }{ $_ }{ 'value' };
	}
	
	#print Dumper $result;
	print Dumper $result;
	return $result;
}


sub __get_defined_option_name_type() {
	my $self																					=		shift;
	my $option																					=		shift;
	
	if( defined $option ) {
		return "short-name" if( $self->{ 'argument' }{ 'short-name' }{ $option } );
		return  "full-name" if( $self->{ 'argument' }{ 'full-name' }{ $option } );
	}
	
	return undef;
}


sub help(){
	my ($self)																					=		@_;
	
	print "Script Name        : $self->{'script-name'}\n" if defined $self->{'script-name'};
	print "Version No.        : $self->{'script-version-no'}\n" if defined $self->{'script-version-no'};
	print "Tag No.            : $self->{'script-tag-no'}\n" if defined $self->{'script-tag-no'};
	print "Created by         : $self->{'script-created-by'}\n" if defined $self->{'script-created-by'};
	print "Created date       : $self->{'script-created-date'}\n" if defined $self->{'script-created-date'};
	print "Description        : $self->{'script-description'}\n" if defined $self->{'script-description'};
	
	if ( keys %{$self->{ 'argument' }} ) {
		print "Options:\n";
		foreach ( keys %{$self->{ 'argument' }} ) {
			print $self->{ 'argument' }{ $_ }{ 'short-name' }.' | '.$self->{ 'argument' }{ $_ }{ 'full-name' };
			print " " x ( 30 - ( length($self->{ 'argument' }{ $_ }{ 'short-name' }) + length($self->{ 'argument' }{ $_ }{ 'full-name' }) ) );
			print $self->{ 'argument' }{ $_ }{ 'description' }."\n";
		}
	}
	
	print "License agreement  : $self->{'script-license-agreement'}\n" if defined $self->{'script-license-agreement'};
}


1;