export default class S3Upload {
    constructor(options={}) {
        this.s3_object_name = 'default_name';
        this.s3_sign_put_url = '/signS3put';
        this.file_dom_el = null;
        this.file_dom_selector = '#file_upload';

        Object.assign(this, options);

        if (this.file_dom_el || this.file_dom_selector) {
            this.handleFileSelect(
                this.file_dom_el ||
                    document.querySelector(this.file_dom_selector)
            );
        }
    }

    onFinishS3Put(public_url, private_url) {
        return console.log('base.onFinishS3Put()', public_url, private_url);
    }

    onProgress(percent, status) {
        return console.log('base.onProgress()', percent, status);
    };

    onError(status) {
        return console.log('base.onError()', status);
    };

    getXMLError(xmlDoc) {
        if (xmlDoc.getElementsByTagName('Message').length > 0) {
            return xmlDoc.getElementsByTagName('Message')[0].textContent;
        }
        return null;
    }

    handleFileSelect(file_element) {
        let f, files, _i, _len, _results;

        files = file_element.files;

        if (files.length === 0) {
            return;
        }

        _results = [];

        this.onProgress(0, 'Upload started.');

        for (_i = 0, _len = files.length; _i < _len; _i++) {
            f = files[_i];
            _results.push(this.uploadFile(f));
        }

        return _results;
    };

    createCORSRequest(method, url) {
        let xhr;
        xhr = new XMLHttpRequest();

        if (xhr.withCredentials !== null) {
            xhr.open(method, url, true);
        } else {
            xhr = null;
        }

        return xhr;
    };

    executeOnSignedUrl(file, callback) {
        let this_s3upload, xhr;
        this_s3upload = this;
        xhr = new XMLHttpRequest();
        xhr.open('GET', this.s3_sign_put_url +
                 '?s3_object_type=' + file.type +
                 '&s3_object_name=' + this.s3_object_name, true);
        xhr.overrideMimeType('text/plain; charset=x-user-defined');
        xhr.onreadystatechange = function() {
            let result;
            if (this.readyState === 4 && this.status === 200) {
                try {
                    result = JSON.parse(this.responseText);
                } catch {
                    this_s3upload.onError('Signing server returned some ugly/empty JSON: "' + this.responseText + '"');
                    return false;
                }

                let signedGetUrl = null;
                if (result.presigned_get_url) {
                    signedGetUrl = decodeURIComponent(
                        result.presigned_get_url);
                }

                return callback(
                    result.presigned_post_url,
                    result.url,
                    signedGetUrl
                );
            } else if (this.readyState === 4 && this.status !== 200) {
                return this_s3upload.onError('Could not contact request signing server. Status = ' + this.status);
            }
        };
        return xhr.send();
    };

    uploadToS3(
        file, urlObj, public_url, presigned_get_url
    ) {
        let this_s3upload, xhr;
        this_s3upload = this;

        xhr = this.createCORSRequest('POST', urlObj.url);

        if (!xhr) {
            this.onError('CORS not supported');
        } else {
            xhr.onload = function() {
                if (xhr.status === 200 || xhr.status === 204) {
                    this_s3upload.onProgress(100, 'Upload completed.');
                    return this_s3upload.onFinishS3Put(
                        public_url, presigned_get_url
                    );
                } else {
                    let parser = new DOMParser();
                    let xmlDoc = parser.parseFromString(
                        xhr.responseText, xhr.responseXML.contentType);

                    let xmlError = this_s3upload.getXMLError(xmlDoc);

                    let errText = xhr.status;
                    if (xmlError) {
                        errText = xmlError;
                    }

                    return this_s3upload.onError(
                        'Upload error: ' + errText);
                }
            };
            xhr.onerror = function() {
                return this_s3upload.onError('Upload failed.');

            };
            xhr.upload.onprogress = function(e) {
                let percentLoaded;
                if (e.lengthComputable) {
                    percentLoaded = Math.round((e.loaded / e.total) * 100);
                    return this_s3upload.onProgress(percentLoaded, percentLoaded === 100 ? 'Finalizing.' : 'Uploading.');
                }
            };
        }

        const formData = new FormData();

        Object.keys(urlObj.fields).forEach((key) => {
            formData.append(key, urlObj.fields[key]);
        });

        formData.append('file', file);

        return xhr.send(formData);
    };

    uploadFile(file) {
        const me = this;
        return this.executeOnSignedUrl(
            file, function(signedURL, publicURL, signedGetURL) {
                return me.uploadToS3(
                    file, signedURL, publicURL, signedGetURL
                );
            });
    };
}

window.S3Upload = S3Upload;
