package PerlRPG::Assets;
use strict;
require Exporter;
use SDL;
use SDL::Event;
use SDLx::App;
use SDLx::Sprite;
use SDLx::Sprite::Animated;
use PerlRPG::Console;
use PerlRPG::Game;

use vars qw/%files @ISA @EXPORT @EXPORT_OK/;
@ISA = qw/Exporter/;
@EXPORT = qw/ScanDirectory GetAsset GetAssetType LoadAssets UnloadAsset SetAssetOption/;
@EXPORT_OK = ();

# Check %files cache for file location, otherwise search in path
sub FindFile {
	my $filename=shift(@_);
	if(exists $files{$filename}) {
		return $files{$filename}{'Location'};
	}

	my $full = FindFileInDir(GetOption('ResourceDir'), $filename);
	if($full) {
		$files{$filename}={
			'Loaded'	=> 0,
			'Location'	=> $full,
			};
		LogData(DEBUG, "Located '$filename' at '$full'");
		return $full;
	}
	LogData(WARN, "Unable to locate file '$filename' in Resource Path");
	return undef;
}

# Search for filename in path given and all sub-directories (Recursive)
sub FindFileInDir {
	my($dir, $filename)=@_;
	if(-f "$dir/$filename") {
		return "$dir/$filename";
	}

	foreach my $file (<$dir/*>) {
		next unless(-d $file);
		if(my $res = FindFileInDir($file, $filename)) {
			return $res;
		}
	}
	return undef;
}

# Scan every file in path given and add to %files (Recursive)
sub ScanDirectory {
	my $path = shift(@_);

	foreach my $file (<$path/*>) {
		if(-d $file) {
			ScanDirectory($file);
		} else {
			my($fname)=$file=~/.+\/(.+?)$/;
			$files{$fname}={
				'Loaded'	=> 0,
				'Location'	=> $file,
				};
		}
	}
}

# Load all assets with given file extension
sub LoadAssets {
	my @res;
	foreach my $ext (@_) {
		LogData(DEBUG, "Loading *.$ext assets");
		foreach my $file (grep { /\.$ext$/i } (keys %files)) {
			LoadAsset($file, $files{$file}{'Location'}) unless($files{$file}{'Loaded'});
			push @res, $file;
		}
	}
	return @res;
}

# Return the asset object
sub GetAsset {
	my($file)=@_;

	if(!exists $files{$file} || !$files{$file}{'Loaded'}) {
		if(!LoadAsset($file)) {
			return undef;
		}
	}
	return $files{$file}{ $files{$file}{'Type'} };
}

# Return asset object type
sub GetAssetType {
	my($file)=@_;

	if(!exists $files{$file} || !$files{$file}{'Loaded'}) {
		if(!LoadAsset($file)) {
			return undef;
		}
	}
	return $files{$file}{'Type'};
}

sub UnloadAsset {
	my($file)=@_;
	if(exists $files{$file}) {
		$files{$file}{'Loaded'} = 0;
		delete $files{$file}{ $files{$file}{'Type'} };
		$files{$file}{'Type'} = '';
	}
}

sub SetAssetOption {
	my($file, $opt)=@_;
	if(!exists $files{$file}) {
		FindFile($file);
		if(!exists $files{$file}) {
			LogData(ERROR, "Unable to find asset '$file' for SetAssetOption");
			return undef;
		}
	}

	if($files{$file}{'Loaded'}) {
		UnloadAsset($file);
	}
	$files{$file}{'Opt'} = $opt;
	return 1;
}

sub LoadAsset {
	my($file, $filename)=@_;

	if(!$filename && !($filename = FindFile($file))) {
		LogData(FATAL, "Unable to load asset file '$file'; Unable to find file.");
		SetOption('Running', 0);
	}

	if(exists $files{$file}) {
		if($files{$file}{'Loaded'}) {
			return $files{$file};
		}
	} else {
		$files{$file}={
			'Loaded'	=> 0,
			'Location'	=> $filename,
			};
	}


	my($ext)=$file=~/.+\.(.+?)$/;
	$ext = lc($ext);
	if(grep { $_ eq $ext } (qw/png jpg jpeg bmp/)) {
		if($files{$file}{'Opt'} eq 'Animated') {
			LoadAnimatedSprite($file, $filename) || return;
		} else {
			LoadSprite($file, $filename) || return;
		}
	} elsif($ext eq 'vs') {
		unless(open(IN, $filename)) {
			LogData(ERROR, "Unable to load '$filename': $!");
			return undef;
		}
		my @frames = <IN>;
		chomp(@frames);
		close(IN);
		LoadVirtualSprite($file, @frames);
	} elsif($ext eq 'gs') {
		unless(open(IN, $filename)) {
			LogData(ERROR, "Unable to load '$filename': $!");
			return undef;
		}
		$files{$file}{'Type'} = 'Script';
		$files{$file}{'Script'} = [<IN>];
		close(IN);
		chomp @{$files{$file}{'Script'}};
	} else {
		LogData(WARN, "Unable to pre-load asset of type '$ext'");
		return undef;
	}


	$files{$file}{'Loaded'} = 1;
	return $files{$file};
}

sub LoadSprite {
	my($file, $filename)=@_;
	$files{$file}{'Type'} = 'Sprite';
	my $sprite = SDLx::Sprite->new(
		image => $filename,
		);
	if(!$sprite) {
		LogData(ERROR, "Unable to load sprite '$filename': $!");
		return undef;
	}
	$files{$file}{'Sprite'} = $sprite;
	return 1;
}

sub LoadAnimatedSprite {
	my($file, $filename)=@_;
	$files{$file}{'Type'} = 'ASprite';
	my $s1 = SDLx::Sprite->new(
		image => $filename,
		);
	my $surface = $s1->surface();

	my $sprite = SDLx::Sprite::Animated->new(
		surface	=> $surface,
		width	=> $surface->width(),
		height	=> $surface->width(),
		step_x	=> $surface->width(),
		step_y	=> $surface->width(),
		);
	if(!$sprite) {
		LogData(ERROR, "Unable to load ASprite '$filename': $!");
		return undef;
	}
	$files{$file}{'ASprite'} = $sprite;
	return 1;
}

sub LoadVirtualSprite {
	my($name, @files)=@_;

	if(exists $files{$name} && $files{$name}{'Loaded'}) {
		return $files{$name};
	}

	my @frames = map { GetAsset($_) || return } (@files);
	my $h = $frames[0]->surface()->height();
	my $w = $frames[0]->surface()->width();

	my $newsurface = SDLx::Surface->new(	width	=> $w,
						height	=> $h * (@frames-0),
						format	=> $frames[0]->surface()->format(),
						pitch	=> $frames[0]->surface()->pitch(),
						flags	=> $frames[0]->surface()->flags(),
						color	=> [0, 0, 0, 255],
						);

	my $dest_row = 0;
	my $dst_format = $newsurface->format();
	foreach my $src (@frames) {
		my $format = $src->surface()->format();
		for(my $y = 0; $y < $h; $y++, $dest_row++) {
			for(my $x = 0; $x < $w; $x++) {
				my $pixel = $src->surface()->get_pixel( $y, $x );
				my $c = SDL::Video::get_RGBA( $format, $pixel );
				my $c2 = SDL::Video::map_RGBA( $dst_format, @$c );
				$newsurface->set_pixel( $dest_row, $x, $c2 );
			}
		}
	}

	my $anim = SDLx::Sprite::Animated->new( surface		=> $newsurface,
						width		=> $newsurface->width(),
						height		=> $h,
						step_x		=> $newsurface->width(),
						step_y		=> $h,
						);
	$files{$name}{'Loaded'} = 1;
	$files{$name}{'Type'} = 'ASprite';
	$files{$name}{'ASprite'} = $anim;
	return $anim;
}


1;
