var cloud = (function(cloud) {
    function Model() {
        //alias for this
        var self = this;
        var uploadURLRequestInProgress = false;
        //currently displayed files
        self.files = ko.observableArray();
        //false, if you are in /
        self.notInRoot = ko.observable(false);
        //defalut path to display
        self.currentPath = ko.observable('/');
        //default upload url (invalid)
        self.uploadURL = ko.observable('/');
        self.newFolderName = ko.observable();
        self.uploadProgress = ko.observable('0%');
        self.quota = {
            rawUsed: ko.observable(0),
            rawSoft: ko.observable(0),
            rawHard: ko.observable(0)
        };
        self.quota.used = ko.computed(function() {
            return cloud.convert(self.quota.rawUsed(), 1);
        });
        self.quota.hard = ko.computed(function() {
            return cloud.convert(self.quota.rawHard(), 1);
        });
        self.quota.soft = ko.computed(function() {
            return cloud.convert(self.quota.rawSoft(), 1);
        });
        self.quota.usedBar = ko.computed(function() {
            return (self.quota.rawUsed() / self.quota.rawHard() * 100).toFixed(0) + '%';
        }, self);
        self.quota.softPos = ko.computed(function() {
            return (self.quota.rawSoft() / self.quota.rawHard() * 100).toFixed(0) + '%';
        }, self);
        self.sortBy = ko.observable('name');

        /**
         * Loads the parent folder
         */
        self.jumpUp = function() {
            var s = self.currentPath();
            loadFolder(s.substr(0, s.substr(0, s.length - 1).lastIndexOf('/') + 1));
        };

        self.sortFiles = (function() {
            self.files.sort({
                name: function(a, b) {
                    if (a.type === b.type) {
                        return a.originalName.localeCompare(b.originalName);
                    }
                    if (a.type === gettext('file')) {
                        return 1;
                    }
                    return -1;
                },
                date: function(a, b) {
                    if (a.type === b.type) {
                        return new Date(b.mTime).getTime() - new Date(a.mTime).getTime();
                    }
                    if (a.type === gettext('file')) {
                        return 1;
                    }
                    return -1;
                },
                size: function(a, b) {
                    if (a.type === b.type) {
                        return b.originalSize - a.originalSize;
                    }
                    if (a.type === gettext('file')) {
                        return 1;
                    }
                    return -1;
                },
            }[self.sortBy()]);
        });

        /**
         * Loads the specified folder
         */
        var loadFolder = cloud.throttle(function(path, fast) {
            self.currentPath(path);
            $.ajax({
                type: 'POST',
                data: 'path=' + path,
                url: '/ajax/store/list',
                dataType: 'json',
                success: function(data) {
                    if (!fast) {
                        $('.file-list .real').css({
                            left: 0,
                            position: 'relative'
                        }).animate({
                            left: '-100%'
                        }, 500).promise().done(function() {
                            loadFolderDone(data);
                            $('.file-list .real').css({
                                left: '-300%',
                                position: 'relative'
                            }).animate({
                                left: 0
                            }, 500);
                        });
                    } else {
                        loadFolderDone(data);
                    }
                },
            })
        });

        var showToplist = ko.observable(false);
        self.toggleToplist = cloud.throttle(function() {
            if (!showToplist()) {
                showToplist(true);
                loadToplist();
            } else {
                showToplist(false);
                self.currentPath('/');
                loadFolder('/');
            }
        });

        self.getToplistText = ko.computed(function() {
            if (!showToplist()) {
                return gettext('Toplist');
            } else {
                return gettext('Back to the root folder');
            }
        })

        function loadToplist() {
            self.currentPath('/');
            $.ajax({
                type: 'POST',
                url: '/ajax/store/top/',
                dataType: 'json',
                success: function(data) {
                    $('.file-list .real').css({
                        left: 0,
                        position: 'relative'
                    }).animate({
                        left: '-100%'
                    }, 500).promise().done(function() {
                        loadFolderDone(data);
                        $('.file-list .real').css({
                            left: '-300%',
                            position: 'relative'
                        }).animate({
                            left: 0
                        }, 500);
                    });
                }
            });
        }

        /**
         * After loadFolder completes, this function updates the UI
         */

        function loadFolderDone(data) {
            var viewData = [];
            var added = 0;
            self.notInRoot(self.currentPath().lastIndexOf('/') !== 0);
            self.files([]);
            for (var i in data) {
                addFile(data[i]);
            }
            self.sortFiles();
        }

        /**
         * Add file to the displayed files list
         */

        function addFile(d) {
            var viewData;
            if (d.TYPE === 'D') {
                viewData = {
                    originalName: d.NAME,
                    originalSize: 0,
                    name: d.NAME.length > 30 ? (d.NAME.substr(0, 27) + '...') : d.NAME,
                    size: 'katalógus',
                    type: 'katalógus',
                    mTime: d.MTIME,
                    getTypeClass: 'name filetype-folder',
                    clickHandler: function(item) {
                        loadFolder(self.currentPath() + item.originalName + '/');
                    }
                };
            } else {
                var type = 'text';
                var ext = {
                    image: /\.(jpg|png|gif|jpeg)$/,
                    pdf: /\.pdf$/,
                    doc: /\.docx?$/,
                    excel: /\.xlsx?$/,
                    csv: /\.csv$/,
                    php: /\.php$/,
                    tex: /\.tex$/,
                    ppt: /\.pptx?/,
                    music: /\.(wav|mp3)$/
                };
                for (var i in ext) {
                    if (d.NAME.match(ext[i])) {
                        type = i;
                        break;
                    }
                }
                var extension;
                try {
                    extension = d.NAME.match(/\.\w+$/)[0].substr(1);
                } catch (ex) {
                    extension = 'N/A';
                }
                viewData = {
                    originalName: d.NAME,
                    originalSize: d.SIZE,
                    name: d.NAME.length > 30 ? (d.NAME.substr(0, 20) + '... (' + extension + ')') : d.NAME,
                    size: cloud.convert(d.SIZE),
                    type: gettext('file'),
                    mTime: d.MTIME,
                    getTypeClass: 'name filetype-' + type,
                    clickHandler: function(item, e) {
                        toggleDetails.call(e.currentTarget);
                    }
                };
            }
            self.files.push(viewData);
        }

        /**
         * After 'addFile', this function animates the new item
         */
        self.fadeIn = function(e) {
            //firefox sucks :S
            try {
                $(e).hide().slideDown(500);
            } catch (ex) {

            }
        }

        self.fadeOutFile = function(e) {
            try {
                $(e).slideUp(500, function() {
                    e.parentNode.removeChild(e);
                });
            } catch (ex) {
                e.parentNode.removeChild(e);
            }
        }

        /**
         * Downloads the specified file (or folder zipped)
         */
        self.download = function(item, ev) {
            ev.stopPropagation();
            ev.preventDefault();
            if (window.navigator.userAgent.indexOf('cloud-gui') > -1) {
                window.location.href = 'cloudfile:' + self.currentPath() + item.originalName;
                return;
            }
            $.ajax({
                type: 'POST',
                data: 'dl=' + self.currentPath() + item.originalName,
                url: '/ajax/store/download',
                dataType: 'json',
                success: function(data) {
                    window.location.href = data.url;
                }
            });
        }

        /**
         * Deletes the specified file (or folder)
         */
        self.delete = function(item, ev) {
            ev.stopPropagation();
            ev.preventDefault();
            $('#modal').show();
            s = "";
            if (item.type == gettext('file')) {
                s = gettext("You are removing the file <strong>%s</strong>.");
            } else {
                s = gettext("You are removing the folder <strong>%s</strong> (and its content).");
            }

            $('#modal-container').html(interpolate(s, [item.originalName]) + " " + gettext("Are you sure?") + '<br /><input class="ok" type="button" value="' + gettext("Delete") + '" style="float: left"/><input class="cancel" type="button" value="' + gettext('Cancel') + '" style="float: right" />');
            $('#modal-container .ok').click(function() {
                $('#modal').hide();
                $.ajax({
                    type: 'POST',
                    data: 'rm=' + self.currentPath() + item.originalName,
                    url: '/ajax/store/delete',
                    dataType: 'json',
                    success: function(data) {
                        self.files.remove(item);
                    }
                })
            });
            $('#modal-container .cancel').click(function() {
                $('#modal').hide();
            });
        }

        /**
         * Renames the specified file
         */
        self.rename = function(item, e) {
            e.stopPropagation();
            e.preventDefault();
            var oldName = $(e.target).parent().parent().parent().find('.name').html();
            $(e.target).parent().unbind('click').click(function(f) {
                f.stopPropagation();
                f.preventDefault();
                $(e.target).parent().parent().parent().find('.name').html(oldName);
                $(e.target).parent().click(function(g) {
                    g.stopPropagation();
                    self.rename(item, g);
                });
            });
            $(e.target).parent().parent().parent().find('.name').html('<input type="text" value="' + item.originalName + '" />\
<input type="submit" value="' + gettext('Rename') + '" />');
            $(e.target).parent().parent().parent().find('.name input').click(function(f) {
                f.stopPropagation();
            })
            $(e.target).parent().parent().parent().find('.name input[type=submit]').click(function(e) {
                e.preventDefault();
                var newName = $(e.target).parent().parent().parent().find('.name input[type=text]').val();
                $.ajax({
                    type: 'POST',
                    data: 'path=' + self.currentPath() + item.originalName + '&new=' + newName,
                    url: '/ajax/store/rename',
                    dataType: 'json',
                    success: function(data) {
                        loadFolder(self.currentPath(), true);
                    }
                })
                return false;
            })
        }

        /**
         * Requests a new upload link from the store server
         */
        self.getUploadURL = function(f) {
            uploadURLRequestInProgress = true;
            $.ajax({
                type: 'POST',
                data: 'ul=' + self.currentPath() + '&next=' + encodeURI(window.location.href),
                url: '/ajax/store/upload',
                dataType: 'json',
                success: function(data) {
                    self.uploadURL(data.url);
                    uploadURLRequestInProgress = false;
                    if (typeof f == 'function') f();
                }
            })
        }

        /**
         * Creates a new folder (and then reloads the current folder)
         */
        self.newFolder = cloud.throttle(function(i, e) {
            $(e.target).parent().parent().parent().removeClass('opened');
            $.ajax({
                type: 'POST',
                data: 'new=' + self.newFolderName() + '&path=' + self.currentPath(),
                url: '/ajax/store/newFolder',
                dataType: 'json',
                success: function(data) {
                    loadFolder(self.currentPath(), true);
                }
            })
        });

        /**
         * Drag'n'drop tests
         */
        var tests = {
            filereader: typeof FileReader != 'undefined',
            dnd: 'draggable' in document.createElement('span'),
            formdata: !! window.FormData,
            progress: "upload" in new XMLHttpRequest
        };

        /**
         * Uploads the specified file(s)
         */
        var readfiles = cloud.delayUntil(function(file, next) {
            for (var i in self.files()) {
                var f = self.files()[i];
                if (file.name == f.originalName) {
                    if (!confirm(
                            interpolate(
                                gettext('File %s is already present! Click OK to override it.'),
                                [file.name]
                                )
                            )
                        ) {
                        return next();
                    }
                }
            }
            if (file.name.indexOf('.') == -1 && file.size % 4096 == 0) {
                if (!confirm(
                        interpolate(
                            gettext('%s seems to be a directory. Uploading directories is currently not supported. If you\'re sure that %s is a file, click OK to upload it.'),
                            [file.name, file.name]
                            )
                        )
                    ) {
                    return next();
                }
            }
            if (file.size > 1024 * 1024 * 1024) {
                $('#upload-zone').hide();
                $('#upload-error').show();
                $('#upload-error-size').show();
                setTimeout(function() {
                    $('#upload-zone').show();
                    $('#upload-error').hide();
                    $('#upload-error-size').hide();
                }, 3000);
                return;
            }
            var formData = tests.formdata ? new FormData() : null;
            formData.append('data', file);
            if (tests.formdata) {
                var xhr = new XMLHttpRequest();
                var start = new Date().getTime();
                xhr.open('POST', self.uploadURL());
                xhr.onload = xhr.onerror = function() {
                    console.log('onload');
                    self.uploadProgress('0%');
                    self.uploadURL('/');
                    console.log('complete, next');
                    next();
                }
                if (tests.progress) {
                    $('#upload-zone').hide();
                    $('#upload-progress-text').show();
                    var originalUsedQuota = self.quota.rawUsed();
                    xhr.upload.onprogress = function(event) {
                        if (event.lengthComputable) {
                            self.quota.rawUsed(originalUsedQuota + parseInt(event.loaded / 1024));
                            var complete = (event.loaded / event.total * 100 | 0);
                            //progress.value = progress.innerHTML = complete;
                            self.uploadProgress(complete.toFixed(1) + '%');
                            var suffix = 'B KB MB GB'.split(' ');
                            var l = event.loaded;
                            var t = event.total;
                            for (var i = 0; l > 1024; i++) {
                                l /= 1024;
                            }
                            l = l.toFixed(1) + ' ' + suffix[i];
                            for (var i = 0; t > 1024; i++) {
                                t /= 1024;
                            }
                            t = t.toFixed(1) + ' ' + suffix[i];
                            var diff = new Date().getTime() - start;
                            if (complete < 100) {
                                $('#upload-progress-text').html(gettext('Upload') + ': ' + cloud.convert(event.loaded / diff * 1000) + '/s (' + (event.loaded / event.total * 100).toFixed(2) + '%)');
                            } else {
                                $('#upload-progress-text').html(gettext('Upload') + ': ' + gettext('done, processing...'));
                            }
                        }
                    }
                }
                xhr.send(formData);
            }
        }, function() {
            return self.uploadURL() !== '/';
        }, 200);

        /**
         * Drag'n'drop listeners
         */
        document.addEventListener('drop', function(e) {
            e.stopPropagation();
            e.preventDefault();
            var len = e.dataTransfer.files.length;
            var files = e.dataTransfer.files;
            console.log(files);
            console.log(e.dataTransfer.files);
            var i = 0;
            (function next() {
                if (i >= files.length) {
                    $('.file-upload').removeClass('opened');
                    $('.file-upload .details').slideUp(700);
                    $('#upload-zone').show();
                    $('#upload-progress-text').hide();
                    loadFolder(self.currentPath());
                    return;
                }
                console.log('reading file ' + i);
                if (self.uploadURL() == '/') {
                    self.getUploadURL(function() {
                        readfiles(files[i++], next);
                    });
                } else {
                    readfiles(files[i++], next);
                }
            })();
            return false;
        });
        document.addEventListener('dragover', function(e) {
            if (!uploadURLRequestInProgress && self.uploadURL() == '/') {
                $('.file-upload .summary').click();
            }
            e.stopPropagation();
            e.preventDefault();
            return false;
        });

        /**
         * Fetch quota information
         */

        function refreshQuota() {
            $.ajax({
                'type': 'GET',
                'url': '/ajax/store/quota',
                dataType: 'json',
                success: function(data) {
                    self.quota.rawUsed(parseInt(data.Used));
                    self.quota.rawSoft(parseInt(data.Soft));
                    self.quota.rawHard(parseInt(data.Hard));
                }
            })
        }

        //initialization
        refreshQuota();
        loadFolder(self.currentPath());
    }
    var model = new Model();
    $(function() {
        ko.applyBindings(model);
        $('#keys').click(function(e) {
            $('.key').slideDown(700);
            $('#keys').slideUp(700);
        });
        $('#current-location select').on('change', function() {
            model.sortBy($('#current-location select').val());
            model.sortFiles();
        })
    });
    document.addEventListener('dragenter', function(e) {
        e.stopPropagation();
        e.preventDefault();
        return false;
    });

    document.addEventListener('drag', function(e) {
        e.stopPropagation();
        e.preventDefault();
        return false;
    });
    return cloud;
})(cloud || {});
