define(
    ['spinner'],
    function (spinner) {
        "use strict";
        /**
         *
         * @constructor
         */
        function Loader() {
            this.el = null;
            this.spinner = null;
            this.loading = [];
            this.data = null;
            this.callback = null;
            this.types = {
                images: {
                    data: null,
                    total: 0, // what is this for?
                    loaded: [],
                    load: function (loader, type) {
                        var img;

                        this.data.forEach(function (src) {
                            img = new Image();
                            img.src = src;
                            img.onload = function () {
                                this.loaded.push(true);
                                loader.itemLoaded(type);
                            }.bind(this);
                        }.bind(this));

                    }
                },
                olinks: {
                    data: null,
                    total: 0,
                    loaded: [],
                    load: function (loader, type) {
                        this.data.forEach(function (array, i) {
                            this.loaded.push(null);

                            VLE.get_olink_url(
                                array[0],
                                array[1] || '',
                                function (url) {
                                    this.loaded[i] = url.replace(/&/g, '&amp;');
                                    loader.itemLoaded(type);
                                },
                                function (error) {
                                    this.loaded[i] = 'javascript:void(0)';
                                    loader.itemLoaded(type);
                                    console.log('failed to load olink: ' + error);
                                },
                                VLE.get_param('_c'),
                                this
                            );
                        }.bind(this));
                    }
                },
                files: {
                    data: null,
                    total: 0,
                    loaded: [],
                    load: function (loader) {
                        this.data.forEach(function (src, i) {
                            this.loaded.push(null);
                            loader.get(src, i);
                        }.bind(this));
                    }
                },
                folder: {
                    data: null,
                    total: 0,
                    loaded: [],
                    vleFolderUrl: ""
                }
            };
        }

        Loader.prototype = {
            /**
             * common load function for each type
             * @param data
             */
            load: function (data) {
                if (!data) {
                    console.log('No data passed to loader');
                    return;
                }
                this.data = {};
                //clear array
                this.loading.splice(0);
                this.callback = data.callback || console.log.bind(null, 'No callback provided!');

                if (data.spinner !== false) {
                    this.spinner = spinner.construct(data.container);
                    this.spinner.init();
                }

                if (data.load.hasOwnProperty("folder")) {
                    for (var i = 0; i < data.load.folder.length; i++) {
                        this.getFolderAttachment(this, data.load.folder[i], i);
                    }
                }

                for (var p in data.load) {
                    if (data.load.hasOwnProperty(p) && data.load[p].length > 0 && this.types[p]) {
                        this.loading.push(p);
                        this.types[p].data = data.load[p];
                        //clear array
                        this.types[p].loaded.splice(0);
                        if (!data.load.hasOwnProperty("folder")) {
                            this.types[p].load.call(this.types[p], this, p);
                        }
                    }
                }
            },
            /**
             *
             * @param src
             * @param index
             * @param isFolder
             */
            get: function (src, index, isFolder) {
                var xhr = new XMLHttpRequest();
                var name = src.split('/').pop().split('.');
                var type = src.split('.').pop();
                var doc;
                xhr.onreadystatechange = function () {
                    if (xhr.readyState == 4) {
                        if (xhr.status == 200 || xhr.status === 0) {
                            switch (type) {
                                case 'svg':
                                case 'xml':
                                    if (window.DOMParser) {
                                        doc = new DOMParser().parseFromString(xhr.responseText, 'text/xml');
                                    }
                                    else {
                                        //IE9 support...
                                        doc = new ActiveXObject('Microsoft.XMLDOM');
                                        doc.async = false;
                                        doc.loadXML(xhr.responseText);
                                    }
                                    doc = doc.documentElement;
                                    break;
                                case 'json':
                                    doc = JSON.parse(xhr.responseText);
                                    break;
                                default:
                                    doc = xhr.responseText;
                            }
                            if (isFolder) {
                                this.types.folder.loaded[index] = doc; // if json exists and loaded from folder
                                this.itemLoaded('folder');
                            } else {
                                this.types.files.loaded[index] = doc;
                                this.itemLoaded('files');
                            }
                        }
                    }
                }.bind(this);
                xhr.open('GET', src);
                xhr.send();
            },
            /**
             * This function makes sure the .json is loaded first then the folder content such as images
             * @param loader
             * @param folder_name
             * @param index
             */
            getFolderAttachment: function (loader, folder_name, index) {

                VLE.get_folder(folder_name, function (results) {

                    for (var i = 0; i < results.length; i++) {
                        if (results[i].path.split('.').pop() === 'json') {
                            loader.get(results[i].url, index, true);
                        }
                    }
                    loader.types.folder.vleFolderUrl = results[0].url.match(/.+?(?=zip)/) + "zip//";
                }, function (error) {
                    console.log("error");
                });

            },
            /**
             *
             * @param type
             * @returns {boolean}
             */
            isLoaded: function (type) {
                //compare data and loaded lengths and, if true, check all values are truthy
                return this.types[type].loaded.length == this.types[type].data.length &&
                    this.types[type].loaded.every(function (data) {
                        return !!data;
                    });
            },
            /**
             *
             * @param type
             */
            itemLoaded: function (type) {
                var index;

                if (this.isLoaded(type)) {
                    index = this.loading.indexOf(type);

                    if (index > -1) {
                        //remove type from loading array
                        this.loading.splice(index, 1);
                        //set type data on return object
                        this.data[type] = this.types[type].loaded;
                        if (type === 'folder') {
                            this.data[type][0].folder_url = this.types[type].vleFolderUrl;
                            console.log('VLE folder URL: ' + this.types[type].vleFolderUrl);
                        }
                        console.log(type + ' loaded');
                    }
                }
                if (this.loading.length === 0) {
                    console.log('everything loaded');
                    this.callback(this.data);
                }
            }
        };

        return {
            /**
             *
             * @returns {Loader}
             */
            construct: function () {
                return new Loader();
            }
        };
    });
