package Crop::File;
use base qw/ Crop::Object::Simple /;

=begin nd
Class: Crop::File
	File for project.
	
	Abstract class.
=cut

use v5.14;
use warnings;

use Crop::Error;
use Crop::File::Warehouse;
use Crop::File::LOCAL;
use Crop::File::CDN;
use Crop::Util;

use Crop::Debug;

=begin nd
Variable: my $Type
	Direct hash of types in form of (1=>LOCAL, 2=>CDN,...).
	
	The point is this structure is calculated only once.
	
Variable: my %WH_type
	Reverse hash of Types in form of (LOCAL=>1, CDN=>2,...).
	
	The point is this structure is calculated only once.
=cut
my $Type = Crop::File::Warehouse->All->Hash;
my %WH_type;
while (my ($id, $wh) = each %$Type) {
	$WH_type{$wh->code} = $id;
}

=begin nd
Variable: our %Attributes
	Class attributes:
	
	ctime     - creation time of file on site, not the ctime of file themself
	id        - generated by <Crop::Object::Simple>
	path      - full path in warehouse, including filename, without leading slash
	size      - size in bytes
	warehouse - warehouse the file is stored in (descendant of this class)
=cut
our %Attributes = (
	ctime     => undef,
	path      => {mode => 'read'},
	size      => {mode => 'read'},
	warehouse => undef,
);

=begin nd
Constructor: new (%attr)
	Set filetype based on the 'warehouse' attr.
	
	The attribute 'warehouse' serves as the base for define integer key for the sama attribute, and will be replaced the one.
	
	As this class is abstract direct call arise the error.
	
Parameters:
	%attr - attributes has have at least one obligatory element 'warehouse' in form of CODE (LOCAL, CDN, DAV)
	
	%attr must be prepared by descendant.
	
Returns:
	$self - ok
	undef - error
=cut
sub new {
	my $class = shift;
	my $attr = expose_hashes \@_;
	
	if ($class eq __PACKAGE__) {
		return warn 'OBJECT|CRIT: File Constructor must have the warehouse been specified' unless defined $attr->{warehouse};
		
		my $descendant = 'Crop::File::' . $Type->{$attr->{warehouse}}->code;
		return $descendant->new($attr, warehouse => undef);
	}
		
	return warn 'OBJECT|CRIT: File type is missing' unless $attr->{warehouse};
	
	my $self = $class->SUPER::new(
		%$attr,
		warehouse => $WH_type{$attr->{warehouse}},
	);
	$self->{ctime} //= $self->S->tik->timestamp;
	
	$self;
}

=begin nd
Method: Table ( )
	Table in the Warehouse.

Returns:
	'file' string
=cut
sub Table { 'file' }

=begin nd
Method: upload ( )
	Pure virtual.
	
	Uploading process depends on warehouse type, so each type has to define its own mechanism.
=cut
sub upload {
	my $self = shift;
	my $class = ref $self;
	
	return warn "FILE|CRIT: Method upload() must be redefined by subclass";
}

1;
