function McVisualisation($rootScope, convUIN) {
    "use strict";

    var _self          = this;
    var _uin           = null;
    var rnd            = mcService.RandomHash(5);
    var items          = {};
    var vFileUploader  = null;
    var vDirectReceive = null;
    var downloadConstants = {
        NOPROCESS       : 0,
        UPLOAD          : 1,
        UPLOADBUFFER    : 2,
        DOWNLOAD        : 3,
        PREPARING       : 4,
        UPLOADIRECT     : 5,
        WAITANSWER      : 6,
        DOWNLOADPREP    : 7,
        DOWNLOADDIRECT  : 8,
        DOWNLOADFTP     : 9
    };
    var currentDuState = downloadConstants.NOPROCESS;
    var rayID = "";

    function __abortTransfer(allOK) {
        switch (currentDuState){
            case downloadConstants.DOWNLOADFTP:
                $rootScope.$broadcast('sendCMDToElectron', [
                    mcConst._CMD_.ce_ftp_abort
                ]);
                break;

            case downloadConstants.DOWNLOAD:
                $rootScope.$broadcast('sendCMDToElectron', [
                    mcConst._CMD_.ce_file_download_abort
                ]);
                break;

            case downloadConstants.WAITANSWER:
                if (vFileUploader && vFileUploader.getUINsend()){
                    $rootScope.$broadcast('sendCMDToElectron', [
                        mcConst._CMD_.ce_file_direct_upload_abort
                    ]);
                }

                $rootScope.SendCMDToServer([
                    mcConst._CMD_.cs_files_transfer_request_abort,
                    mcConst.SessionID,
                    $rootScope.GetChatID()
                ]);
                break;

            case downloadConstants.UPLOADIRECT:
                $rootScope.$broadcast('sendCMDToElectron', [
                    mcConst._CMD_.ce_file_direct_upload_abort
                ]);

                $rootScope.SendCMDToServer([
                    mcConst._CMD_.cs_files_transfer_abort,
                    mcConst.SessionID,
                    $rootScope.GetChatID()
                ]);
                break;

            case downloadConstants.UPLOADBUFFER:
            case downloadConstants.UPLOAD:
                $rootScope.$broadcast('abortUploading');
                break;

            case downloadConstants.PREPARING:
                $rootScope.$broadcast('abortPreparingUploading');
                break;

            case downloadConstants.DOWNLOADPREP:
                vDirectReceive.reject(true);
                break;

            case downloadConstants.DOWNLOADDIRECT:
                $rootScope.$broadcast('sendCMDToElectron', [
                    mcConst._CMD_.ce_remove_ftp_user,
                    _uin
                ]);

                if (!allOK) {
                    $rootScope.SendCMDToServer([
                        mcConst._CMD_.cs_files_transfer_abort,
                        mcConst.SessionID,
                        $rootScope.GetChatID()
                    ]);
                }
                break;
        }

        _self._hideProgressInfo();
    }

    function _acceptFilesReceive() {

    }

    // ===========================================================

    this._getViews  = function (cancelText) {
        return {
            progressWrapper:
                { id: "progressWrapper" + rnd, css: "noBGColor byCenter borderTopBottom", height: 30, padding: 0, borderless: true, hidden: true, cols: [
                    { id: "universalProgress" + rnd, borderless: true, css: "noBGColor byCenter", hidden: true,
                        template: function () {
                            var html = "&nbsp;";

                            if (this.progress){
                                var data = this.progress;

                                html = mcService.myReplaceFormated(
                                    "<div class='uploader_overall'>" +
                                    "   <div class='uploader_status'>" +
                                    "       <div class='uploader_progress' style='width:#{width}'></div>" +
                                    "       <div class='uploader_message'>#{txt}</div>" +
                                    "   </div>"+
                                    "</div>",
                                    {
                                        width   : data.percent !== undefined ? data.percent + "%" : 0,
                                        txt     : data.text + (data.size ? "/" + data.size + " " : " ") + (data.percent !== undefined ? data.percent + "%" : "")
                                    }
                                );
                            }

                            return html;
                        }
                    },

                    { id: "uploadProgress" + rnd, view: "list", type: "myUploader", css: "uploader_nopadding", scroll: false, padding: 0, borderless: true, hidden: true, select: false},
                    { view: "button", value: cancelText || mcLang(33), width: 105, click: function () { // "33" :"Отмена",
                        __abortTransfer();

                        _self.onAbortButton && _self.onAbortButton();
                    }}
                ]},

            downloadFilesQuestion:
                { id: "downloadFilesQuestion" + rnd, css: "borderTopBottom", borderless: true, height: 60, hidden: true, rows: [
                    { id: "downloadFileList", view: "template", template: "&nbsp;", padding: 5, borderless: true, css: "whiteBg monospaceAll", scroll: 'y'},

                    { cols: [
                        {},
                        { view: "button", value: mcLang(592), maxWidth: 130, click: _acceptFilesReceive}, // "592":"Принять",
                        { width: 10},
                        { view: "button", value: mcLang(33),  maxWidth: 130, click: __abortTransfer, type: "danger"}, // "33" :"Отмена",
                        {}
                    ]}
                ]}
        }
    };

    this.getUploadProgress = function () {
        return "uploadProgress" + rnd;
    };

    this._initViews = function () {
        items.progressWrapper       = $$("progressWrapper" + rnd);
        items.universalProgress     = $$("universalProgress" + rnd);
        items.uploadProgress        = $$("uploadProgress" + rnd);
    };

    this._showDownloadFileList = function (list) {
        _uin = list.UIN;

        $rootScope.$broadcast(window._messages_.clientData.sendCMDToElectron, [
            mcConst._CMD_.ce_get_user_folder,

            list.UIN,
            list.DisplayName,

            function (path) {
                vDirectReceive.setFilesList(list, path);

                if ($rootScope.customUserOptions.getOption(_uin, "autoReceive")) {
                    setTimeout(function () {
                        vDirectReceive.accept(path);
                    }, 100);
                } else {
                    // $rootScope.$broadcast("unPinTool");
                    $rootScope.$broadcast("selectTool", [mcConst.dataModels.ReceiveFiles]);
                    $rootScope.$broadcast(window._messages_.receiveFiles.setReceiveFilesInfo, [vDirectReceive.getInfo()]);
                }
            }
        ]);
    };

    this._hideProgressInfo = function (allOk){
        if (currentDuState && !allOk && window._messages_.chatFrame){
            // if (!allOk && window._messages_.chatFrame) {
            $rootScope.$broadcast(window._messages_.chatFrame.scrollDownChat);
            // }
        }

        if (allOk){
            switch (currentDuState){
                case downloadConstants.DOWNLOAD:
                case downloadConstants.DOWNLOADFTP:
                    webix.message(mcLang(575)); // "575":"Файл скачан",
                break;

                case  downloadConstants.UPLOAD:
                    webix.message(mcLang(576)); // "576":"Файл загружен на сервер",
                break;
            }
        }

        // currentDuStat e = downloadConstants.NOPROCESS;

        if (items.progressWrapper) {
            _self._showProgressInfo(downloadConstants.NOPROCESS, true);
        }
    };

    this._showProgressInfo = function (state, clear){
        currentDuState = state;

        if (currentDuState !== downloadConstants.NOPROCESS && currentDuState !== downloadConstants.DOWNLOADPREP) {
            items.progressWrapper.show();
        } else {
            items.progressWrapper.hide();
        }

        if (clear){
            items.uploadProgress.clearAll();
        }

        switch (currentDuState){
            case downloadConstants.PREPARING:
            case downloadConstants.DOWNLOAD:
            case downloadConstants.DOWNLOADFTP:
            case downloadConstants.UPLOADBUFFER:
            case downloadConstants.UPLOADIRECT:
            case downloadConstants.DOWNLOADDIRECT:
                _self._updateProgress({
                    percent : 0,
                    text    : ' ... '
                });

                items.universalProgress.show();
                items.uploadProgress.hide();
            break;

            case downloadConstants.WAITANSWER:
                _self._updateProgress({
                    text: mcLang(583) // "583":"Ожидаем согласие на прием файлов...",
                });

                items.universalProgress.show();
                items.uploadProgress.hide();
            break;

            case downloadConstants.UPLOAD:
                items.universalProgress.hide();
                items.uploadProgress.show();
            break;
        }
    };

    this._updateProgress = function (chunk) {
        if (currentDuState){
            items.universalProgress.define('progress', chunk);
            items.universalProgress.refresh();
        }
    };

    this._onPrepareProgress = function (percent) {
        _self._updateProgress({
            percent: percent,
            text   : 'SHA1 calculating'
        });
    };

    this.abortTransfer = __abortTransfer;

    this.setFileUploader = function (_fileUploader) {
        vFileUploader = _fileUploader;
    };

    this.setDirectReceive = function (_directReceive) {
        vDirectReceive = _directReceive;
    };

    this.onAbortButton = null;

    this.active = function (_rayID) {
        // if (!rayID || _rayID === rayID) {
        //     rayID = _rayID;
        //     return true;
        // } else {
        //     return false;
        // }
        return !!items.progressWrapper;
    };

    this.getState = function () {
        return currentDuState;
    };

    this.constants = downloadConstants;
}