#!/usr/bin/perl

use PhexProxy::SortArray qw( Sort_Table );
# use String::Approx 'amatch';
use PhexProxy::Filter;
use Data::Dumper;
use strict;


my $KeywordMatchingMultiply		= 5;
my $NegativMatchingQuantifier	= -100;
my $ApproxMatchingQuantifier	= "40%";
my $MaxSourcesForOneHit			= 20;
my $MaxScanningDepth			= 1000;


# speed related Things
my $SpeedRankingPointsforModem	= 1;
my $SpeedRankingPointsforISDN	= 2;
my $SpeedRankingPointsforDSL	= 4;
my $SpeedRankingPointsforCable	= 4;
my $SpeedRankingPointsforT1		= 6;
my $SpeedRankingPointsforT3		= 7;

my $IsSpeedModem				= 56;	
my $IsSpeedISDN					= 64;
my $IsSpeedDSL					= 1024;
my $IsSpeedCable				= 2048;
my $IsSpeedT1					= 4096;
my $IsSpeedT3					= 6144;

print Dumper PhexSortRank();
sub PhexSortRank(){
	
	my $self					= shift;
	my $SearchQuery				= shift;
	my $FileTypeHashRef			= shift;

	# debug:
	my $SearchQuery				= "britney .jpg";

	my $ResultContent;
	my $ResultString;
	my @ResultContent			= ();
	my @UNSORTED				= ();
	my @SORTED					= ();
	my $SortedHashRef			= {};
	my $SortedHashRefCounter	= 0;

	# debug
	open(RH,"<dump.txt");
		while(<RH>){
			$ResultString .= $_;		 
		};
	close RH;

	# separete the content from the phex proxy
	@ResultContent = split(/\\n/, $ResultString );

	# trenne den Search Query an ' .' auf
	my ( $TemporarySearchQuery, undef) = split(' .', $SearchQuery);
	

	for ( @ResultContent ) {

		if ( length($_) > 20 ) {

			my ($Speed,$SHA1,$Size,$FileIndex,$PeerHost,$FileName) = split(/\;\!\$\#\%\&/, $_);	# ;!$#%& 
			
			if ( length($FileName) > 0 && length($Speed) > 0 && length($SHA1) == 32 && length($Size) > 0 && length($FileIndex) > 0 && $PeerHost =~ /(\d{0,255})+(\.)(\d{0,255})+(\.)(\d{0,255})+(\.)(\d{0,255})+(\:)(\d{1,})/ ) {
				
				my ( $OnlyFileName , $OnlyFileTyp ) = split(/(\.([^.]+?)$)/i, $FileName );	# funzt auch korrekt bei "TEST.JPEG.bmp.jpg" ^^

				# if ( ( lc($OnlyFileTyp) eq lc $FileTypeHashRef->{1} ) || ( lc($OnlyFileTyp) =~ /$FileTypeHashRef->{1}/ ) ) {
				 if ( ( lc($OnlyFileTyp) eq lc "jpg" ) || ( lc($OnlyFileTyp) =~ /jpg/ ) ) {
					
					my $TempFileName = $FileName;

					$TempFileName =~ s/\./ /ig;
					$TempFileName =~ s/\-/ /ig;
					$TempFileName =~ s/\,/ /ig;
					$TempFileName =~ s/\+/ /ig;

					my $matched = 0;
				#	eval {
				#		$matched = amatch($FileName, $ApproxMatchingQuantifier, $TemporarySearchQuery);
				#	};
			
					################################################
					# Wenn der Suchbegriff dem FileName entspricht
					
					if ( $FileName eq $TemporarySearchQuery ) {
						$NegativMatchingQuantifier = 0;
					} elsif ( lc($TemporarySearchQuery) eq lc($FileName) ) {
						$NegativMatchingQuantifier = 0;
					} elsif ( eval { $FileName =~ /$TemporarySearchQuery/ig } ) {
						$NegativMatchingQuantifier = 0;
					} elsif ( $matched == 1 ) {
						$NegativMatchingQuantifier = 0;

					} else {
						
						foreach my $SinglePartOfFilename ( split(' ', $TempFileName ) ) {
							foreach my $SinglePartSearchQuery ( split(' ', $TemporarySearchQuery ) ) {
								if ( lc($SinglePartOfFilename) eq lc($SinglePartSearchQuery) ) {
									$NegativMatchingQuantifier = 0;
								} elsif ( eval { $SinglePartOfFilename =~ /$SinglePartSearchQuery/ig } ) {
									$NegativMatchingQuantifier = 0;
								} else {
									# negativ modifier works here
									# eg: no match so substract -100 points from PageKount

								};	# if ( lc($SinglePartO...
							}; # foreach my $SinglePartSearchQuery ...
						}; # foreach my $SinglePartOfFilename ...
						
					}; # if ( $FileName eq $TemporarySearchQuery ) {}
					
					###################################################
					# Wenn der Suchbegriff dem FileName entspricht
					my $KeyWordMatching = 0;

					if ( length($OnlyFileName) > 0 ) {
						$KeyWordMatching = GetKeyWordMatching( length($SearchQuery) / length($OnlyFileName) ); 
					};
	

					########################################
					#### teste, ob die dateigröße ok ist
					#### teste, ob es kein spamfile ist
					############## >>>>>>>>>>>> todo: ip filter einbauen <<<<<<<<<<<< ############
					my $StatusA = PhexProxy::Filter->SpamFilter( \$FileName, $TemporarySearchQuery );
					my $StatusB = PhexProxy::Filter->SizeFilter( $FileTypeHashRef->{1}, $Size );
					if ( $StatusB == 1 && $StatusA == 1) {

						my $SpeedPoints = GetSpeedPoints($Speed);
						$SortedHashRef->{ $SortedHashRefCounter }->{ 'PH' } = $PeerHost .';'. $FileIndex .';'. $FileName . ';' . $SpeedPoints . "\t\t";
						$SortedHashRef->{ $SortedHashRefCounter }->{ 'FN' } = $FileName;				
						$SortedHashRef->{ $SortedHashRefCounter }->{ 'SH' } = $SHA1;
						$SortedHashRef->{ $SortedHashRefCounter }->{ 'SZ' } = $Size;
						$SortedHashRef->{ $SortedHashRefCounter }->{ 'FI' } = $FileIndex;
						$SortedHashRef->{ $SortedHashRefCounter }->{ 'SP' } = $Speed;
						$SortedHashRef->{ $SortedHashRefCounter }->{ 'RK' } = ($KeyWordMatching + $SpeedPoints + $NegativMatchingQuantifier);
					
						#		print "\n#############\n";
						#		print "SpeedPoints=$SpeedPoints\n";
						#		print "SHA1=$SHA1\n";
						#		print "Size=$Size\n";
						#		print "FileIndex=$FileIndex\n";
						#		print "PeerHost=$PeerHost\n";
						#		print "FileName=$FileName\n";

						$SortedHashRefCounter++;
					}; # if ( $StatusB == -1 ) {

					#### teste, ob die dateigröße ok ist
					#### teste, ob es kein spamfile ist
					########################################
					
				}; # if ( ( lc($OnlyFileTyp) eq $FileTypeHashRef->{1} ) || ( lc($OnlyFileTyp) =~ /$FileTypeHashRef->{1}/ ) ) {

			}; # if ( length($FileName) > 0 && length($Speed) ... ) {
			
		}; # if ( length($_) > 20 ) {

	}; # for ( @ResultContent ) {


	########################################################################################################################
	###### 2 nested for-iterations for ordering the same sources into one single result by checking the sha1 values
	###### get count of HashRef $SortedHashRef -> keep this value, if we would take that value from keys() dynamically it would result in an endless loop :-(
	my $SortHashRefCount = keys(%{$SortedHashRef});

	for ( my $Key=0; $Key<=$SortHashRefCount; $Key++ ) {
		
		my $FileName	= %{$SortedHashRef}->{ $Key }->{ 'FN' };
		my $Speed		= %{$SortedHashRef}->{ $Key }->{ 'SP' };
		my $SHA1		= %{$SortedHashRef}->{ $Key }->{ 'SH' };
		my $Size		= %{$SortedHashRef}->{ $Key }->{ 'SZ' };
		my $FileIndex	= %{$SortedHashRef}->{ $Key }->{ 'FI' };
		my $PeerHost	= %{$SortedHashRef}->{ $Key }->{ 'PH' };
		
		for ( my $NextKey=0; $NextKey<=$SortHashRefCount; $NextKey++ ) {

			my $FileNameNext	= %{$SortedHashRef}->{ $NextKey }->{ 'FN' };
			my $SpeedNext		= %{$SortedHashRef}->{ $NextKey }->{ 'SP' };
			my $SHA1Next		= %{$SortedHashRef}->{ $NextKey }->{ 'SH' };
			my $SizeNext		= %{$SortedHashRef}->{ $NextKey }->{ 'SZ' };
			my $FileIndexNext	= %{$SortedHashRef}->{ $NextKey }->{ 'FI' };
			my $PeerHostNext	= %{$SortedHashRef}->{ $NextKey }->{ 'PH' };
		
			# finde doppelte sha1 werte
			if ( $SHA1 eq $SHA1Next ) {
				
				my @IsDoublePeer = split("\t\t", $SortedHashRef->{ $Key }->{ 'PH' });
				
				my $IsDoublePeer;
				my $BadCount = 0;
				
				for ( my $i=0; $i<=$#IsDoublePeer; $i++ ) {
					my ( $peer, $index, $name ) = split(";", $IsDoublePeer[$i] );
					if ( ($peer eq $PeerHost) && ( length($peer) > 7 ) ) {	# only valid peers needed
						#print "peer=$peer und peerhost=$PeerHost\n";
						$BadCount++;
					}; # if ( $peer eq $PeerHost
				}; # for ( my $i=0; $i<=$#IsDoublePeer; $i++ ) {}
				
				# wenn die ips $peer und $PeerHostNext nicht gleich sind
				if ( $BadCount == 0 ) {
			
					my $SpeedPoints = GetSpeedPoints($SpeedNext);
					$SortedHashRef->{ $Key }->{ 'PH' } .= $PeerHostNext .';'. $FileIndexNext .';'. $FileNameNext . ';' . $SpeedPoints . "\t\t";					
					
					# erhöhe den Ranking Wert des aktuellen Eintrages um den Speed des folgenden Eintrages mit gleicher SHA1 
					# diese daten des folgenden Eintrages bekommen wir in der zeile 166:	my ($Speed,$SHA1,$Size,$FileIndex,$PeerHost,$FileName) = split(/\;\!\$\#\%\&/, $_);	# ;!$#%&  geliefert

					$SortedHashRef->{ $Key }->{ 'RK' } += $SpeedPoints; 
					$SortedHashRef->{ $Key }->{ 'SZ' } = $Size;
					$SortedHashRef->{ $Key }->{ 'SH' } = $SHA1;
				
					# hier dann den aktuellen Next Eintrag löschen
					delete $SortedHashRef->{ $NextKey };
					
				};	# if ( $BadCount == 0 ) {}
			
			}; # if ( $SHA1 eq $SHA1Next ) {
			
		}; # for ( my $NextKey=0; $NextKey<=$SortHashRefCount; $NextKey++ ) {
		
	}; # for ( my $Key=0; $Key<=$SortHashRefCount; $Key++ ) {

	###### 2 nested for-iterations for ordering the same sources into one single result by checking the sha1 values
	########################################################################################################################


	################################################################
	###### Einzelne Sortierung der Ergebnisse nach Speed für ein File
	while( my ($key, $value) = each( %{$SortedHashRef} ) ) {
	
		my $PH = %{$SortedHashRef}->{ $key }->{ 'PH' };
		my $SZ = %{$SortedHashRef}->{ $key }->{ 'SZ' };
		my $SH = %{$SortedHashRef}->{ $key }->{ 'SH' };
		my $RK = %{$SortedHashRef}->{ $key }->{ 'RK' };
		
		my ( @Temporary ) = split("\t\t", $PH);
		my $SortBySpeed;
		$PH ='';   # WICHTIG!!!

		my @SortBySpeed = Sort_Table(
			cols      => '4',
			field     => '4',
			sorting   => 'descending',
			structure => 'csv',
			separator => ';',
			data      => \@Temporary,
		);

		my $SourcesCounter = 0;

		# Setzte die nach Speed sortierten Einträge wieder zusammen
		# Ignoriere dabei falsche Werte ( if-Anweisungen )
		for ( my $j=0 ; $j<=$#SortBySpeed ; $j++ ) {
			my ( $peer, $index, $filename, $speed ) = split(";", $SortBySpeed[$j] );	# im dateinamen darf kein ";" vorkommen
		
				if ( $peer.';'.$index.';'.$filename ne ';;' ) {
					if ( $MaxSourcesForOneHit >= $SourcesCounter ){
						$PH .= $peer.';'. $index.';'. $filename. "\r\n";
						$SourcesCounter++;
					}; # if ( $SourcesCounter >=
				}; # if ( $peer.';'.$inde

		}; # for ( my $j=0 ; $j<=$#SortBySpeed ; $j++ ) {}
				
		if ( ( length($PH) != 0 ) && ( length($SZ) != 0 ) && ( length($SH) != 0 ) ) {
			push(@UNSORTED, "$RK###$PH###$SZ###$SH\n"); 
		};

	}; # while( my ($key, $value) = each( %{$SortedHashRef} ) ) {
	###### Einzelne Sortierung der Ergebnisse nach Speed für ein File
	################################################################

	##########################################
	##### Fix für 1-Result-Bug - 24.ß8.2006
	
	if ( keys %{$SortedHashRef} == 1 ) {
		# Wenn nur ein Ergebnis vorliegt, funktioniert die untere Sortierung mittels Sort_Table nicht korrekt
		# darum wird hier ein Dummy Element eingefügt, welches später wieder entfernt wird. 
		# Dieses Dummy Element ist von nöten, damit @SORTED = Sort_Table() korrekt funktioniert, wenn nur 1 Ergebnis vorliegt.
		push(@UNSORTED, "-3333###-3333###-3333###-3333\n"); 	
	};

	#########################################################
	###### eigentliche Sortierung nach SortRank durchführen
	
	@SORTED = Sort_Table(
		cols      => '4',
		field     => '1',
		sorting   => 'descending',
		structure => 'csv',
		separator => '###',
		data      => \@UNSORTED,
	);

	# speicher separat freigegeben, der Hash geht eh out of scope
	%{$SortedHashRef}	= ();

	return \@SORTED;

}; # sub PhexSortRank(){



sub GetKeyWordMatching(){

	my $int = shift;
	return sprintf ("%.2f", $int) * $KeywordMatchingMultiply;
		
}; # GetKeyWordMatching(){}



sub GetSpeedPoints(){

	my $SpeedValue = shift;

	if ( $SpeedValue <= $IsSpeedModem ) {	# modem speed
		return $SpeedRankingPointsforModem;
	} elsif ( $SpeedValue >= $IsSpeedISDN && $SpeedValue < $IsSpeedDSL ) {	# isdn 
		return $SpeedRankingPointsforISDN;
	} elsif ( $SpeedValue >= $IsSpeedDSL && $SpeedValue < $IsSpeedCable ) {	# dsl
		return $SpeedRankingPointsforDSL;
	} elsif ( $SpeedValue >= $IsSpeedCable && $SpeedValue < $IsSpeedT1 ) {	# cable
		return $SpeedRankingPointsforCable;
	} elsif ( $SpeedValue >= $IsSpeedT1 && $SpeedValue < $IsSpeedT3 ) {	# t1
		return $SpeedRankingPointsforT1;	
	} elsif ( $SpeedValue >= $IsSpeedT3 ) {	# t3
		return $SpeedRankingPointsforT3;
	};

	# never reached
	return 0;

}; # sub GetSpeedPoints(){


# 350	;!$#%&	6KZ7DNIKSGXMGW37OUQRRWWFCHHCDNGC	;!$#%&	625	;!$#%&	7254	;!$#%&	201.92.103.14:42753	;!$#%&	britneyraiva_x17online[1].jpg	\n


# later write cache with full results:
# schreibe: 1#$Speed,$SHA1,$Size,$Fileindex,$PeerHost,$FileName
#			2#$Speed,$SHA1,$Size,$Fileindex,$PeerHost,$FileName
#			3#$Speed,$SHA1,$Size,$Fileindex,$PeerHost,$FileName