#!/usr/bin/perl

use strict;
use warnings;
use Getopt::Long;

Getopt::Long::Configure ("bundling", "gnu_compat");

my $version = 0.1;
my %options = map {$_, 0} qw(upper lower num special alpha alphanum all stdin version help); 

GetOptions (	"upper|u" => \$options{'upper'}, 
		"lower|l" => \$options{'lower'}, 
		"num|n" => \$options{'num'}, 
		"special|s" => \$options{'special'}, 
		"alpha" => \$options{'alpha'}, 
		"alphanum" => \$options{'alphanum'}, 
		"all" => \$options{'all'}, 
		"stdin" => \$options{'stdin'},
		"help|h" => \$options{'help'}, 
		"version|v" => \$options{'version'}, 
	 );

if ($options{'help'} == 1){
	print	"perlpwd - Generates a random password from a given set of characters\n" .
		"using perl's rand() function\n" . 
		"\nUsage:" . 
		"\tperlpwd [options...] [passwordlength]\n" . 
		"If no passwordlength is given, the defaultlength (12 characters) will be used\n\n" . 
		"Options:\n" .
		"  -u, --upper\t\tUse upper case letters\n" . 
		"  -l, --lower\t\tUse lower case letters\n" . 
		"  -n, --num\t\tUse all digits\n" .
		"  -s, --special\t\tUse special characters\n" . 
		"      --alpha\t\tUse upper and lower case characters\n" .
		"      --alphanum\tUse all letters and digits\n" . 
		"      --all\t\tUse all characters (default)\n" .
		"      --stdin\t\tRead characters from STDIN\n" .
		"  -h, --help\t\tPrint this help and exit\n" . 
		"  -v, --version\t\tDisplay the program version and exit\n" ; 
		exit 0;
	}

if ($options{'version'}) {
	print "perlpwd  - version $version\nAuthor: Haui, contact haui45\@web.de\n";
	exit 0;
}

########## define the character arrays ###########
my @upper = qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z);
my @lower = qw(a b c d e f g h i j k l m n o p q r s t u v w x y z);
my @num = qw(0 1 2 3 4 5 6 7 8 9 );
no warnings;
my @special = qw( . : ; - _ # ' + * ~ ^ ° ! " § $ % & /  = ? \ } ] [ { , ( ) < > | );
use warnings;
my @characters;
#################################################


#**evaluate the commandline options****
if ($options{'alphanum'}){
	$options{'num'} = 1;
	$options{'upper'} = 1;
	$options{'lower'} = 1;
}

if ($options{'alpha'}){
	$options{'upper'} = 1;
	$options{'lower'} = 1;
}

if ($options{'all'}){
	$options{'num'} = 1;
	$options{'upper'} = 1;
	$options{'lower'} = 1;
	$options{'special'} = 1;
}

if ($options{'num'}){
	@characters = (@characters, @num);
}
if ($options{'lower'}){
	@characters = (@characters, @lower);
}

if ($options{'upper'}){
	@characters = (@characters, @upper);
}
if ($options{'special'}){
	@characters = (@characters, @special);
}
if ($options{'stdin'}){
	my $input="";
	while(my $line = <STDIN>){
		chomp $line;
		$input .= $line;
	}
	chomp $input;
	undef @characters;
	@characters = split //, $input;
	
	#delete duplicate entries
	my %hash = map{$_, 1} @characters;
	undef @characters;
	@characters = keys %hash;
	#end
}

# use all characters if nothing else is defined
unless (@characters){
	@characters = (@num, @special, @lower, @upper);
}

#******************************************

my $tmprand = int(rand(75)) + 25;

#randomize the array 
for (my $i = 0; $i <= $tmprand; $i++){
	@characters = sort{int(rand(2))}(@characters);
}


my $password = "";
my $passwordlength = 12;
if ($ARGV[0]){
	$passwordlength = int($ARGV[0]);
}

#generate the password
for (my $i=0; $i<$passwordlength; $i++){
	$password .= $characters[int(rand($#characters + 1))];
}

print "$password\n";
