com.sc2bc.upload = {
    init: function (options) {
        this.options = options
    },
    options: {}
}

$(function () {
    if (!/(Chrome\/(1[1-9]|[1-9][0-9]+)|Firefox\/([4-9]|[1][0-9]+))/.test(navigator.userAgent)) {
        // from this browser we would probably spread creep
        return;
    }
    if (typeof XMLHttpRequest.prototype.sendAsBinary != "function") {
        XMLHttpRequest.prototype.sendAsBinary = function(datastr) {
            function byteValue(x) {
                return x.charCodeAt(0) & 0xff;
            }
            var ords = Array.prototype.map.call(datastr, byteValue);
            var ui8a = new Uint8Array(ords);
            this.send(ui8a.buffer);
        }
    }
    var ticket = false
    var opts = {
        fileParameterName: 'file'
    }
    var queue = [],
        total = 0
    var replayExt = /\.SC2Replay$/i,
        archiveExt = /\.zip/i
    var icon = '<span class="icon-container"><span class="icon"></span></span>';
    var form = $('form.upload'),
        file = form.find('input[name=file]'),
        fileLabel = file.parents('label'),
        browse = $('<div class="buttons buttons-browse"><a href="#browse" class="button button-browse button-submit"><span class="value">' + _('Browse\u2026') + '</span></a></div>'),
        upload = form.find('input[name=upload]'),
        container = $('<div class="buttons">'),
        linkUpload = $('<a href="#upload" class="button button-create button-upload">' + _('Upload') + '</a>')
    linkUpload.insertBefore(upload)
    upload.remove()
    upload = linkUpload
    container.insertBefore(upload)
    var privateInput = form.find('input[name=private]').parent('label')
    if (privateInput.length) {
        container.append(privateInput.remove())
    }
    container.append(upload)
    browse.insertBefore(container)
    fileLabel.addClass('mini')
    updateControls()
    browse.click(function (event) {
        event.preventDefault()
        file.click()
    })
    upload.click(function (event) {
        event.preventDefault()
        startUpload()
    })
    file.attr('multiple', 'multiple')
        .change(function (event) {
        if (!this.files) {
            browse.find('value').html(_('Browse\u2026'))
            return
        }
        browse.find('value').html(_('Add more\u2026'))
        var files = this.files
        for (var i = 0; i < files.length; i++) {
            addToQueue(files[i])
        }
        updateControls()
    })
    function updateQueueStyles() {
        var container  = $('#queue'),
            formContainer = form.parents('.form')
        if (!queue.length) {
            container.remove()
            return;
        } else {
            if (!container.length) {
                container = $('<div id=queue class="upload-queue"><div class=items></div></div>')
                container.insertAfter(form.find('.buttons-browse'))
            }
        }
    }
    function addToQueue(file)
    {
        var name = file.name
        var type = 'unknown';
        if (replayExt.test(name)) {
            type = 'replay'
        } else if (archiveExt.test(name)) {
            type = 'archive'
        }
        var item = {
            file: file,
            name: name,
            size: file.size,
            state: type == 'replay' ? 'new' : 'unknown',
            type: type
        }
        queue.push(item)

        updateQueueStyles()
        var container = $('#queue .items'),
            name = file.name.replace(/.SC2Replay/i, '')
            fileContainer = $('<div class=item><span class=name>' + name + '</span> <span class=size>' + mishak.fileSizeToHuman(file.size) + '</span></div>')
            if (type == 'replay') {
                fileContainer.append('<span class=progress><span class=bar></span></span>')
            } else {
                fileContainer.addClass('unknown')
            }
        
        fileContainer.appendTo(container)
        item.container = fileContainer
    }
    function updateControls()
    {
        if (queue.length) {
            updateTotals();
        }
    }
    function updateTotals()
    {
        var archives = 0,
            unknown = 0,
            replays = 0,
            size = 0
        for (var i = 0; i < queue.length; i++) {
            var item = queue[i]
            size += item.size
            switch (item.type) {
                case 'replay':
                    replays++
                    break
                case 'archive':
                    archives++
                    break
                default:
                    unknown++
                    break
            }
        }
        var parts = []
        if (replays) {
            parts.push(_('%d replays', replays))
        }
        if (archives) {
            parts.push(_('%d archives', archives))
        }
        if (unknown) {
            parts.push(_('%d unknown', unknown))
        }
        var value = parts.pop()
        if (parts.length) {
            value = parts.join(', ') + ' ' + _('and') + ' ' + value
        }
        var container = $('#queue .items')
        container.find('.total').remove()
        container.append('<div class="item total"><span class=name>' + value + '</span> <span class=progress><span class=bar></span></span> <span class=size>' + mishak.fileSizeToHuman(size) + '</span></div>')
    }
    function getTotalSize()
    {
        var size = 0
        for (var i = 0; i < queue.length; i++) {
            size += queue[i].size
        }
        return size
    }
    function startUpload()
    {
        form.find('input[name=private]').parent('label').hide()
        form.find('.button-browse, .button-upload').hide()
        var cancel = form.find('.button-cancel')
        if (cancel.length) {
            cancel.show()
            return
        } else {
            cancel = $('<a href="#cancel" class="button-cancel button button-destructive">' + icon + _('Cancel') + '</a>')
            cancel.click(function (event) {
                event.preventDefault()
                cancelUpload()
            })
            cancel.insertBefore(upload)
        }
        uploadFile()
    }
    function cancelUpload()
    {
        fileAbortUpload()
        form.find('input[name=private]').parent('label').show()
        form.find('.button-browse, .button-upload').show()
        form.find('.button-cancel').hide()
    }
    function fileAbortUpload()
    {
        for (var i = 0; i < queue.length; i++) {
            var item = queue[i]
            switch (item.state) {
                case 'reading':
                case 'uploading':
                    if (item.reader) {
                        item.reader.abort()
                    }
                    if (item.request) {
                        item.request.abort()
                    }
                    item.state = 'aborted'
                    running--
                    break
            }
        }
    }
    function fileRead(item)
    {
        item.state = 'reading'
        var reader = new FileReader()
        item.reader = reader
        reader.file = item.file
        reader.onloadend = function (event) {
            fileUpload(item)
        }
        reader.readAsBinaryString(item.file);
    }
    function getBoundary()
    {
        return '------multipartformboundary' + (new Date).getTime();
    }
    function getRequestBody(name, contents, boundary)
    {
		var dashdash = '--',
			crlf = '\r\n',
			result = '';

        var data = {}
        if ($('input[name=private]').is(':checked')) {
            data['private'] = 'on'
        }
        if (ticket) {
            data.ticket = ticket
        }
		$.each(data, function(i, val) {
	    	if (typeof val === 'function') val = val();
			result += dashdash;
			result += boundary;
			result += crlf;
			result += 'Content-Disposition: form-data; name="'+i+'"';
			result += crlf;
			result += crlf;
			result += val;
			result += crlf;
		});
		
		result += dashdash;
		result += boundary;
		result += crlf;
		result += 'Content-Disposition: form-data; name="' + opts.fileParameterName + '"';
		result += '; filename="' + name + '"';
		result += crlf;
		
		result += 'Content-Type: application/octet-stream';
		result += crlf;
		result += crlf; 
		
		result += contents;
		result += crlf;
        
		result += dashdash;
		result += boundary;
		result += dashdash;
		result += crlf;
		return result;
    }
    var limit = 2
    var running = 0
    var update = []
    function fileUpload(item)
    {
        var request = new XMLHttpRequest()
        item.request = request
        item.container.addClass('uploading')
        var boundary = getBoundary()
        var contents = getRequestBody(item.name, item.reader.result, boundary)
        if (request.upload) {
            request.upload.onprogress = function (event) {
                item.container.find('.bar').css('width', event.loaded / event.total * 100 + '%')
            }
        }

        request.open('POST', com.sc2bc.upload.options.uploadUri, true);
        request.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' 
            + boundary);
        request.onload = function (event) {
            var response = $.parseJSON(request.response)
            item.container.find('.progress .bar').css('width', '100%')
            item.state = 'uploaded'
            item.url = response.url
            item.update = response.update
            item.id = response.id
            var name = item.container.find('.name')
            name.html('<a href="' + item.url + '">' + name.html() + '</a>')
            item.container.removeClass('uploading').addClass('complete')
            running--
            if (!update.length) {
                update.push(item)
                updateFile()
            }
            if (!running) {
                uploadFinished()
            } else {
                uploadFile()
            }
        }
        request.sendAsBinary(contents);  
    }
    function getFilesToUploadCount()
    {
        var total = 0
        for (var i = 0; i < queue.length; i++) {
            switch (queue[i].state) {
                case 'new':
                case 'aborted':
                    total++
            }
        }
        return total
    }
    function uploadFile()
    {
        if (limit && running >= limit) {
            return;
        }
        var filesToUploadCount = getFilesToUploadCount()
        if (!filesToUploadCount) {
            uploadFinished()
            return
        }
        if (filesToUploadCount > 1 && !ticket) {
            $.get(com.sc2bc.upload.options.ticketUri, null, function (data, status) {
                ticket = data.ticket
                uploadFile()
            }, 'json')
            return
        }
        for (var i = 0; i < queue.length; i++) {
            switch (queue[i].state) {
                case 'uploaded':
                case 'updated':
                    continue
                case 'new':
                case 'aborted':
                    running++
                    fileRead(queue[i])
                    uploadFile()
                    return
            }
        }
    }
    function uploadFinished()
    {
        form.find('input[name=private]').parent('label').show()
        form.find('.button-browse, .button-upload').show()
        form.find('.button-cancel').hide()
    }
    function updateFile()
    {
        var item = update.shift()
        if (!item) {
            return;
        }
        $.get(item.update, null, function () {
            updateFile()
        })
    }
    var dropzone = $('<div class="drop-zone"><div class="drop-target"></div><div class="drop-message"></div></div>'),
        dropzoneMessage = dropzone.find('.drop-message'),
        dropzoneTarget = dropzone.find('.drop-target')
    form.prepend(dropzone)
    dropzoneMessage.text(_('Drag replays here!'))
    $(document).bind('dragenter', function (event) {
        dropzoneMessage.text(_('Drag replays here!'))
        dropzone.show()
        event.stopPropagation()
        event.preventDefault()
    }).bind('dragexit', function (event) {
        dropzone.hide()
        event.stopPropagation()
        event.preventDefault()
    }).bind('dragover', function (event) {
        dropzoneMessage.text(_('Drag replays here!'))
        dropzone.removeClass('hover')
        event.stopPropagation()
        event.preventDefault()
    })
    dropzoneTarget.bind('dragover', function (event) {
        dropzoneMessage.text(_('They smell awesome!'))
        dropzone.addClass('hover')
        event.stopPropagation()
        event.preventDefault()
    })
    dropzoneTarget.bind('drop', function (event) {
        if (event.originalEvent.dataTransfer.files.length) {
            dropzoneMessage.text(_('Tasting victory\u2026'))
            var files = event.originalEvent.dataTransfer.files
            for (var i = 0; i < files.length; i++) {
                addToQueue(files[i])
            }
            updateControls()
            event.stopPropagation()
            event.preventDefault()
        }
        dropzoneMessage.text(_('Yummy replays here!'))
        dropzone.removeClass('hover')
    })
})

