dojo.provide("parus.database");

dojo.require("parus.xml");
dojo.require("parus.parus8");
dojo.require("parus.changePasswordDialog");

if (!parus) parus = {};

if (!parus.database) dojo.mixin(parus, {
  database: {}
});

dojo.mixin(parus.database, {

  connected: null,

  attributes: null,

  login: null,

  authException: null,

  companyName: null,

  sessionIdentAllowedForSubDomains: false,

  connect: function(handler, login, password, newPassword, getNegotiateUserName, sslCertAuth) {

    this.connected = null;
    this.authException = null;
    this.attributes = {};
    this.login = login;
    this.sessionIdentAllowedForSubDomains = !! sslCertAuth;

    var ahandler = handler;

    var h = handler.split(";");
    if (h.length > 1) {
      ahandler = h[0];
      this.companyName = h[1];
    }
    else this.companyName = "";

    var errorText;
    var allowContinue = false;

    var host = "..";
    var isOtherHost = false;
    if (sslCertAuth && parus.parus8._SSLCertAuthSubDomain) {
      host = parus.parus8._SSLCertAuthSubDomain;
      isOtherHost = true;
    }

    var url = (newPassword ? "changePassword.xml" : getNegotiateUserName ? "getNegotiateUserName.xml" : "sysinfo.xml");

    var content = {
      SessionCompanyName: this.companyName
    };
    if (login) content["login"] = login;
    if (password) content["password"] = password;
    if (sslCertAuth) content["SSLCert_auth_request"] = "1";
    if (newPassword) content["new_password"] = newPassword;

    dojo.xhrGet({
      handleAs: "xml",
      sync: true,
      headers: (login || password || sslCertAuth) ? {
        "Disable-Basic-Auth": "yes"
      } : {},
      withCredentials: this.sessionIdentAllowedForSubDomains,
      preventCache: true,
      url: host + "/" + ahandler + "/" + url,
      content: content,
      load: dojo.hitch(this, function(response) {
        if (response.documentElement.nodeName == "error") {
          if (response.documentElement.getAttribute("session_reused") != "1") {
            var messageNodes = response.documentElement.getElementsByTagName("message");
            errorText = ((messageNodes.length > 0) ? messageNodes[0].childNodes[0].nodeValue : response.documentElement.childNodes[0].nodeValue) || errorText;
          }
        }
        else {
          this.connected = handler;
          for (var i = 0; i < response.documentElement.attributes.length; i++)
          this.attributes[response.documentElement.attributes[i].nodeName] =
          response.documentElement.attributes[i].nodeValue;
          this.companyName = this.attributes["company"];
        }
        return (response);
      }),
      error: dojo.hitch(this, function(e) {
        if (e.status === 403) {
          dojo.xhrGet({
            handleAs: "xml",
            sync: true,
            preventCache: true,
            url: "../.system/session.xml",
            load: dojo.hitch(this, function(response) {
              if (!dojo.isIE) response.normalize();
              var nodes = response.documentElement.getElementsByTagName("*");
              for (var i = 0; i != nodes.length; i++) {
                if (nodes[i].nodeName.startsWith("auth-")) {
                  this.attributes[nodes[i].nodeName] = nodes[i].childNodes.item(0).nodeValue;
                }
              }
              return (response);
            })
          });
        }
        else if (isOtherHost && (e.status === undefined) && (e.name === "NetworkError")) errorText = "Не удалось получить ответ от сервера для выбранного и отправленного сертификата пользователя. Обратитесь к Администратору";
      })
    });

    if (!this.connected && !errorText && (this.attributes["auth-is2FactorAuth"] || sslCertAuth)) {
      if (this.attributes["auth-is2FactorAuth"] == "1" || sslCertAuth) {
        if (!isOtherHost) return this.connect(handler, login, password, newPassword, getNegotiateUserName, true);
        //e.status === 403
        else if (this.attributes["auth-SSLCert_Current_Thumbprint"]) errorText = "Выбранный сертификат пользователя не прошел проверку на сервере.";
        else errorText = "Сертификат пользователя не был выбран или он не поддерживается сервером.";
      }
    }

    if (!errorText && this.attributes["auth-loginEnabled"]) {
      if (this.attributes["auth-loginEnabled"] == "0") {
        if (this.attributes["auth-loginEnabledTimeLeft"]) {
          errorText = "Максимальное количество одновременных сеансов пользователя превышено. Рекомендуем повторить попытку через " + this.attributes["auth-loginEnabledTimeLeft"] + " мин.";
        }
        else {
          errorText = "Максимальное количество одновременных сеансов пользователя превышено. Обратитесь к Администратору";
        }
      }
    }

    if (!errorText && this.attributes["auth-logonTryWeb"]) {
      if (this.attributes["auth-logonTryWeb"] == "0") {
        errorText = "Доступ пользователю закрыт. Обратитесь к администратору";
      }
    }

    if (!errorText && this.attributes["auth-accountLocked"]) {
      if (this.attributes["auth-accountLocked"] != "0") {
        errorText = "Учётная запись пользователя заблокирована. Обратитесь к администратору";
      }
    }

    if (!errorText && !newPassword) {
      var canChangePassword = this.attributes["auth-userCanChangePassword"] == "1";

      if (this.attributes["auth-passwordExpiried"]) {
        if (this.attributes["auth-passwordExpiried"] == "1") {
          if (canChangePassword) {
            errorText = "Срок действия вашего пароля истек. <br/> Воспользуйтесь возможностью \"<b>Изменить пароль</b>\"";
          }
          else {
            errorText = "Срок действия вашего пароля истек. Работа в системе невозможна. Обратитесь к администратору";
          }
        }
        else if (this.attributes["auth-passwordExpiried"] == "2") {
          if (canChangePassword) {
            errorText = "Срок действия вашего пароля закончится в ближайшее время. <br/> Закройте приложение (крестом в правом верхнем углу), и воспользуйтесь возможностью \"<b>Изменить пароль</b>\"";
          }
          else {
            errorText = "Срок действия вашего пароля закончится в ближайшее время. Обратитесь к администратору";
          }
          allowContinue = true;
        }
      }

      if (!errorText && this.attributes["auth-mustChangePassword"]) {
        if (this.attributes["auth-mustChangePassword"] == "1") {
          errorText = "Необходимо сменить пароль. <br/> Воспользуйтесь возможностью \"<b>Изменить пароль</b>\"";
        }
      }
    }

    if (errorText) {
      if (!allowContinue) {
        this.authException = true;
      }
      parus.parus8.notificationMessage(errorText);
    }

    if (this.authException || !this.connected) {
      this.clearSessionIdent();
      this.connected = null;
      this.companyName = null;
      this.attributes = null;
    }

    return this.connected;
  },

  clearSessionIdent: function() {
    var params = {
      path: "/"
    };
    /*if (this.sessionIdentAllowedForSubDomains)
     dojo.mixin(params, {
     domain: window.location.hostname
     });*/
    dojo.cookie("HTTPID", "", params);
  },

  _xhr: function(url, id, params, loaded, error, noTimeout) {

    if (!this.connected) throw new Error("Not connected to database.");

    if ( !! !noTimeout) parus.parus8.registerAction();

    var queryparam = "";

    var emptydata = null;

    if (params) for (var key in params) if (params[key] == parus.parus8.CLASS_EmptyData) {
      emptydata = true;
      break;
    };

    if (emptydata) {

      var response = document.createElement("ROWSET");

      if (loaded) {
        var deferred = new dojo.Deferred();
        setTimeout(function() {
          loaded(response);
          deferred.callback({
            success: true
          });
        }, 1);
        return deferred;
      }
      else return response;
    };

    var qp = [];
    if (id) dojo.mixin(qp, {
      id: id
    });
    for (var key in params) {
      var p = {};
      p[key] = params[key];
      qp.push(p);
    };

    queryparam = parus.xml.toXml({
      query: qp
    });

    var responseDocument = null;

    var asXML = url.indexOf(".xml") != -1;

    var h = this.connected.split(";");
    if (h.length > 1) {
      h = h[0];
    }
    else h = this.connected;

    var loadedCalled = false;

    var deferredParams = {

      handleAs: asXML ? "xml" : "json",
      sync: (loaded ? false : true),
      content: {
        query: queryparam,
        "SessionCompanyName": this.companyName
      },
      headers: {
        "Disable-Basic-Auth": "yes"
      },

      url: encodeURI("../" + h + "/" + url),

      load: dojo.hitch(this, function(response) {

        if (asXML) {
          if (!dojo.isIE) response.normalize();

          if (response.documentElement.nodeName == "error") {
            if (error) {
              error(response);
            }
            else {
              parus.parus8.errorMessage(parus.parus8.nodeField(response.documentElement, "message"));
              if (loaded && !loadedCalled) {
                loadedCalled = true;
                loaded(response);
              }
            };

            responseDocument = null;
            return response;
          }
        };

        responseDocument = response;
        if (loaded) loaded(response);
        return (response);
      }),

      error: function(e) {
        if (error) {
          error(e);
        }
        else {
          console.log("Database error", e);
          parus.parus8.errorMessage("Ошибка получения данных. <br/>Вероятно, произошел сетевой сбой, или сервер стал недоступен. <br/>Попробуйте обновить страницу в браузере и перевойти в приложение.");
        };

        if (loaded && !loadedCalled) {
          loadedCalled = true;
          loaded(document.createElement("ROWSET"));
        }


        responseDocument = null;
        return e;
      }

    };

    if (deferredParams.sync && dojo.isSafari) {
      if (!deferredParams.headers) deferredParams.headers = {};
      dojo.mixin(deferredParams.headers, {
        "Sync-Short-Timeout": "yes"
      });
    };

    var deferred = dojo.xhrPost(deferredParams);

    return loaded ? deferred : responseDocument;
  },

  _buildUrl: function(url) {

    var h = this.connected.split(";");
    if (h.length > 1) {
      h = h[0];
    }
    else h = this.connected;

    h = "../" + h + url;

    if (this.companyName) {
      if (h.indexOf("?") == -1) h = h + "?SessionCompanyName=" + this.companyName;
      else h = h + "&SessionCompanyName=" + this.companyName;
    }

    return encodeURI(h);

  },

  query: function(id, params, loaded, error, noTimeout) {
    return this._xhr("query.xml", id, params, loaded, error, noTimeout);
  },

  execute: function(id, params, loaded, error, noTimeout) {
    return this._xhr("execute.xml", id, params, loaded, error, noTimeout);
  },

  queryObject: function(id, params, loaded, error, noTimeout) {
    return this._xhr("query.js", id, params, loaded, error, noTimeout);
  },

  toBuffer: function(input, type, ident, continueAction) {

    var h = this.connected.split(";");
    if (h.length > 1) {
      h = h[0];
    }
    else h = this.connected;


    if (!input.value) {
      if (continueAction) continueAction(null);
      return;
    }

    var form = document.createElement("form");

    form.method = "POST";
    form.action = "../" + h + "/tobuffer.xml";
    form.encoding = "multipart/form-data";

    var typeinput;
    if (dojo.isIE) {
      form.insertAdjacentHTML("afterBegin", "<input type='hidden' name='type'/>");
      typeinput = form.childNodes[0];
    } else {
      typeinput = form.appendChild(document.createElement("input"));
      typeinput.type = "hidden";
      typeinput.name = "type";
    };
    typeinput.value = type;

    if (ident) {
      var identinput;
      if (dojo.isIE) {
        form.insertAdjacentHTML("afterBegin", "<input type='hidden' name='IDENT'/>");
        identinput = form.childNodes[0];
      } else {
        identinput = form.appendChild(document.createElement("input"));
        identinput.type = "hidden";
        identinput.name = "IDENT";
      };
      identinput.value = ident;
    };

    var parent = input.parentNode;
    var oldname = input.name;
    input.name = "data";
    form.appendChild(input);

    document.body.appendChild(form);

    dojo.io.iframe.send({
      method: "POST",
      form: form,
      handleAs: (dojo.isIE >= 10) ? "html" : "xml",

      handle: function(response) {
        if (!dojo.isIE) response.normalize();

        if (response.documentElement.nodeName == "error") {
          parus.parus8.errorMessage(parus.parus8.nodeField(response.documentElement, "message"));
          response = null;
        };

        document.body.removeChild(form);

        if (parent) parent.appendChild(input);
        input.name = oldname;

        if (response) {
          if (continueAction) continueAction(parus.parus8.nodeField(parus.parus8.rowNodes(response)[0], "IDENT"));
        };
        return response;
      }
    });
  }

});