#!/usr/bin/perl 

#########################################
##### Author:		Sebastian Enger / B.Sc
##### CopyRight:	Sebastian Enger / B.Sc
##### LastModified	7.01.2007
##### Function:		Dublicated Content Filter für Google
##### Todo:			
########################################

# todo:
# statische synonym textdatei nehmen und diese dann abarbeiten, wenn kein treffer gefunden wurde dann benutze das langsame my $result	= Lingua::DE::Wortschatz::use_service('T', $_);
# StringManipulation ist mir noch zu krass, der text wird extrem unleserlich bis jetzt noch
###	amazon content grabbing + adding

# string::approx benutzen 
# TheCerial: my $ApproxMatchingQuantifier   = "40%";
# TheCerial: $matched						= amatch($FileName, $ApproxMatchingQuantifier, $TemporarySearchQuery);

# my $sentences			= get_sentences($text);				# returns an array ref
# my $FullContentArray	= &Main( $sentences	);
# $WordCount			= $#FullContent;

# synonyme in format bringen
# synonyme vergleichen mit textdate und zu modifizierendem text
# wenn syn. nicht in text datei vorhanden dann benutze webservice
# ergebnisse vom webservice dann auch in unsere syn. datei hinzufügen


# perl -MCPAN -e 'install "Text::German"'
# perl -MCPAN -e 'install "Text::English"'
# perl -MCPAN -e 'install "Lingua::EN:Inflect"'
# perl -MCPAN -e 'install "Lingua::DE::Wortschatz"'
# perl -MCPAN -e 'install "Lingua::DE::Num2Word"'
# perl -MCPAN -e 'install "Lingua::DE::ASCII"'
# perl -MCPAN -e 'install "Lingua::DE::Sentence"'
# perl -MCPAN -e 'install "Lingua::DE::TypoGenerator"'
# perl -MCPAN -e 'install "String::Approx"'
# perl -MCPAN -e 'install "Text::Levenshtein"'


# reniceing to 20 !
system("renice 20 $$");
system("clear");

use strict;
# use Text::German;
# use Text::English;
# use Lingua::DE::ASCII;
use Lingua::EN::Inflect;
use Lingua::DE::Sentence;
use Lingua::DE::Num2Word;
use Lingua::DE::Wortschatz;	# 
# use String::Approx 'amatch';		# amatch
# use Lingua::DE::TypoGenerator;		# generate typing errors from given keyword

# use Data::Dumper;
# use Text::Levenshtein qw(fastdistance);

# random initilisation
srand();


# variables
my $lang						= "de";
my $text						= "";
my $TextWordCounter				= 1;
my $ModifiedWordcounter			= 1;
my $FullContentArray			= "";

my $UsedString					= 0;
my $UsedTextBlowup				= 0;
my $UsedSynonym					= 0;
my $UsedZahl2Word				= 1;
my $UsedGrundform				= 0;

my $StopWordList				= {};
my %StopWordList				= ();

my @SynonymContent				= ();
my @FullContent					= ();

my $MainKeyWord					= "Harry Potter";
my $SrcFile						= "src-$lang.txt";	# quell	
my $ModFile						= "mod.txt";		# .. zielfile
my $SynFile						= "synonym-db/synonym-$lang.txt";
my $now_string					= localtime;


# stopword list initialisieren
%StopWordList = ( "einen" => undef ) ;

# print Dumper $StopWordList;exit;


# src file einlesen
open( RH, "<$SrcFile" ) or die "sudden flaming death\n";
	flock(RH, 2);
	$text = do { local( $/ ) ; <RH> } ;
close RH;


open(SYN,"<$SynFile") or die;
	flock(SYN,2);
	@SynonymContent = <SYN>;
close SYN;


@FullContent			= split(' ', $text);
my $TextWordCounter		= $#FullContent; 
my $FullContentArray	= &Main( \@FullContent );


# mod file schreiben
open( WH, ">$ModFile" ) or die "sudden flaming death\n";
	flock(WH, 2);

#	my $ModifiedText = "";
	for ( @{$FullContentArray} ) {	# todo: content ordnen: sprich nach 5 sätzen ( eg nach 5 .) ein \n schreiben
		print WH " " . $_;
#		$ModifiedText .= $_ . " ";
	};

#	my $sentences	= get_sentences($ModifiedText);	
#	for ( @{$sentences} ) {
#		print WH "$_\n";
#	};

close WH;

my $now1_string		= localtime;
my $ModifiedText	= sprintf("%.4f", $ModifiedWordcounter / $TextWordCounter ) * 100;


print "#################### ContentCleaner ####################\n";
print "#### \t [$ModifiedText%] modified Text\n";
print "#### \t [$ModifiedWordcounter] modified Words \n";
print "#### \t [$TextWordCounter] whole Words \n";

	print "#### \t Transformations used: ";
	if ( $UsedString == 1 ) {
		print "[StringManipulation()] ";
	};
	if ( $UsedTextBlowup == 1 ) {
		print "[TextBlowup()] ";
	};
	if ( $UsedSynonym == 1 ) {
		print "[SynonymManipulation()] ";
	};
	if ( $UsedZahl2Word == 1 ) {
		print "[Zahl2Wort()] ";
	};
	if ( $UsedGrundform == 1 ) {
		print "[GrundformManipulation()] ";
	};
	print "\n";


print "#### \t Beg: $now_string \n";
print "#### \t End: $now1_string \n";
print "#### \t Worked: $MainKeyWord	| $SrcFile | $SynFile\n";
print "#########################################################\n";

exit(0);


########
### Main(): rufe alle wichtige funktionen geordnet auf

sub Main(){

	my $FullContent = shift;

	$FullContent = &SynonymManipulation( $FullContent );				### SynonymManipulation(): zufälliges ersetzen von deutschen wörtern mit einem zufälligem synonym zum ursprünglichen wort	
	$FullContent = &TextBlowup( $FullContent );							### TextBlowup(): füge satzkombinationen zum array hinzu
	$FullContent = &ZahlManipulation( $FullContent );					### ZahlManipulation(): ersetzen von zahlen mit den entsprechenden namen für die zahlen
	#	$FullContent = &StringManipulation( $FullContent );				### StringManipulation(): buchstaben, zeichen, wörter spiegeln, vertauschen, löschen, ersetzen ...
	#	$FullContent = &GrundformManipulation( $FullContent );			### GrundformManipulation(): reduzierung von deutschen wörtern auf ihre grundform
	
	return $FullContent;

}; # Main()


###########
### ZahlManipulation(): ersetzen von zahlen mit den entsprechenden namen für die zahlen

sub ZahlManipulation(){

	my $FullContentArray	= shift;

	# zahl in wort umwandeln, wenn quellzeichen eine zahl ist
	for ( @{$FullContentArray} ) {

		if ( $_ =~ /\d/ && $lang == "de" ) {
			
			my $Copy = $_;
			#	print "old: $_\n";
		
			$_ = Zahl2Wort( $_ );
						
			if ( $Copy =~ /\./ ) {
				$_ = $_ . ".";
			} elsif ( $Copy =~ /\,/ ) {
				$_ = $_ . ",";
			} elsif ( $Copy =~ /\;/ ) {
				$_ = $_ . ";";
			} elsif ( $Copy =~ /\!/ ) {
				$_ = $_ . "!";
			} elsif ( $Copy =~ /\?/ ) {
				$_ = $_ . "?";
			};

			# im fehlerfall, restauriere den wert von $Copy als aktuellen wert von $_
			if ( $_ eq "null") {
				$_ = $Copy;
			} else {
				$ModifiedWordcounter++;
			};

			#	print "new: $_\n";

		} elsif ( $_ =~ /\d/ && $lang == "en" ) {

			my $Copy = $_;
			#	print "old: $_\n";
		
			$_ = Number2Word( $_ );
						
			if ( $Copy =~ /\./ ) {
				$_ = $_ . ".";
			} elsif ( $Copy =~ /\,/ ) {
				$_ = $_ . ",";
			} elsif ( $Copy =~ /\;/ ) {
				$_ = $_ . ";";
			} elsif ( $Copy =~ /\!/ ) {
				$_ = $_ . "!";
			} elsif ( $Copy =~ /\?/ ) {
				$_ = $_ . "?";
			};

			# im fehlerfall, restauriere den wert von $Copy als aktuellen wert von $_
			if ( $_ eq "zero") {
				$_ = $Copy;
			} else {
				$ModifiedWordcounter++;
			};
			
		}; # } elsif ( $_ =~ /\d/ && $lang == "en" ) {

	}; # for ( @{$FullContent} ) {

	return $FullContentArray;

}; # sub ZahlManipulation(){


###########
### SynonymManipulation(): zufälliges ersetzen von deutschen wörtern mit einem zufälligem synonym zum ursprünglichen wort

sub SynonymManipulation(){

	my $FullContentArray	= shift;
	$UsedSynonym			= 1;
	my $UpperFlag			= 0;
	
	# NEXTLOOP:
	for ( @{$FullContentArray} ) {
		
		# $CurrentWordCount++;

		my $WordToModify		= $_;
		my $WordToModifyCopy	= $_;

		my $WordToModifyTemp	= $_;
		$WordToModifyTemp		=~ s/[;,?!.(){}&%$"\]\[]//g;	# ersetze alle ungewollten zeichen mit ""

		# benutze die schnelle funktion grep case-insensetive um nach dem aktuellen wort $WordToModifyTemp in der synonymdatenbank @SynonymContent nachzuschauen
		my @grepNames			= grep( /$WordToModifyTemp/i, @SynonymContent) if length $WordToModifyTemp >= 5;
		
		
		# hole einen zufälligen dateneintrag eg "test,test2,test3" aus unserem synonym flatfile herraus
		my $SynTempEntrys		= @grepNames[ int(rand($#grepNames)) ];
		my $strlen				= length $SynTempEntrys;
		
		# wenn $strlen > 0 bedeutet, dass mittels grep ein match gefunden wurde
		# sprich, fahre fort: wenn aktuelles wort kein stopwort ist, ein match für ein synonym gefunden wurde, und das aktuelle wort nicht dem hauptkeyword entspricht
		if ( !exists $StopWordList{$WordToModifyTemp} && $strlen > 0 && $MainKeyWord !~ /$WordToModifyTemp/i ) {
		
			# hole die synonym einträge aus $SynTempEntrys und speichere sie in einem neue array
			my @SynTempEntrys = split("," , $SynTempEntrys );	
			
			# hole ein zufälligen eintrag aus unserem temporären @SynTempEntrys array
			# my $SynReplace	= @SynTempEntrys[ 0 ];	# hole den ersten eintrag aus dem array
			my $SynReplace	= @SynTempEntrys[ int(rand($#SynTempEntrys)) ];
			$SynReplace		=~ s/[;,?!.(){}&%$"\]\[]//g;

			# wenn das aktull ausgesuchte synonym mit dem aktuell zu ersetzenden wort übereinstimmt, dann versuche eine neues, zufälliges zu holen
			if ( $SynReplace eq $WordToModifyTemp || $SynReplace =~ /$WordToModifyTemp/i ) {
				#	print "!!! [$WordToModifyTemp] Ersetzungsstring und Wort sind gleich!\n";
				$SynTempEntrys	= @grepNames[ int(rand($#grepNames)) ];
				@SynTempEntrys	= split("," , $SynTempEntrys );
				$SynReplace		= @SynTempEntrys[ int(rand($#SynTempEntrys)) ];
				#	print "[$SynReplace] -> neues synonym\n ";
			};

			#	my $ModifiedText = sprintf("%.4f", $ModifiedWordcounter / $TextWordCounter ) * 100;
			#	print "[$ModifiedText %] Modified Text - [$CurrentWordCount] Current Word / [$ModifiedWordcounter / $TextWordCounter] Modified Words\n";

			#	print "\tErsetze [$WordToModifyTemp] mit $SynReplace\n";
			#	print "Alter Satz: $_\n";

			$_ =~ eval { s/$WordToModify/$SynReplace/igc } ;

			# schreibe das nächste wort groß, nachdem zuletzt ein satzende festgestellt wurde
			if ( $UpperFlag == 1 ) {
				$UpperFlag = 0;
				$_ = ucfirst($_);
				#	print "Schreibe groß $_\n";
				#	sleep 1;
			};

			# füge Satzzeichen wieder mit ein!
			if ( $WordToModifyCopy =~ /\./ ) {
				$_ = $_ . ".";
				$UpperFlag = 1;
			} elsif ( $WordToModifyCopy =~ /\,/ ) {
				$_ = $_ . ",";
			} elsif ( $WordToModifyCopy =~ /\;/ ) {
				$_ = $_ . ";";
			} elsif ( $WordToModifyCopy =~ /\!/ ) {
				$_ = $_ . "!";
				$UpperFlag = 1;
			} elsif ( $WordToModifyCopy =~ /\?/ ) {
				$_ = $_ . "?";
				$UpperFlag = 1;
			};

			# füge newlines hinzu: funzt nicht
			if ( $WordToModify =~ /\n/ ) {
				$_ .= "\n";
			};

			#	print "Neuer Satz: $_\n";

			$ModifiedWordcounter++;
			
		}; # if ( $strlen > 0 ) {

	
	#	my $random = rand();
	#	if ( $random > 0.975 ) {
	#		
	#		my $old		= $_;
	#		my $result;
	#		eval {
	#			$result	= Lingua::DE::Wortschatz::use_service('T', $_);
	#		};
	#		my @lines	= $result->hashrefs();
	#		my $String	= @lines[ int(rand(@lines)) ] ;
	#		$_			= $String->{Synonym} if ( length($String->{Synonym}) > 1 );		
	#		print "Old: $old --- New: $_\n";
	#
	#	};

	}; # for ( @FullContentArray ) {

	return $FullContentArray;

}; # sub SynonymManipulation(){



############
### TextBlowup(): füge satzkombinationen zum array hinzu

sub TextBlowup(){
	
	my $FullContentArray	= shift;
	my $TextBlowupCounter	= 0;
	$UsedTextBlowup			= 1;

	for ( @{$FullContentArray} ) {
		
		# random wert von 0.9995 führt bei einem text von 26K zu 0-2 veränderungen
		if ( rand() > 0.9995 ) {
			$TextBlowupCounter++;
			my @alpha_sorted = ();									# lege neues array an

			for (my $i=0; $i<=int(rand(20))+7; $i++ ) {				# für 0 bis rand(30) fülle ein das neue array @alpha_sorted mit zufälligen werten aus dem arrays @FullContent
				my $randomString	= lc @FullContent[ int(rand($#FullContent)) ];
				$randomString		=~ s/[;,?!.(){}&%$"\]\[]//g;
				push(@alpha_sorted, $randomString );
			};
		
			@alpha_sorted	= sort { $b cmp $a } (@alpha_sorted);	# führe  sort aus ...
					
			# later: splice the content of @alpha_sorted as a string somewhere in the rand(middle) of @FullContent


			# ... und schaufele die geordneten daten wieder ans ende von  @FullContent
			my $RandCount = 0;
			for (@alpha_sorted) {
				if ( $RandCount == 0 ) {
					push(@{$FullContentArray}, ucfirst $_);		# das erste zeichen muss gross gemacht werden -> Satzbeginn
				} else {
					push(@{$FullContentArray}, $_);		
				}; # if ( $RandCount == 0 ) {
				$RandCount++;
			}; # for (@alpha_sorted) {

			push(@{$FullContentArray}, ".");					# Satzende -> Punkt setzen !

			$ModifiedWordcounter += $#alpha_sorted;
			print "[$TextBlowupCounter] TextBlowup @alpha_sorted.\n";

		#	sleep 3;
		#	print @{$FullContentArray};
		#	exit;

		}; # if ( $random > 0.95 ) {

	}; # for ( @FullContent ) {

	return $FullContentArray;

}; # sub GrundformManipulation(){


###########
### Zahl2Wort(): wandele eine zahl in ein deutsches wort um

sub Zahl2Wort(){

	my $zahl = shift;
	my $text = Lingua::DE::Num2Word::num2de_cardinal( $zahl );
	if ( length ($text) >= length ($zahl) ) {
		return $text;
	} else {
		return $zahl;
	};

}; # sub Zahl2Wort(){


###########
### Number2Word(): wandele eine zahl in ein englisches wort um

sub Number2Word(){

	my $zahl = shift;
	my $text = Lingua::EN::Inflect::NUMWORDS($zahl);
	if ( length ($text) >= length ($zahl) ) {
		return $text;
	} else {
		return $zahl;
	};

}; # sub Number2Word(){







###########################################
##### folgenden code nicht verwenden
###########################################


### wörter falsch schreiben 
# use Lingua::DE::TypoGenerator;
# my $ldt = Lingua::DE::TypoGenerator->new();
# my @typos = $ldt->typos("Harry Potter");
# print join " \n", , @typos;



#	$FullContent = StringManipulation( $FullContent );					### StringManipulation(): buchstaben, zeichen, wörter spiegeln, vertauschen, löschen, ersetzen ...
#	$FullContent = &GrundformManipulation( $FullContent );				### GrundformManipulation(): reduzierung von deutschen wörtern auf ihre grundform

my @letters		= (	"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 @numbers		= ( "0", "1", "2", "3", "4", "5", "6", "7",
					"8", "9" );

my @characters	= (	"+", "-", "&", " ", "(", ")", "@", "!",
					"%" );


############
### GrundformManipulation(): reduzierung von deutschen wörtern auf ihre grundform

sub GrundformManipulation(){
	
	my $FullContentArray	= shift;
	$UsedGrundform			= 1;	

	for ( @{$FullContentArray} ) {
		
		my $random = rand();

		if ( $random > 0.5 ) {
			$_ = Text::German::reduce($_);			
		};

	}; # for ( @FullContentArray ) {

	return $FullContentArray;

}; # sub GrundformManipulation(){





############
### StringManipulation(): buchstaben, zeichen, wörter spiegeln, vertauschen, löschen, ersetzen ...


sub StringManipulation(){
	
	my $FullContentArray	= shift;
	$UsedString				= 1;
	

	for ( @{$FullContentArray} ) {


		# für jede Anweisung wird eine neue zufällige Zahl erstellt
		

		###
		# Erste Buchstaben groß/klein schreiben
		###

		my $random = rand();
		if ( $random > 0.4 && $random < 0.5 ) {
			$_ = ucfirst();		# zufällig ersten Buchstaben groß schreiben
		} elsif ( $random > 0.5 && $random < 0.6 ) {
			$_ = lcfirst();		# zufällig ersten Buchstaben klein schreiben
		};


		###
		# Wort groß/klein schreiben
		###

		my $random = rand();
		if ( $random >= 0.3 && $random <= 0.4 ) {
			$_ = uc();		# zufällig Wort groß schreiben
		} elsif ( $random >= 0.7 && $random <= 0.8 ) {
			$_ = lc();		# zufällig Wort klein schreiben
		};


		###
		# zufälliges Zeichen einfügen
		###

		my $random			= rand();
		my $replaceString	= @characters[ rand(@characters) ] ;
		
		if ( $random < 0.09 ) {
			substr($_, rand(length), 0 ) = "$replaceString";
		};
		
		
		###
		# zufällige Nummer einfügen
		###

		my $random			= rand();
		my $replaceString	= @numbers[ rand(@numbers) ] ;
		
		if ( $random < 0.09 ) {
			substr($_, rand(length), 0 ) = "$replaceString";
		};


		###
		# zufälligen Buchstaben einfügen
		###

		my $random			= rand();
		my $replaceString	= @letters[ rand(@letters) ] ;
		
		if ( $random < 0.09 ) {
			substr($_, rand(length), 0 ) = "$replaceString";	
		};


		###
		# Wörter zufällig verdoppeln
		###

		my $random = int(rand(30));
			
		if ( $random == 5 ) {
			$_ .= $_;
		};


		###
		# Wörter zufällig verdoppeln und das vedoppelte spiegeln
		###

		my $random = int(rand(30));
			
		if ( $random == 6 ) {
			$_ .= reverse $_;
		};


		###
		# Wörter zufällig spiegeln
		###

		my $random = int(rand(30));
			
		if ( $random == 7 ) {
			$_ = reverse $_;
		};


		###
		# zeichen aus einem Wort zufällig löschen
		###

		my $random	= rand();
		my $length  = length($_);
	
		if ( $length > 0 ) {
		
			if ( $random < 1/$length ) {
				substr($_, rand(length), rand(length) ) = "";
			}; # if ( $random < 1/$length ) {
		
		}; # if ( $length > 0 ) {
		
		###
		# Deutsche Umlaute zufällig ersetzen
		###

		my $random = int(rand(30));
			
		if ( $random == 1 ) {
			eval {
				$_ = to_ascii($_) if ( length($_) > 3 );
			};
		};


		###
		# Wort zufällig mit unsinnigen zeichen füllen
		###

		my $random	= rand();
		my $length  = length($_);
		
		if ( $length > 0 ) {

			if ( $random < 3/length ) {

				my $cp = $_;
				$_  = "";

				for ( length($cp) ) {
					
					my $random = int(rand(127));
					$_ .= chr($random);

				}; # for
			}; # if ( $random
		}; # if ( $length > 0 ) {
	
	}; # for ( @FullContent ) {

	return $FullContentArray;

}; # sub StringManipulation(){


# my $LevenshteinDistance = fastdistance($WordToModifyTemp, $SynEntry) if length $WordToModifyTemp > 3;
			# print "$WordToModifyTemp MATCH $SynEntry\n";
			# if ( $WordToModifyTemp =~ /$SynEntry/i && length $WordToModifyTemp > 3 && $LevenshteinDistance <= 2 ) {
			

# bringe die synonyme in ein hash ein
#for ( @SynonymContent ) {
#	# my @SynTempEntrys = split("," , $_ );
#	for ( split("," , $_ ) ) {
#		chomp;
#		# print "adde $_\n";
#		$SynonymContent->{ lc($_) } = undef;
#	}; # for ( @SynTempEntrys ) {
#}; # for ( @SynonymContent ) {

#print Dumper($SynonymContent); 
#exit;


1;