use utf8;
 use Encode qw(decode);
+use English qw( -no_match_vars );
 use URI::Escape;
 use Cwd;
 use DateTime;
 use File::stat;
+use File::Slurp qw(slurp);
 use File::Spec::Unix;
 use File::Spec::Win32;
 use File::MimeInfo::Magic;
+use MIME::Base64;
 use SL::DB::Helper::Mappings;
 use SL::DB::Order;
 use SL::DB::DeliveryOrder;
 use SL::Helper::CreatePDF qw(:all);
 use SL::Locale::String;
 use SL::SessionFile;
+use SL::SessionFile::Random;
 use SL::File;
-use SL::Controller::Helper::ThumbnailCreator qw(file_probe_image_type);
-
-use constant DO_DELETE    =>   0;
-use constant DO_UNIMPORT  =>   1;
+use SL::Controller::Helper::ThumbnailCreator qw(file_probe_image_type file_probe_type);
 
+use constant DO_DELETE   => 0;
+use constant DO_UNIMPORT => 1;
 
 use Rose::Object::MakeMethods::Generic
 (
 
 __PACKAGE__->run_before('check_object_params', only => [ qw(list ajax_delete ajax_importdialog ajax_import ajax_unimport ajax_upload ajax_files_uploaded) ]);
 
+# gen:    bitmask: bit 1 (value is 1, 3, 5 or 7) => file created
+#                  bit 2 (value is 2, 3, 6 or 7) => file from other source (e.g. directory for scanned documents)
+#                  bit 3 (value is 4, 5, 6 or 7) => upload as other source
+# gltype: is this used somewhere?
+# dir:    is this used somewhere?
+# model:  base name of the rose model
+# right:  access right used for import
 my %file_types = (
-  'sales_quotation' =>         { gen => 1 ,gltype => '',   dir =>'SalesQuotation',       model => 'Order',          right => 'import_ar'  },
-  'sales_order'     =>         { gen => 1 ,gltype => '',   dir =>'SalesOrder',           model => 'Order',          right => 'import_ar'  },
-  'sales_delivery_order' =>    { gen => 1 ,gltype => '',   dir =>'SalesDeliveryOrder',   model => 'DeliveryOrder',  right => 'import_ar'  },
-  'invoice'         =>         { gen => 1 ,gltype => 'ar', dir =>'SalesInvoice',         model => 'Invoice',        right => 'import_ar'  },
-  'credit_note'     =>         { gen => 1 ,gltype => '',   dir =>'CreditNote',           model => 'Invoice',        right => 'import_ar'  },
-  'request_quotation' =>       { gen => 3 ,gltype => '',   dir =>'RequestForQuotation',  model => 'Order',          right => 'import_ap'  },
-  'purchase_order' =>          { gen => 3 ,gltype => '',   dir =>'PurchaseOrder',        model => 'Order',          right => 'import_ap'  },
-  'purchase_delivery_order' => { gen => 3 ,gltype => '',   dir =>'PurchaseDeliveryOrder',model => 'DeliveryOrder',  right => 'import_ap'  },
-  'purchase_invoice' =>        { gen => 2 ,gltype => 'ap', dir =>'PurchaseInvoice',      model => 'PurchaseInvoice',right => 'import_ap'  },
-  'vendor' =>                  { gen => 0 ,gltype => '',   dir =>'Vendor',               model => 'Vendor',         right => 'xx'  },
-  'customer' =>                { gen => 1 ,gltype => '',   dir =>'Customer',             model => 'Customer',       right => 'xx'  },
-  'part' =>                    { gen => 0 ,gltype => '',   dir =>'Part',                 model => 'Part',           right => 'xx'  },
-  'gl_transaction' =>          { gen => 2 ,gltype => 'gl', dir =>'GeneralLedger',        model => 'GLTransaction',  right => 'import_ap'  },
-  'draft' =>                   { gen => 0 ,gltype => '',   dir =>'Draft',                model => 'Draft',          right => 'xx'  },
-  'csv_customer' =>            { gen => 1 ,gltype => '',   dir =>'Reports',              model => 'Customer',       right => 'xx'  },
-  'csv_vendor'   =>            { gen => 1 ,gltype => '',   dir =>'Reports',              model => 'Vendor',         right => 'xx'  },
+  'sales_quotation'             => { gen => 1, gltype => '',   dir =>'SalesQuotation',       model => 'Order',          right => 'import_ar'  },
+  'sales_order'                 => { gen => 5, gltype => '',   dir =>'SalesOrder',           model => 'Order',          right => 'import_ar'  },
+  'sales_delivery_order'        => { gen => 1, gltype => '',   dir =>'SalesDeliveryOrder',   model => 'DeliveryOrder',  right => 'import_ar'  },
+  'invoice'                     => { gen => 1, gltype => 'ar', dir =>'SalesInvoice',         model => 'Invoice',        right => 'import_ar'  },
+  'invoice_for_advance_payment' => { gen => 1, gltype => 'ar', dir =>'SalesInvoice',         model => 'Invoice',        right => 'import_ar'  },
+  'final_invoice'               => { gen => 1, gltype => 'ar', dir =>'SalesInvoice',         model => 'Invoice',        right => 'import_ar'  },
+  'credit_note'                 => { gen => 1, gltype => '',   dir =>'CreditNote',           model => 'Invoice',        right => 'import_ar'  },
+  'request_quotation'           => { gen => 7, gltype => '',   dir =>'RequestForQuotation',  model => 'Order',          right => 'import_ap'  },
+  'purchase_order'              => { gen => 7, gltype => '',   dir =>'PurchaseOrder',        model => 'Order',          right => 'import_ap'  },
+  'purchase_delivery_order'     => { gen => 7, gltype => '',   dir =>'PurchaseDeliveryOrder',model => 'DeliveryOrder',  right => 'import_ap'  },
+  'purchase_invoice'            => { gen => 6, gltype => 'ap', dir =>'PurchaseInvoice',      model => 'PurchaseInvoice',right => 'import_ap'  },
+  'vendor'                      => { gen => 0, gltype => '',   dir =>'Vendor',               model => 'Vendor',         right => 'xx'         },
+  'customer'                    => { gen => 1, gltype => '',   dir =>'Customer',             model => 'Customer',       right => 'xx'         },
+  'project'                     => { gen => 0, gltype => '',   dir =>'Project',              model => 'Project',        right => 'xx'         },
+  'part'                        => { gen => 0, gltype => '',   dir =>'Part',                 model => 'Part',           right => 'xx'         },
+  'gl_transaction'              => { gen => 6, gltype => 'gl', dir =>'GeneralLedger',        model => 'GLTransaction',  right => 'import_ap'  },
+  'draft'                       => { gen => 0, gltype => '',   dir =>'Draft',                model => 'Draft',          right => 'xx'         },
+  'csv_customer'                => { gen => 1, gltype => '',   dir =>'Reports',              model => 'Customer',       right => 'xx'         },
+  'csv_vendor'                  => { gen => 1, gltype => '',   dir =>'Reports',              model => 'Vendor',         right => 'xx'         },
+  'shop_image'                  => { gen => 0, gltype => '',   dir =>'ShopImages',           model => 'Part',           right => 'xx'         },
+  'letter'                      => { gen => 7, gltype => '',   dir =>'Letter',               model => 'Letter',         right => 'sales_letter_edit | purchase_letter_edit' },
 );
 
 #--- 4 locale ---#
 sub action_list {
   my ($self) = @_;
 
-  my $isjson = 0;
-  $isjson = 1 if $::form->{json};
+  my $is_json = 0;
+  $is_json = 1 if $::form->{json};
 
-  $self->_do_list($isjson);
+  $self->_do_list($is_json);
 }
 
 sub action_ajax_importdialog {
   my $ids    = $::form->{ids};
   my $source = $::form->{source};
   my $path   = $::form->{path};
-  my @files = $self->_get_from_import($path);
+  my @files  = $self->_get_from_import($path);
   foreach my $filename (@{ $::form->{$ids} || [] }) {
-    my ($file,undef) = grep { $_->{name} eq $filename } @files;
+    my ($file, undef) = grep { $_->{name} eq $filename } @files;
     if ( $file ) {
-      my $obj = SL::File->save(object_id     => $self->object_id,
-                               object_type   => $self->object_type,
-                               mime_type     => 'application/pdf',
-                               source        => $source,
-                               file_type     => 'document',
-                               file_name     => $file->{filename},
-                               file_path     => $file->{path}
+      my $obj = SL::File->save(object_id   => $self->object_id,
+                               object_type => $self->object_type,
+                               mime_type   => 'application/pdf',
+                               source      => $source,
+                               file_type   => 'document',
+                               file_name   => $file->{filename},
+                               file_path   => $file->{path}
                              );
       unlink($file->{path}) if $obj;
     }
 
 sub action_ajax_delete {
   my ($self) = @_;
-  $self->_delete_all(DO_DELETE,$::locale->text('Following files are deleted:'));
+  $self->_delete_all(DO_DELETE, $::locale->text('Following files are deleted:'));
 }
 
 sub action_ajax_unimport {
   my ($self) = @_;
-  $self->_delete_all(DO_UNIMPORT,$::locale->text('Following files are unimported:'));
+  $self->_delete_all(DO_UNIMPORT, $::locale->text('Following files are unimported:'));
 }
 
 sub action_ajax_rename {
   my ($self) = @_;
-  my $file = SL::File->get(id => $::form->{id});
+  my ($id, $version) = split /_/, $::form->{id};
+  my $file = SL::File->get(id => $id);
   if ( ! $file ) {
-    $self->js->flash('error',$::locale->text('File not exists !'))->render();
+    $self->js->flash('error', $::locale->text('File not exists !'))->render();
     return;
   }
-  $main::lxdebug->message(LXDebug->DEBUG2(), "object_id=".$file->object_id." object_type=".$file->object_type." dbfile=".$file);
   my $sessionfile = $::form->{sessionfile};
-      $main::lxdebug->message(LXDebug->DEBUG2(), "sessionfile=".$sessionfile);
   if ( $sessionfile && -f $sessionfile ) {
-     $main::lxdebug->message(LXDebug->DEBUG2(), "file=".$file->file_name." to=".$::form->{to}." sessionfile=".$sessionfile);
     # new uploaded file
     if ( $::form->{to} eq $file->file_name ) {
       # no rename so use as new version
       $file->save_file($sessionfile);
-      $self->js->flash('warning',$::locale->text('File \'#1\' is used as new Version !',$file->file_name));
+      $self->js->flash('warning', $::locale->text('File \'#1\' is used as new Version !', $file->file_name));
 
     } else {
-      # new filename so it is a new file with same attributes as old file
+      # new filename, so it is a new file with the same attributes as the old file
       eval {
-        SL::File->save(object_id     => $file->object_id,
-                       object_type   => $file->object_type,
-                       mime_type     => $file->mime_type,
-                       source        => $file->source,
-                       file_type     => $file->file_type,
-                       file_name     => $::form->{to},
-                       file_path     => $sessionfile
+        SL::File->save(object_id   => $file->object_id,
+                       object_type => $file->object_type,
+                       mime_type   => $file->mime_type,
+                       source      => $file->source,
+                       file_type   => $file->file_type,
+                       file_name   => $::form->{to},
+                       file_path   => $sessionfile
                      );
         unlink($sessionfile);
         1;
 
   } else {
     # normal rename
-    my $res;
+    my $result;
 
     eval {
-      $res = $file->rename($::form->{to});
-      $main::lxdebug->message(LXDebug->DEBUG2(), "rename result=".$res);
+      $result = $file->rename($::form->{to});
       1;
     } or do {
       $self->js->flash(       'error', t8('internal error (see details)'))
       return;
     };
 
-    if ($res != SL::File::RENAME_OK) {
+    if ($result != SL::File::RENAME_OK) {
       $self->js->flash('error',
-                         $res == SL::File::RENAME_EXISTS ? $::locale->text('File still exists !')
-                       : $res == SL::File::RENAME_SAME   ? $::locale->text('Same Filename !')
-                       :                                   $::locale->text('File not exists !'))
+                         $result == SL::File::RENAME_EXISTS ? $::locale->text('File still exists !')
+                       : $result == SL::File::RENAME_SAME   ? $::locale->text('Same Filename !')
+                       :                                      $::locale->text('File not exists !'))
         ->render;
       return;
     }
   $self->{accept_types} = '';
   $self->{accept_types} = 'image/png,image/gif,image/jpeg,image/tiff,*png,*gif,*.jpg,*.tif' if $self->{file_type} eq 'image';
   $self->render('file/upload_dialog',
-                { layout          => 0
+                { layout => 0
                 },
   );
 }
   my ($self) = @_;
 
   my $source = 'uploaded';
-  $main::lxdebug->message(LXDebug->DEBUG2(), "file_upload UPLOAD=".$::form->{ATTACHMENTS}->{uploadfiles});
   my @existing;
   if ( $::form->{ATTACHMENTS}->{uploadfiles} ) {
     my @upfiles = @{ $::form->{ATTACHMENTS}->{uploadfiles} };
     foreach my $idx (0 .. scalar(@upfiles) - 1) {
       eval {
         my $fname = uri_unescape($upfiles[$idx]->{filename});
-        $main::lxdebug->message(LXDebug->DEBUG2(), "file_upload name=".$fname);
-        ## normalize and find basename
+        # normalize and find basename
         # first split with unix rules
         # after that split with windows rules
-        my ($volume,$directories,$basefile) = File::Spec::Unix->splitpath($fname);
-        ($volume,$directories,$basefile) = File::Spec::Win32->splitpath($basefile);
+        my ($volume, $directories, $basefile) = File::Spec::Unix->splitpath($fname);
+        ($volume, $directories, $basefile) = File::Spec::Win32->splitpath($basefile);
 
         # to find real mime_type by magic we must save the filedata
 
-        my $sess_fname = "file_upload_".$self->object_type."_".$self->object_id."_".$idx;
-        my $sfile     = SL::SessionFile->new($sess_fname, mode => 'w');
+        my $sess_fname = "file_upload_" . $self->object_type . "_" . $self->object_id . "_" . $idx;
+        my $sfile      = SL::SessionFile->new($sess_fname, mode => 'w');
 
         $sfile->fh->print(${$upfiles[$idx]->{data}});
         $sfile->fh->close;
         my $mime_type = File::MimeInfo::Magic::magic($sfile->file_name);
 
         if (! $mime_type) {
-          # if filename has the suffix "pdf", but is really no pdf set mimetype for no suffix
+          # if filename has the suffix "pdf", but isn't really a pdf, set mimetype for no suffix
           $mime_type = File::MimeInfo::Magic::mimetype($basefile);
           $mime_type = 'application/octet-stream' if $mime_type eq 'application/pdf' || !$mime_type;
         }
-        $main::lxdebug->message(LXDebug->DEBUG2(), "mime_type=".$mime_type);
         if ( $self->file_type eq 'image' && $self->file_probe_image_type($mime_type, $basefile)) {
           next;
         }
-        my ($existobj) = SL::File->get_all(object_id     => $self->object_id,
-                                        object_type   => $self->object_type,
-                                        mime_type     => $mime_type,
-                                        source        => $source,
-                                        file_type     => $self->file_type,
-                                        file_name     => $basefile,
+        my ($existobj) = SL::File->get_all(object_id   => $self->object_id,
+                                           object_type => $self->object_type,
+                                           mime_type   => $mime_type,
+                                           source      => $source,
+                                           file_type   => $self->file_type,
+                                           file_name   => $basefile,
                                       );
 
-        $main::lxdebug->message(LXDebug->DEBUG2(), "store1 exist=".$existobj);
         if ($existobj) {
-  $main::lxdebug->message(LXDebug->DEBUG2(), "id=".$existobj->id." sessionfile=". $sfile->file_name);
           push @existing, $existobj->id.'_'.$sfile->file_name;
         } else {
-          my $fileobj = SL::File->save(object_id     => $self->object_id,
-                                       object_type   => $self->object_type,
-                                       mime_type     => $mime_type,
-                                       source        => $source,
-                                       file_type     => $self->file_type,
-                                       file_name     => $basefile,
+          my $fileobj = SL::File->save(object_id        => $self->object_id,
+                                       object_type      => $self->object_type,
+                                       mime_type        => $mime_type,
+                                       source           => $source,
+                                       file_type        => $self->file_type,
+                                       file_name        => $basefile,
+                                       title            => $::form->{title},
+                                       description      => $::form->{description},
                                        ## two possibilities: what is better ? content or sessionfile ??
-                                       #file_contents => ${$upfiles[$idx]->{data}},
-                                       file_path     => $sfile->file_name
+                                       file_contents    => ${$upfiles[$idx]->{data}},
+                                       file_path        => $sfile->file_name
                                      );
-          $main::lxdebug->message(LXDebug->DEBUG2(), "obj=".$fileobj);
           unlink($sfile->file_name);
         }
         1;
 
 sub action_download {
   my ($self) = @_;
-  my ($id,$version) = split /_/, $::form->{id};
+
+  my $id      = $::form->{id};
+  my $version = $::form->{version};
+
   my $file = SL::File->get(id => $id );
   $file->version($version) if $version;
   my $ref  = $file->get_content;
   }
 }
 
+sub action_ajax_get_thumbnail {
+  my ($self) = @_;
+
+  my $id      = $::form->{file_id};
+  my $version = $::form->{file_version};
+  my $file    = SL::File->get(id => $id);
+
+  $file->version($version) if $version;
+
+  my $thumbnail = _create_thumbnail($file, $::form->{size});
+
+  my $overlay_selector  = '#enlarged_thumb_' . $id;
+  $overlay_selector    .= '_' . $version            if $version;
+  $self->js
+    ->attr($overlay_selector, 'src', 'data:' . $thumbnail->{thumbnail_img_content_type} . ';base64,' . MIME::Base64::encode_base64($thumbnail->{thumbnail_img_content}))
+    ->data($overlay_selector, 'is-overlay-loaded', '1')
+    ->render;
+}
+
+
 #
 # filters
 #
 sub check_object_params {
   my ($self) = @_;
 
-  my $id = ($::form->{object_id} // 0) * 1;
-  my $draftid = ($::form->{draft_id} // 0) * 1;
-  my $gldoc = 0;
-  my $type = undef;
+  my $id      = ($::form->{object_id} // 0) * 1;
+  my $draftid = ($::form->{draft_id}  // 0) * 1;
+  my $gldoc   = 0;
+  my $type    = undef;
 
   if ( $draftid == 0 && $id == 0 && $::form->{is_global} ) {
     $gldoc = 1;
-    $type = $::form->{object_type};
+    $type  = $::form->{object_type};
   }
   elsif ( $id == 0 ) {
-    $id = $::form->{draft_id};
+    $id   = $::form->{draft_id};
     $type = 'draft';
   } elsif ( $::form->{object_type} ) {
     $type = $::form->{object_type};
   }
-  die "No object type"     if ! $type;
-  die "No file type"       if ! $::form->{file_type};
-  die "Unkown object type" if ! $file_types{$type};
+  die "No object type"      unless $type;
+  die "No file type"        unless $::form->{file_type};
+  die "Unknown object type" unless $file_types{$type};
 
   $self->is_global($gldoc);
   $self->file_type($::form->{file_type});
   $self->object_id($id);
   $self->object_model($file_types{$type}->{model});
   $self->object_right($file_types{$type}->{right});
-  $main::lxdebug->message(LXDebug->DEBUG2(), "checked: object_id=".$self->object_id." object_type=".$self->object_type." is_global=".$self->is_global);
 
  # $::auth->assert($self->object_right);
 
 #
 
 sub _delete_all {
-  my ($self,$do_unimport,$infotext) = @_;
+  my ($self, $do_unimport, $infotext) = @_;
   my $files = '';
   my $ids = $::form->{ids};
   foreach my $id_version (@{ $::form->{$ids} || [] }) {
-    my ($id,$version) = split /_/, $id_version;
+    my ($id, $version) = split /_/, $id_version;
     my $dbfile = SL::File->get(id => $id);
-    $dbfile->version($version) if $dbfile && $version;
-    if ( $dbfile && $dbfile->delete ) {
-      $files .= ' '.$dbfile->file_name;
+    if ( $dbfile ) {
+      if ( $version ) {
+        $dbfile->version($version);
+        $files .= ' ' . $dbfile->file_name if $dbfile->delete_version;
+      } else {
+        $files .= ' ' . $dbfile->file_name if $dbfile->delete;
+      }
     }
   }
-  $self->js->flash('info',$infotext.$files) if $files;
+  $self->js->flash('info', $infotext . $files) if $files;
   $self->_do_list(1);
 }
 
 sub _do_list {
-  my ($self,$json) = @_;
+  my ($self, $json) = @_;
+
   my @files;
-  $main::lxdebug->message(LXDebug->DEBUG2(), "do_list: object_id=".$self->object_id." object_type=".$self->object_type." file_type=".$self->file_type." json=".$json);
+  my @object_types = ($self->object_type);
   if ( $self->file_type eq 'document' ) {
-    @files   = SL::File->get_all_versions(object_id   => $self->object_id  ,
-                                          object_type => $self->object_type,
-                                          file_type   => $self->file_type  );
-
-    $main::lxdebug->message(LXDebug->DEBUG2(), "cnt1=".scalar(@files));
-  }
-  elsif ( $self->file_type eq 'attachment' ||  $self->file_type eq 'image' ) {
-    @files   = SL::File->get_all(object_id   => $self->object_id  ,
-                                 object_type => $self->object_type,
-                                 file_type   => $self->file_type  );
-    $main::lxdebug->message(LXDebug->DEBUG2(), "cnt2=".scalar(@files));
+    push @object_types, qw(dunning1 dunning2 dunning3 dunning_invoice dunning_orig_invoice) if $self->object_type eq 'invoice'; # hardcoded object types?
   }
+  @files = SL::File->get_all_versions(object_id   => $self->object_id,
+                                      object_type => \@object_types,
+                                      file_type   => $self->file_type,
+                                     );
+
   $self->files(\@files);
-  $self->_mk_render('file/list',1,0,$json);
+
+  $_->{thumbnail}     = _create_thumbnail($_)                     for @files;
+  $_->{version_count} = SL::File->get_version_count(id => $_->id) for @files;
+
+  if($self->object_type eq 'shop_image'){
+    $self->js
+      ->run('kivi.ShopPart.show_images', $self->object_id)
+      ->render();
+  }else{
+    $self->_mk_render('file/list', 1, 0, $json);
+  }
 }
 
 sub _get_from_import {
-  my ($self,$path) = @_;
+  my ($self, $path) = @_;
   my @foundfiles ;
 
-  $main::lxdebug->message(LXDebug->DEBUG2(), "import path=".$path);
   my $language = $::lx_office_conf{system}->{language};
   my $timezone = $::locale->get_local_time_zone()->name;
   if (opendir my $dir, $path) {
-    my @files = ( readdir $dir);
+    my @files = (readdir $dir);
     foreach my $file ( @files) {
       next if (($file eq '.') || ($file eq '..'));
       $file = Encode::decode('utf-8', $file);
-      $main::lxdebug->message(LXDebug->DEBUG2(), "file=".$file);
 
-      next if( -d "$path/$file");
+      next if ( -d "$path/$file" );
 
       my $tmppath = File::Spec->catfile( $path, $file );
-      $main::lxdebug->message(LXDebug->DEBUG2(), "tmppath=".$tmppath." file=".$file);
-      next if( ! -f $tmppath);
+      next if( ! -f $tmppath );
 
       my $st = stat($tmppath);
-      my $dt = DateTime->from_epoch( epoch => $st->mtime, time_zone => $timezone, locale => $language);
-      my $sname = $main::locale->quote_special_chars('HTML',$file);
-      push @foundfiles , {
+      my $dt = DateTime->from_epoch( epoch => $st->mtime, time_zone => $timezone, locale => $language );
+      my $sname = $main::locale->quote_special_chars('HTML', $file);
+      push @foundfiles, {
         'name'     => $file,
         'filename' => $sname,
         'path'     => $tmppath,
         'mtime'    => $st->mtime,
-        'date'     => $dt->dmy('.')." ".$dt->hms,
+        'date'     => $dt->dmy('.') . " " . $dt->hms,
       };
 
     }
+    closedir($dir);
+
+  } else {
+    $::lxdebug->message(LXDebug::WARN(), "SL::File::_get_from_import opendir failed to open dir " . $path);
   }
-  $main::lxdebug->message(LXDebug->DEBUG2(), "return ".scalar(@foundfiles)." files");
+
   return @foundfiles;
 }
 
 sub _mk_render {
-  my ($self,$template,$edit,$scanner,$json) = @_;
+  my ($self, $template, $edit, $scanner, $json) = @_;
   my $err;
   eval {
-    ##TODO  here a configurable code must be implemented
+    ##TODO make code configurable
 
     my $title;
-    $main::lxdebug->message(LXDebug->DEBUG2(), "mk_render: object_id=".$self->object_id." object_type=".$self->object_type.
-                              " file_type=".$self->file_type." json=".$json." filecount=".scalar(@{ $self->files })." is_global=".$self->is_global);
     my @sources = $self->_get_sources();
     foreach my $source ( @sources ) {
-      $main::lxdebug->message(LXDebug->DEBUG2(), "mk_render: source name=".$source->{name});
       @{$source->{files}} = grep { $_->source eq $source->{name}} @{ $self->files };
     }
     if ( $self->file_type eq 'document' ) {
 
     my $output         = SL::Presenter->get->render(
       $template,
-      title             => $title,
-      SOURCES           => \@sources,
-      edit_attachments  => $edit,
-      object_type       => $self->object_type,
-      object_id         => $self->object_id,
-      file_type         => $self->file_type,
-      is_global         => $self->is_global,
-      json              => $json,
+      title            => $title,
+      SOURCES          => \@sources,
+      edit_attachments => $edit,
+      object_type      => $self->object_type,
+      object_id        => $self->object_id,
+      file_type        => $self->file_type,
+      is_global        => $self->is_global,
+      json             => $json,
     );
     if ( $json ) {
       $self->js->html('#'.$self->file_type.'_list_'.$self->object_type, $output);
       if ( $self->existing && scalar(@{$self->existing}) > 0) {
         my $first = shift @{$self->existing};
-        my ($first_id,$sfile) = split('_',$first,2);
-        #$main::lxdebug->message(LXDebug->DEBUG2(), "id=".$first_id." sessionfile=". $sfile);
+        my ($first_id, $sfile) = split('_', $first, 2);
         my $file = SL::File->get(id => $first_id );
-        $self->js->run('kivi.File.askForRename',$first_id,$file->file_name,$sfile,join (',', @{$self->existing}), $self->is_global);
+        $self->js->run('kivi.File.askForRename', $first_id, $file->file_type, $file->file_name, $sfile, join (',', @{$self->existing}), $self->is_global);
       }
       $self->js->render();
     } else {
 sub _get_sources {
   my ($self) = @_;
   my @sources;
-  $main::lxdebug->message(LXDebug->DEBUG2(), "get_sources file_type=". $self->file_type);
   if ( $self->file_type eq 'document' ) {
-    ##TODO statt gen neue attribute in filetypes :
+    # TODO statt gen neue attribute in filetypes :
+    if (($file_types{$self->object_type}->{gen}*1 & 4)==4) {
+      # bit 3 is set => means upload
+      my $source = {
+        'name'         => 'uploaded',
+        'title'        => $main::locale->text('uploaded Documents'),
+        'chk_action'   => 'uploaded_documents_delete',
+        'chk_title'    => $main::locale->text('Delete Documents'),
+        'chkall_title' => $main::locale->text('Delete all'),
+        'file_title'   => $main::locale->text('filename'),
+        'confirm_text' => $main::locale->text('delete'),
+        'can_rename'   => 1,
+        'are_existing' => $self->existing ? 1 : 0,
+        'rename_title' => $main::locale->text('Rename Attachments'),
+        'can_upload'   => 1,
+        'can_delete'   => 1,
+        'upload_title' => $main::locale->text('Upload Documents'),
+        'done_text'    => $main::locale->text('deleted')
+      };
+      push @sources , $source;
+    }
+
     if (($file_types{$self->object_type}->{gen}*1 & 1)==1) {
       my $gendata = {
         'name'         => 'created',
         'chkall_title' => $main::locale->text('Delete all'),
         'file_title'   => $main::locale->text('filename'),
         'confirm_text' => $main::locale->text('delete'),
-        'can_rename'   => 1,
+        'can_delete'   => $::instance_conf->get_doc_delete_printfiles,
+        'can_rename'   => $::instance_conf->get_doc_delete_printfiles,
         'rename_title' => $main::locale->text('Rename Documents'),
         'done_text'    => $main::locale->text('deleted')
       };
       push @sources , $gendata;
     }
+
     if (($file_types{$self->object_type}->{gen}*1 & 2)==2) {
       my @others =  SL::File->get_other_sources();
-      $main::lxdebug->message(LXDebug->DEBUG2(), "other cnt=". scalar(@others));
       foreach my $scanner_or_mailrx (@others) {
         my $other = {
           'name'         => $scanner_or_mailrx->{name},
-          'title'        => $main::locale->text('from \'#1\' imported Files',$scanner_or_mailrx->{description}),
+          'title'        => $main::locale->text('from \'#1\' imported Files', $scanner_or_mailrx->{description}),
           'chk_action'   => $scanner_or_mailrx->{name}.'_unimport',
           'chk_title'    => $main::locale->text('Unimport documents'),
           'chkall_title' => $main::locale->text('Unimport all'),
           'can_rename'   => 1,
           'rename_title' => $main::locale->text('Rename Documents'),
           'can_import'   => 1,
-          'import_title' => $main::locale->text('Add Document from \'#1\'',$scanner_or_mailrx->{name}),
+          'can_delete'   => 0,
+          'import_title' => $main::locale->text('Add Document from \'#1\'', $scanner_or_mailrx->{name}),
           'path'         => $scanner_or_mailrx->{directory},
           'done_text'    => $main::locale->text('unimported')
         };
       'are_existing' => $self->existing ? 1 : 0,
       'rename_title' => $main::locale->text('Rename Attachments'),
       'can_upload'   => 1,
+      'can_delete'   => 1,
       'upload_title' => $main::locale->text('Upload Attachments'),
       'done_text'    => $main::locale->text('deleted')
     };
       'are_existing' => $self->existing ? 1 : 0,
       'rename_title' => $main::locale->text('Rename Images'),
       'can_upload'   => 1,
+      'can_delete'   => 1,
       'upload_title' => $main::locale->text('Upload Images'),
       'done_text'    => $main::locale->text('deleted')
     };
     push @sources , $attdata;
   }
-  $main::lxdebug->message(LXDebug->DEBUG2(), "get_sources count=".scalar(@sources));
   return @sources;
 }
 
+# ignores all errros
+# todo: cache thumbs?
+sub _create_thumbnail {
+  my ($file, $size) = @_;
+
+  $size //= 64;
+
+  my $filename;
+  if (!eval { $filename = $file->get_file(); 1; }) {
+    $::lxdebug->message(LXDebug::WARN(), "SL::File::_create_thumbnail get_file failed: " . $EVAL_ERROR);
+    return;
+  }
+
+  # Workaround for pfds which are not handled by file_probe_type.
+  # Maybe use mime info stored in db?
+  my $mime_type = File::MimeInfo::Magic::magic($filename);
+  if ($mime_type =~ m{pdf}) {
+    $filename = _convert_pdf_to_png($filename, size => $size);
+  }
+  return if !$filename;
+
+  my $content;
+  if (!eval { $content = slurp $filename; 1; }) {
+    $::lxdebug->message(LXDebug::WARN(), "SL::File::_create_thumbnail slurp failed: " . $EVAL_ERROR);
+    return;
+  }
+
+  my $ret;
+  if (!eval { $ret = file_probe_type($content, size => $size); 1; }) {
+    $::lxdebug->message(LXDebug::WARN(), "SL::File::_create_thumbnail file_probe_type failed: " . $EVAL_ERROR);
+    return;
+  }
+
+  # file_probe_type returns a hash ref with thumbnail info and content
+  # or an error message
+  if ('HASH' ne ref $ret) {
+    $::lxdebug->message(LXDebug::WARN(), "SL::File::_create_thumbnail file_probe_type returned an error: " . $ret);
+    return;
+  }
+
+  return $ret;
+}
+
+sub _convert_pdf_to_png {
+  my ($filename, %params) = @_;
+
+  my $size    = $params{size} // 64;
+  my $sfile   = SL::SessionFile::Random->new();
+  unless (-f $filename) {
+    $::lxdebug->message(LXDebug::WARN(), "_convert_pdf_to_png failed, no file found: $filename");
+    return;
+  }
+  # quotemeta for storno case "storno\ zu\ 1020" *nix only
+  my $command = 'pdftoppm -singlefile -scale-to ' . $size . ' -png' . ' ' . quotemeta($filename) . ' ' . $sfile->file_name;
+
+  if (system($command) == -1) {
+    $::lxdebug->message(LXDebug::WARN(), "SL::File::_convert_pdf_to_png: system call failed: " . $ERRNO);
+    return;
+  }
+  if ($CHILD_ERROR) {
+    $::lxdebug->message(LXDebug::WARN(), "SL::File::_convert_pdf_to_png: pdftoppm failed with error code: " . ($CHILD_ERROR >> 8));
+    $::lxdebug->message(LXDebug::WARN(), "SL::File::_convert_pdf_to_png: File: $filename");
+    return;
+  }
+
+  return $sfile->file_name . '.png';
+}
+
 1;
 
 __END__
 
 SL::Controller::File - Controller for managing files
 
-
 =head1 SYNOPSIS
 
-=begin text
-
-    # The Controller is called direct from the webpages
-
+The Controller is called directly from the webpages
 
     <a href="controller.pl?action=File/list&file_type=document\
        &object_type=[% HTML.escape(type) %]&object_id=[% HTML.url(id) %]">
 
 
-    # or indirect via javascript functions from js/kivi.File.js
-
+or indirectly via javascript functions from js/kivi.File.js
 
     kivi.popup_dialog({ url:     'controller.pl',
                         data:    { action     : 'File/ajax_upload',
                                  }
                            ...
 
-=end text
-
-
 =head1 DESCRIPTION
 
 This is a controller for handling files in a storage independent way.
 
 =item C<form.ids>
 
-The ids of the files to unimport. Only this files are unimported not all versions of a file if the exists
+The ids of the files to unimport. Only these files are unimported not all versions of a file if the exists
 
 =back
 
 
 One file can be renamed. There can be some checks if the same filename still exists at one object.
 
-
 =head1 AUTHOR
 
 Martin Helmling E<lt>martin.helmling@opendynamic.deE<gt>