package WebGUI::Asset::File::ZipArchive;

=head1 LEGAL

 -------------------------------------------------------------------
  WebGUI is Copyright 2001-2009 Plain Black Corporation.
 -------------------------------------------------------------------
  Please read the legal notices (docs/legal.txt) and the license
  (docs/license.txt) that came with this distribution before using
  this software.
 -------------------------------------------------------------------
  http://www.plainblack.com                     info@plainblack.com
 -------------------------------------------------------------------

=cut

use strict;
use base 'WebGUI::Asset::File';
use WebGUI::HTMLForm;
use WebGUI::SQL;
use WebGUI::Utility;

use Archive::Tar;
use Archive::Zip;
use Cwd ();
use Scope::Guard ();



=head1 NAME

Package WebGUI::Asset::ZipArchive

=head1 DESCRIPTION

Provides a mechanism to upload and automatically extract a zip archive
containing related items.  An asset setting will set the launch point of the archive.

=head1 SYNOPSIS

use WebGUI::Asset::ZipArchive;

=head1 METHODS

These methods are available from this class:

=cut

#-------------------------------------------------------------------

=head2 unzip ( $storage, $filename )

Uncompress and/or expand an archive, based on the file extension of the filename.
Returns 1 if the unzip was successful.  Returns 0 if there were problems.

=head3 $storage

A WebGUI::Storage object containing the archive.

=head3 $filename

The filename of the archive.

=cut

sub unzip {
	my $self = shift;
	my $storage = shift;
	my $filename = shift;
   
	my $filepath = $storage->getPath();
    my $cwd = Cwd::cwd();
    chdir $filepath;
    my $dir_guard = Scope::Guard->new(sub { chdir $cwd });
   
	my $i18n = WebGUI::International->new($self->session,"Asset_ZipArchive");
	if ($filename =~ m/\.zip$/i) {
		my $zip = Archive::Zip->new();
		unless ($zip->read($filename) == $zip->AZ_OK){
			$self->session->errorHandler->warn($i18n->get("zip_error"));
			return 0;
		}
		$zip->extractTree();
        $self->fixFilenames;
	} elsif ($filename =~ m/\.tar$/i) {
		Archive::Tar->extract_archive($filepath.'/'.$filename,1);
		if (Archive::Tar->error) {
			$self->session->errorHandler->warn(Archive::Tar->error);
			return 0;
		}
        $self->fixFilenames;
	} else {
		$self->session->errorHandler->warn($i18n->get("bad_archive"));
	}

	return 1;
}

#-------------------------------------------------------------------

=head2 addRevision ( )

This method exists for demonstration purposes only.  The superclass
handles revisions to ZipArchive Assets.

=cut

sub addRevision {
	my $self = shift;
	my $newSelf = $self->SUPER::addRevision(@_);
	return $newSelf;
}

#-------------------------------------------------------------------

=head2 definition ( definition )

Defines the properties of this asset.

=head3 definition

A hash reference passed in from a subclass definition.

=cut

sub definition {
	my $class = shift;
	my $session = shift;
	my $definition = shift;
	my $i18n = WebGUI::International->new($session,"Asset_ZipArchive");
	push(@{$definition}, {
		assetName=>$i18n->get('assetName'),
		tableName=>'ZipArchiveAsset',
		autoGenerateForms=>1,
		icon=>'ziparchive.gif',
		className=>'WebGUI::Asset::File::ZipArchive',
		properties=>{
			showPage=>{
				tab=>"properties",
				label=>$i18n->get('show page'),
				hoverHelp=>$i18n->get('show page description'),
				fieldType=>'text',
				defaultValue=>'index.html'
			},
			templateId=>{
				tab=>"display",
				label=>$i18n->get('template label'),
				namespace=>"ZipArchiveAsset",
				fieldType=>'template',
				defaultValue=>'ZipArchiveTMPL00000001',
			},
		}
	});
	return $class->SUPER::definition($session,$definition);
}


#-------------------------------------------------------------------

=head2 fixFilenames ( )

Fix any files with dangerous extensions, in all files that were extracted.  This is done
locally, because if we used a method from Storage, then it would also rename HTML files.

=cut

sub fixFilenames {
	my $self    = shift;
    my $storage = $self->getStorageLocation;
    my $files   = $storage->getFiles('all');
    FILE: foreach my $file (@{ $files }) {
        my $extension = $storage->getFileExtension($file);
        next FILE unless isIn($extension, qw/pl perl pm cgi php asp sh/);
        my $newFile = $file;
        #$newFile =~ s/\.$extension$/_$extension.txt/;
        $newFile =~ s/\.$extension$/_$extension.txt/;
        $storage->renameFile($file, $newFile);
    }
}

#-------------------------------------------------------------------

=head2 prepareView ( )

See WebGUI::Asset::prepareView() for details.

=cut

sub prepareView {
	my $self = shift;
	$self->SUPER::prepareView();
	my $template = WebGUI::Asset::Template->new($self->session, $self->get("templateId"));
	$template->prepare($self->getMetaDataAsTemplateVariables);
	$self->{_viewTemplate} = $template;
}


#-------------------------------------------------------------------

=head2 processPropertiesFromFormPost ( )

Used to process properties from the form posted.  In this asset, we use
this method to deflate the zip file into the proper folder

=cut

sub processPropertiesFromFormPost {
	my $self = shift;
	#File should be saved here by the superclass
	$self->SUPER::processPropertiesFromFormPost;
	my $storage = $self->getStorageLocation();
	
	my $file = $self->get("filename");
	
	#return undef unless $file;
	my $i18n = WebGUI::International->new($self->session, 'Asset_ZipArchive');
	unless ($self->session->form->process("showPage")) {
		$storage->delete;
		$self->session->db->write("update FileAsset set filename=NULL where assetId=".$self->session->db->quote($self->getId));
		$self->session->scratch->set("za_error",$i18n->get("za_show_error"));
		return undef;
	}
	
	unless ($file =~ m/\.tar$/i || $file =~ m/\.zip$/i) {
		$storage->delete;
		$self->session->db->write("update FileAsset set filename=NULL where assetId=".$self->session->db->quote($self->getId));
		$self->session->scratch->set("za_error",$i18n->get("za_error"));
		return undef;
	}
	
	unless ($self->unzip($storage,$self->get("filename"))) {
		$self->session->errorHandler->warn($i18n->get("unzip_error"));
	}
}


#-------------------------------------------------------------------

=head2 view ( )

Method called by the container www_view method.  In this asset, this is
used to show the file to administrators.

=cut

sub view {
	my $self = shift;
	if (!$self->session->var->isAdminOn && $self->get("cacheTimeout") > 10) {
        my $cache = $self->getCache;
        my $out   = $cache->get if defined $cache;
		return $out if $out;
	}
	my %var = %{$self->get};
	#$self->session->errorHandler->warn($self->getId);
	$var{controls} = $self->getToolbar;
	if($self->session->scratch->get("za_error")) {
	   $var{error} = $self->session->scratch->get("za_error");
	}
	$self->session->scratch->delete("za_error");
	my $storage = $self->getStorageLocation;
	if($self->get("filename") ne "") {
	   $var{fileUrl} = $storage->getUrl($self->get("showPage"));
	   $var{fileIcon} = $storage->getFileIconUrl($self->get("showPage"));
	}
	unless($self->get("showPage")) {
	   $var{pageError} = "true";
	}
	my $i18n = WebGUI::International->new($self->session,"Asset_ZipArchive");
	$var{noInitialPage} = $i18n->get('noInitialPage');
	$var{noFileSpecified} = $i18n->get('noFileSpecified');
       	my $out = $self->processTemplate(\%var,undef,$self->{_viewTemplate});
	if (!$self->session->var->isAdminOn && $self->get("cacheTimeout") > 10) {
		WebGUI::Cache->new($self->session,"view_".$self->getId)->set($out,$self->get("cacheTimeout"));
	}
       	return $out;
}


#-------------------------------------------------------------------

=head2 www_edit ( )

Web facing method which is the default edit page

=cut

sub www_edit {
    my $self = shift;
    return $self->session->privilege->insufficient() unless $self->canEdit;
    return $self->session->privilege->locked() unless $self->canEditIfLocked;
	my $i18n = WebGUI::International->new($self->session, 'Asset_Wobject');
	my $addEdit = ($self->session->form->process("func") eq 'add') ? $i18n->get('add') : $i18n->get('edit');
    return $self->getAdminConsole->render($self->getEditForm->print, $self->addEditLabel);
}

#-------------------------------------------------------------------

=head2 www_view ( )

Web facing method which is the default view page.  This method does a 
302 redirect to the "showPage" file in the storage location.

=cut

sub www_view {
	my $self = shift;
	return $self->session->privilege->noAccess() unless $self->canView;
	if ($self->session->var->isAdminOn) {
		return $self->session->asset($self->getContainer)->www_view;
	}
	$self->session->http->setRedirect($self->getFileUrl($self->getValue("showPage")));
	return "1";
}


1;

