# Copyright: 2013 Bastian Blank <bastian@waldi.eu.org>
# License: BSD 2-clause, see LICENSE for details.

import os

from flask import abort, current_app, jsonify, redirect, request, url_for
from flask.views import MethodView

from ..utils.html import ContentRange
from ..utils.name import ItemName
from . import blueprint


class Upload(object):
    @staticmethod
    def upload(item, f, size_input, offset=0):
        """
        Copy data from temp file into storage.
        """
        read_length = 16*1024
        size_written = 0

        while True:
            if size_input is not None:
                read_length = min(read_length, size_input)
            if size_input == 0:
                break

            buf = f.read(read_length)
            if not buf:
                break

            item.data.write(buf, offset + size_written)

            len_buf = len(buf)
            size_written += len_buf
            if size_input is not None:
                size_input -= len_buf

        return size_written


class UploadView(MethodView):
    def post(self):
        f = request.files['file']
        if not f:
            raise NotImplementedError

        try:
            if ContentRange.from_request():
                abort(416)
        except RuntimeError:
            abort(400)

        name = ItemName.create()

        # Get size of temporary file
        f.seek(0, os.SEEK_END)
        size = f.tell()
        f.seek(0)

        with current_app.storage.create(name, size) as item:
            Upload.upload(item, f, size)

            # Save meta-data
            item.meta['filename'] = f.filename
            item.meta['size'] = size
#            item.meta['type'] = data_type

        return redirect(url_for('bepasty.display', name=name))


class UploadNewView(MethodView):
    def post(self):
        data = request.get_json()
        data_filename = data['filename']
        data_size = data['size']
#        #data_type = data['type']

        name = ItemName.create()

        with current_app.storage.create(name, data_size) as item:
            # Save meta-data
            item.meta['filename'] = data_filename
            item.meta['size'] = data_size
#            item.meta['type'] = data_type

            return jsonify({'url': url_for('bepasty.upload_continue', name=name)})


class UploadContinueView(MethodView):
    def post(self, name):
        f = request.files['file']
        if not f:
            raise NotImplementedError

        try:
            content_range = ContentRange.from_request()
        except RuntimeError:
            abort(400)

        name = ItemName.parse(name)

        with current_app.storage.openwrite(name) as item:
            if content_range:
                Upload.upload(item, f, content_range.size, content_range.begin)
            else:
                # Get size of temporary file
                f.seek(0, os.SEEK_END)
                size = f.tell()
                f.seek(0)

                Upload.upload(item, f, size)

            return jsonify({'files': [{
                    'filename': item.meta['filename'],
                    'size': item.meta['size'],
                    'url': url_for('bepasty.display', name=name),
            }]})


blueprint.add_url_rule('/+upload', view_func=UploadView.as_view('upload'))
blueprint.add_url_rule('/+upload/new', view_func=UploadNewView.as_view('upload_new'))
blueprint.add_url_rule('/+upload/<name>', view_func=UploadContinueView.as_view('upload_continue'))

@@ -556,51 +556,8 @@
 ue:%0A
-            if size_input is not None:%0A    
     
@@ -875,51 +875,8 @@
 buf%0A
-            if size_input is not None:%0A    
     
@@ -1069,32 +1069,82 @@
 plementedError%0A%0A
+        # Check Content-Range, disallow its usage%0A
         try:%0A   
@@ -1276,32 +1276,154 @@
     
-name = ItemName.create()
+# Check Content-Type, default to application/octet-stream%0A        content_type = request.headers.get('Content-Type') or 'application/octet-stream'
 %0A%0A  
@@ -1523,32 +1523,92 @@
      f.seek(0)%0A%0A
+        # Create new name%0A        name = ItemName.create()%0A%0A
         with cur
@@ -1803,25 +1803,24 @@
 ze'%5D = size%0A
-#
             
@@ -1831,36 +1831,39 @@
 .meta%5B'type'%5D = 
-data
+content
 _type%0A%0A        r
@@ -2079,25 +2079,24 @@
 'size'%5D%0A
-#
         
 #data_ty
@@ -2087,17 +2087,16 @@
         
-#
 data_typ
@@ -2113,16 +2113,42 @@
 type'%5D%0A%0A
+        # Create new name%0A
         
@@ -2360,17 +2360,16 @@
 ta_size%0A
-#
         
@@ -2635,32 +2635,62 @@
 plementedError%0A%0A
+        # Check Content-Range%0A
         try:%0A   
@@ -2787,32 +2787,53 @@
     abort(400)%0A%0A
+        # Parse name%0A
         name = I

Handle type during upload