our $VERSION = '0.02';

=head1 NAME

HTTP::Upload::FlowJs::Examples - examples for HTTP::Upload::FlowJs

=head1 Pure PSGI example

This is a verbose example that assumes a PSGI / Plack environment
and some helper routines to handle the payload of POST parameters.

=head2 ASSUMPTIONS

It is assumed in the below code that your HTTP framework implements some
routines to retrieve information about the current request:

  sub params() {
      # return request parameters, both GET and POST parameters
      # as a hash reference
  }
  
  sub upload {
      # return something like a file system object to retrieve the content
      # of a file upload parameter
  }

=head2 SETUP

  use HTTP::Upload::FlowJs;

  my @parameter_names = (
    'file',                 # The name of the file
    'flowChunkNumber',      # The index of the chunk in the current upload.
                            # First chunk is 1 (no base-0 counting here).
    'flowTotalChunks',      # The total number of chunks.
    'flowCurrentChunkSize', # Current chunk size
    'flowChunkSize',        # The general chunk size. Using this value and
                            # flowTotalSize you can calculate the total number of
                            # chunks. Please note that the size of the data received in
                            # the HTTP might be lower than flowChunkSize of this for
                            # the last chunk for a file.
    'flowTotalSize',        #  The total file size.
    'flowIdentifier',       # A unique identifier for the file contained in the request.
    'flowFilename',         # The original file name (since a bug in Firefox results in
                            # the file name not being transmitted in chunk
                            # multipart posts).
    'flowRelativePath',     # The file's relative path when selecting a directory
                            # (defaults to file name in all browsers except Chrome).
  );
  
  my $uploads = '/tmp/flowjs_uploads/';
  my $flowjs = HTTP::Upload::FlowJs->new(
      incomingDirectory => $uploads,
      allowedContentType => sub { $_[0] =~ m!^image/! },
      parameter_names => \@parameter_names, # to override the default names
  );
  
=head2 POST handler

Your handler for POST requests is where you have to validate and store a
received chunk. This is also where you determine whether a file was received
completely and hand it off for further processing.

  sub POST_upload {
    my $params = params();

    my %info;
    @info{ @parameter_names } = @{$params}{@parameter_names};
    $info{ localChunkSize } = -s $params{ file };
    # or however you get the size of the uploaded chunk

    # you might want to set this so users don't clobber each others upload
    my $session_id = '';
    my @invalid = $flowjs->validateRequest( 'POST', \%info, $session_id );
    if( @invalid ) {
        warn 'Invalid flow.js upload request:';
        warn $_ for @invalid;
        return [500,[],["Invalid request"]];
        return;
    };

    if( $flowjs->disallowedContentType( \%info, $session_id )) {
        # We can determine the content type, and it's not an image
        return [415,[],["File type disallowed"]];
    };

    my $chunkname = $flowjs->chunkName( \%info, undef );

    # Save or copy the uploaded file
    upload('file')->copy_to($chunkname);

    # Now check if we have received all chunks of the file
    if( $flowjs->uploadComplete( \%info, undef )) {
        # Combine all chunks to final name

        my $digest = Digest::SHA256->new();

        my( $content_type, $ext ) = $flowjs->sniffContentType();
        my $final_name = "file1.$ext";
        open( my $fh, '>', $final_name )
            or die $!;
        binmode $fh;

        my( $ok, @unlink_chunks )
            = $flowjs->combineChunks( \%info, undef, $fh, $digest );
        unlink @unlink_chunks;

        # Notify backend that a file arrived
        print sprintf "File '%s' upload complete\n", $final_name;
    };

    # Signal OK
    return [200,[],[]]
  };

=head2 GET handler

The GET handler is used by the Javascript code to retrieve information about
whether a chunk already has been uploaded or not.
  
  sub GET_upload {
    my $params = params();
    my %info;
    @info{ @parameter_names} = @{$params}{@parameter_names};
    my $flowjs = HTTP::Upload::FlowJs->new(
        incomingDirectory => $uploads,
        allowedContentType => sub { $_[0] =~ m!^image/! },
    );

    my @invalid = $flowjs->validateRequest( 'GET', \%info, session->{connid} );
    if( @invalid ) {
        warn 'Invalid flow.js upload request:';
        warn $_ for @invalid;
        return [500, [], [] ];

    } elsif( $flowjs->disallowedContentType( \%info, $session_id)) {
        # We can determine the content type, and it's not an image
        return [415,[],["File type disallowed"]];

    } else {
        my( $status, @messages )
            = $flowjs->chunkOK( $uploads, \%info, $session_id );
        if( $status != 500 ) {
            # 200 or 416
            return [$status, [], [] ];
        } else {
            warn $_ for @messages;
            return [$status, [], [] ];
        };
    };
  };

=cut

1;