function McLoadingImages($rootScope) {
    "use strict";

    var deferredLoadImages = new McDeferredLoadImages();
    var loadingImgList = {};
    var self = this;

    function getImgFromLoadList(hash) {
        return loadingImgList[hash] && loadingImgList[hash].idx && loadingImgList[hash].idx.length ? loadingImgList[hash].idx.shift() : null;
    }
    function getImgNameFromLoadList(hash) {
        return loadingImgList[hash] ? loadingImgList[hash].name : null;
    }
    function getTaskIdLoadList(hash) {
        return loadingImgList[hash] && loadingImgList[hash].ID && loadingImgList[hash].ID.length ? loadingImgList[hash].ID.shift() : null;
    }
    function runLoad(queue, idx, done, onLoadImg){
        self.loadThumbs([queue[idx], getImgNameFromLoadList(queue[idx])], onLoadImg, function () {
            idx ++;

            if (idx < queue.length){
                runLoad(queue, idx, done, onLoadImg);
            } else
            if (done) {
                done();
            }
        });
    }

    self.loadAllThumbs = function(done, onLoadImg){
        if (!deferredLoadImages){
            deferredLoadImages = new McDeferredLoadImages();
        }

        var queue = [];

        Object.keys(loadingImgList).forEach(function (hash) {
            loadingImgList[hash].idx.forEach(function () {
                queue.push(hash);
            });
        });

        runLoad(queue, 0, done, onLoadImg);
    };

    self.loadThumbs = function (info, cb, done) {
        var fileInfo = mcService.isObject(info) ? info : {
            Hash    : info[0],
            FileName: info[1],
            idx     : info[2],
            tmp     : info[3]
        };

        if (fileInfo.FileName){
            $rootScope.SendCMDToServer([
                mcConst._CMD_.cs_get_image_thumbs,
                mcConst.SessionID,

                fileInfo.Hash,                //info[0] , //.Hash     , // SHA1 хэш файла
                $rootScope.thumbsSize.x     , // произвольная ширина уменьшеной копии изображения
                $rootScope.thumbsSize.y     , // произвольная высота уменьшенной копии изображения
                fileInfo.FileName,            //info[1] , // FileName , // локальное название файла
                mcService.getCurrentChantTypeForFiles($rootScope.GetChatType()),

                function (requestData) {
                    var idx   = getImgFromLoadList(requestData.Hash) || fileInfo.idx;
                    var where = "/" + $rootScope.GetChatType().toLowerCase() + "/";

                    if (idx) {
                        var _link   = document.getElementById('link_' + requestData.Hash + idx);
                        var _imgOK  = document.getElementById('img_' + requestData.Hash + idx);
                        var fileName= mcService.extractFileName(requestData.FileName);
                        var hasError= false;

                        if (where !== "/kanban/" || where !== "/forum/") {
                            where = "/";
                        }

                        var lnkHref = mcService.getLocalHostPath($rootScope.isWebClient) + "/" + mcConst.pathAliases.AliasFiles + where + requestData.Hash + "/" + (requestData.Exists ? encodeURI(fileName) : mcConst.imagesPath.nofile);

                        if (requestData.Body && requestData.Body.length) {
                            if (!(_imgOK && _link)) return;
                            
                            _imgOK.src       = "data:image/jpeg;base64," + requestData.Body;
                            _imgOK.className = "finger";
                            _link.href       = lnkHref;

                            cb && cb();
                        } else {
                            var imgSrc  = requestData.Exists && ($rootScope.isWebClient || mcConst.ClientSettings.SysEventsShowImagesInChat)
                                ? mcService.getLocalHostPath($rootScope.isWebClient) + "/" + mcConst.pathAliases.AliasFiles + where + requestData.Hash + '-' + $rootScope.thumbsSize.xy + '.jpg'
                                : mcConst.imagesPath.nofile;

                            if (_imgOK && _imgOK.src && _link && _link.href){
                                _imgOK.src = imgSrc;
                                _link.href = lnkHref;

                                _imgOK.onload = function () {
                                    if (!hasError) {
                                        _imgOK.className = "";
                                    }

                                    if (cb) {
                                        cb(this.height, requestData, getTaskIdLoadList(requestData.Hash), imgSrc, lnkHref);
                                    }
                                };

                                _imgOK.onerror = _imgOK.onabort = function (err) {
                                    console.warn(err);

                                    hasError = true;

                                    _imgOK.src = mcConst.imagesPath.noImage;
                                    _imgOK.className = "noImageClick";

                                    try {
                                        this.parentElement.style.height  = "auto";
                                        this.parentElement.style.width   = "auto";
                                        this.parentElement.style.display = "inline";
                                    } catch (e) {}
                                };
                            } else

                            if (deferredLoadImages) {
                                deferredLoadImages.addImage(idx, requestData.Hash, imgSrc, lnkHref);
                            }
                        }
                    } else
                    if (requestData.Exists){
                        var _imgTemp = document.getElementById('img_temp_' + requestData.Hash + "_" + fileInfo.tmp);

                        if (_imgTemp){
                            where = "/kanban/";

                            _imgTemp.src = requestData.Exists && ($rootScope.isWebClient || mcConst.ClientSettings.SysEventsShowImagesInChat)
                                ? mcService.getLocalHostPath($rootScope.isWebClient) + "/" + mcConst.pathAliases.AliasFiles + where + requestData.Hash + '-' + $rootScope.thumbsSize.xy + '.jpg'
                                : mcConst.imagesPath.nofile;

                            _imgTemp.onload = function () {
                                cb && cb();
                            };

                            _imgTemp.onerror = _imgTemp.onabort = function (err) {
                                console.warn(err);

                                hasError = true;

                                _imgTemp.src = mcConst.imagesPath.noImage;

                                try {
                                    this.parentElement.style.height  = "auto";
                                    this.parentElement.style.width   = "auto";
                                    this.parentElement.style.display = "inline";
                                } catch (e) {}
                            };
                        }
                    } else
                    if (!requestData.Exists){
                        var _imgNO  = mcService.getByCssClass('img_temp_' + requestData.Hash);

                        if (_imgNO && _imgNO.length) {
                            for (var i = 0; i < _imgNO.length; i++){
                                _imgNO[i].src = mcConst.imagesPath.noImage;

                                _imgNO[i].parentElement.onclick = function (e) {
                                    e.preventDefault();
                                };
                            }
                        }
                    }

                    if (done){
                        done(requestData);
                    }
                }
            ]);
        }
    };

    self.loadAllImages = function (cb) {
        if (!deferredLoadImages){
            deferredLoadImages = new McDeferredLoadImages();
        }

        deferredLoadImages.load(cb);
    };

    self.addImageToLoad = function (hash, idx, name, taskID) {
        if (!loadingImgList.hasOwnProperty(hash)) {
            loadingImgList[hash] = {
                idx : [idx],
                name: name
            };

            if (taskID) {
                loadingImgList[hash].ID = [taskID];
            }
        } else {
            if (mcService.inArray(idx, loadingImgList[hash].idx) === -1){
                loadingImgList[hash].idx.push(idx);

                if (taskID){
                    if (loadingImgList[hash].ID){
                        loadingImgList[hash].ID.push(taskID);
                    } else {
                        loadingImgList[hash].ID = [taskID];
                    }
                }
            }
        }
    };

    self.destroy = function () {
        deferredLoadImages = null;
    };

    return self;
}

// ==============   DEFERRED LOAD IMAGES  =======================

function McDeferredLoadImages() {
    var items = {};

    this.addImage = function (idx, hash, src, href) {
        if (!items.hasOwnProperty(idx)) {
            items[idx] = [hash, src, href];
        }
    };

    this.load = function (cb) {
        var count      = Object.keys(items).length;
        var currentIdx = 0;

        Object.keys(items).forEach(function (idx) {
            var hash    = items[idx][0];
            var imgSrc  = items[idx][1];
            var lnkHref = items[idx][2];
            var hasError= false;

            var _link   = document.getElementById('link_' + hash + idx);
            var _img    = document.getElementById('img_' + hash + idx);

            if (_img && _img.src && _link && _link.href){
                _img.src   = imgSrc;
                _link.href = lnkHref;

                console.log('loadAll: ' + imgSrc);

                _img.onload = function () {
                    currentIdx ++;

                    if (!hasError) {
                        _img.className = "";
                    }

                    delete items[idx];

                    if (currentIdx === count && cb){
                        cb();
                    }
                };

                _img.onerror =_img.onabort = function (err) {
                    console.warn(err);

                    hasError = true;

                    _img.src = mcConst.imagesPath.noImage;
                    _img.className = "noImageClick";

                    try {
                        this.parentElement.style.height  = "auto";
                        this.parentElement.style.width   = "auto";
                        this.parentElement.style.display = "inline";
                    } catch (e) {}
                }
            }
        });
    };
}
