#!/usr/bin/perl -w
#
# WoW Generic Updater v0.2
# 
# http://www.phutility.de/wow/tools/
# (c)2010 gr11x

use strict;
use LWP::UserAgent;
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
use File::Basename;
use File::Path;
use XML::Simple;
use POSIX qw(strftime);

$| = 1;

my $addonnameregex = qr/^[\w\s\.\(\)\-]+$/;
sub parseparams() {
	my @params;
	foreach (@ARGV) {
		if ($_ =~ m/$addonnameregex/) {
			push @params, $_;
		}
	}
	return @params;
}

my $now_string = strftime "%Y-%m-%d", localtime;

my $ua = LWP::UserAgent->new;
#$ua->agent('Mozilla/5.0');
#$ua->proxy(['http', 'ftp'], 'http://proxy:8080/');
$ua->timeout(30);

my $addons = XMLin();
my $addondir = $addons->{dir};
my $cachefile = $addons->{cache};
my $keepold = 0;
my $sourcecurse = "http://wow.curseforge.com";

my $sourcewowui = "http://wowui.worldofwar.net/?p=download&m=";
my $sourcewowinterface = "http://www.wowinterface.com/downloads/download";
my $sourcewowace = "http://www.wowace.com";
my $cursefile = "curseaddons_".$now_string.".html";

my @keys;
my $OS;

if ($ENV{OS} =~ m/^Windows/) {
	$OS = "win32";
} else {
	$OS = "unix";
}

if ($#ARGV > -1) {
	@keys = sort(parseparams());
} else {
	@keys = sort {"\L$a" cmp "\L$b"} keys %{$addons->{addon}};
}

sub msgr($) {
	printf "%10s\n", shift;
}

sub msgl($) {
	printf "%-60s", shift;
}

sub readcachefile($) {
	my $cache = XMLin(shift);
	return $cache;
}

sub readzipfordirs($) {
	my $zip = Archive::Zip->new(shift);
	my @dirs;
	my $last = "";
	foreach my $member ($zip->members()) {
		if ($member->fileName() =~ m/^([^\/]+)\//) {			
#		if ($member->isDirectory()) {
#			my ($tldir) = split /\//, $member->fileName();
			my $tldir = $1;
			unless ($tldir eq $last) {
				push @dirs, $tldir;
				$last = $tldir;
			}
		}
	}
	return @dirs;
}

sub extract($) {
	my $zip = Archive::Zip->new(shift);
	msgl("Extracting zip archive...");
	$zip->extractTree(undef, "$addondir/");
	msgr("DONE");
}

sub removeold($) {
	my @dirs = readzipfordirs(shift);
	msgl("Removing old directories...");
	foreach (@dirs) {
		if (-d "$addondir/$_") {
			rmtree("$addondir/$_");
		}
	}
	msgr("DONE");
}

sub download($$) {
	my ($source, $target) = @_;
	my $response;
	my $simplefilename;
	if ($source =~ m/\.zip$/i) {
		($simplefilename) = fileparse($source);	
	} else {
		$response = $ua->head($source);
		if ($response->base  =~ m/\.zip$/i) {
			($simplefilename) = fileparse($response->base);
		} elsif ($response->header("Content-Disposition") =~ m/"(.+?\.zip)"/) {
			($simplefilename) = fileparse($1);
		} else {
			($simplefilename) = fileparse($target);
		}
	}
	msgl("Downloading $simplefilename...");
	$response = $ua->get($source, ":content_file" => $target);
	if ($response->is_success) {
		msgr("DONE");
		return 1;
	}
	msgr("FAILED");
	return 0;
}

sub cleanup($) {
	msgl("Cleaning up...");
	unlink(shift);
	msgr("DONE");
}

sub directdownload($$) {
	my ($source, $target) = @_;
	if (download($source, $target)) {
		unless ($keepold) {
			removeold($target);
		}
		extract($target);
		cleanup($target);
	}
}

sub prepareddownload($$$$) {
	my ($url, $pattern, $base, $target) = @_;
	my $response = $ua->get($url);
	if ($response->is_success) {
		if ($response->content =~ m/$pattern/) {
			directdownload("$base/$1", $target);
		} else {
			print "Search pattern for this addon seems to be wrong, please review!\n";
		}
	} else {
		print "Error while getting information about this addon!\n";
	}
}

sub getcurseurl($$$) {
	my $id = shift;
	my $is_ace = shift;
	my $get_latest = shift;
	my ($pattern1, $pattern2, $addonsuffix, $source);
	if ($is_ace == 1) {
		$source = $sourcewowace;
	} else {
		$source = $sourcecurse;
	}
	$pattern1 = qr!<table class="listing">.*?<td class="col-file">.*?<a href="(.*?)">!s;
#	$pattern2 = qr!<dl class="fact-list">.*?<dt class=".*?">Filename</dt>.*?<a href="(.*?)">(.*?)</a>!s;
	$pattern2 = qr!<li class="user-action user-action-download">.*?<a href="(.*?)">!s;
	$addonsuffix = ($get_latest == 1) ? "/addons/".$id."/files/" : "/addons/".$id."/";
	my $response = $ua->get($source.$addonsuffix);
	if ($response->is_success) {
		my $filepattern = $pattern2;		# handle download links to latest/beta versions
		if ($get_latest == 1) {
			$filepattern = $pattern1;
		}
		if ($response->content =~ m/$filepattern/) {
			my $dlpage = $1;
			$response = $ua->get($source.$dlpage);
			if ($response->is_success) {
				if ($response->content =~ m/$pattern2/) {
					return $1;
				} else {
					print "Error while fetching download link!\n";
				}
			} else {
				print "Error while fetching download page!\n";
			}			
		} else {
			print "Search pattern for this addon seems to be wrong, please review!\n";
		}
	} else {
		print "Error while fetching addon page!\n";
	}
}

sub main() {
	if (-d $addondir) {
		print "Addon directory found, startig update/install...\n";
		foreach my $addon (@keys) {
			my $target = "$addondir/$addon.zip";
			print "\n$addon:\n";
			if ($addons->{addon}->{$addon}->{keepold}) {
				$keepold = 1;
			} else {
				$keepold = 0;
			}
			if ($addons->{addon}->{$addon}->{direct}) {
				directdownload($addons->{addon}->{$addon}->{direct}, $target);
			} elsif (defined($addons->{addon}->{$addon}->{source}) && defined($addons->{addon}->{$addon}->{id})) {
				if ($addons->{addon}->{$addon}->{source} eq "curse" || $addons->{addon}->{$addon}->{source} eq "wowace") {
					my $get_latest = 0;
					if (defined($addons->{addon}->{$addon}->{type}) && ($addons->{addon}->{$addon}->{type} eq "alpha" || $addons->{addon}->{$addon}->{type} eq "beta")) {
						$get_latest = 1;
					}
					if ($addons->{addon}->{$addon}->{source} eq "wowace") {
						directdownload(getcurseurl($addons->{addon}->{$addon}->{id}, 1, $get_latest), $target);
					} else {
						directdownload(getcurseurl($addons->{addon}->{$addon}->{id}, 0, $get_latest), $target);
					}
				} elsif ($addons->{addon}->{$addon}->{source} eq "wowui") {
					directdownload($sourcewowui.$addons->{addon}->{$addon}->{id}, $target);
				} elsif ($addons->{addon}->{$addon}->{source} eq "wowinterface") {
					directdownload($sourcewowinterface.$addons->{addon}->{$addon}->{id}, $target);
				} else {
					print "Error, source or id not defined, aborting.\n";
				}
			} else {
				prepareddownload(
					$addons->{addon}->{$addon}->{content},
					$addons->{addon}->{$addon}->{regex},
					$addons->{addon}->{$addon}->{prelink},
					$target
				);
			}
		}
	} else {
		print "\nDirectory $addondir does not exist,\nplease create or edit!\n";
	}
	print "________________________________\n\nFinished.\n\n";
	if ($OS eq "win32") {
		system("pause");		
	}
}

main();
