dojo.provide("parus.digitalSignatureAsync");

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

dojo.mixin(parus.digitalSignature, {

  checkPluginAsync: function() {
    cadesplugin.async_spawn(dojo.hitch(this, function *(args) {
      try {
        cadesplugin.get_extension_version(dojo.hitch(this, this.onGetExtensionVersion));
        cadesplugin.get_extension_id(dojo.hitch(this, this.onGetExtensionID));

        var about = yield cadesplugin.CreateObjectAsync("CAdESCOM.About");
        if (about) {
          this.pluginDef.resolve();

          dojo.mixin(this.version, {
            major: yield about.MajorVersion,
            minor: yield about.MinorVersion,
            build: yield about.BuildVersion
          });

          console.log("Plugin version: " + this.version.major + '.' + this.version.minor + '.' + this.version.build);
        }
      }
      catch(e) {
        console.log("checkPluginAsync", e);
        this.rejectPlugin();
      }
    }));
  },

  certificatesStoreAsync: function(deferred, allowedThumbprints){
    cadesplugin.async_spawn(dojo.hitch(this, function *(args) {
      try {
        var certificates = [];

        var certStore = yield cadesplugin.CreateObjectAsync("CAdESCOM.Store");
        yield certStore.Open();
        try {
          var certCount = 0;
          var certs;
          // cades plugin bug workaround - "Certificates" collection not assigned when no certificates in store.
          try {
            certs = yield certStore.Certificates;
            certCount = yield certs.Count;
          }
          catch (e){
            certCount = 0;
          }

          var currentDate = new Date();
          for (var i = 1; i <= certCount; i++) {
            var cert = yield certs.Item(i);
            var validToDate = new Date(yield cert.ValidToDate);
            var hasPrivateKey = yield cert.HasPrivateKey();
            /*var isValid = yield cert.IsValid();
            isValid = yield isValid.Result;*/

            var pubKey = yield cert.PublicKey();
            var algo = yield pubKey.Algorithm;
            var algoOid = yield algo.Value;
            var GOSTMethods = this.getGOSTMethodsByOid(algoOid, false);

            if (cert
              && (currentDate < validToDate) && hasPrivateKey //&& isValid
              && this.isAllowedThumbprint(yield cert.Thumbprint, allowedThumbprints)) {
              certificates.push({
                SERIALNUMBER: yield cert.SerialNumber,
                THUMBPRINT: yield cert.Thumbprint,
                ISSUEDTO: yield cert.GetInfo(cadesplugin.CAPICOM_CERT_INFO_SUBJECT_SIMPLE_NAME),
                ISSUER: yield cert.GetInfo(cadesplugin.CAPICOM_CERT_INFO_ISSUER_SIMPLE_NAME),
                VALIDFROMDATE: new Date(yield cert.ValidFromDate),
                VALIDTODATE: new Date(yield cert.ValidToDate),
                OID: algoOid,
                GOST_VERSION: GOSTMethods.version,
                GOST_KEYSIZE: GOSTMethods.keySize
              });
            }
          }
        }
        finally {
          yield certStore.Close();
        }

        deferred.resolve(new dojo.data.ItemFileReadStore({
          data: {
            items: certificates,
            identifier: "THUMBPRINT"
          }
        }));
      }
      catch (e){
        deferred.reject(cadesplugin.getLastError(e));
      }
    }));
  },

  signDataAsync: function(deferred, signInfo, certificateThumbprint){
    cadesplugin.async_spawn(dojo.hitch(this, function *(args) {
      try {
        var certStore = yield cadesplugin.CreateObjectAsync("CAdESCOM.Store");
        yield certStore.Open();
        try {
          var certs = yield certStore.Certificates;
          var certItem = yield certs.Find(
            cadesplugin.CAPICOM_CERTIFICATE_FIND_SHA1_HASH, certificateThumbprint);
          var cert = yield certItem.Item(1);

          var signer = yield cadesplugin.CreateObjectAsync("CAdESCOM.CPSigner");
          yield signer.propset_Certificate(cert);
          yield signer.propset_Options(cadesplugin.CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN);

          var signedData = yield cadesplugin.CreateObjectAsync("CAdESCOM.CadesSignedData");
          yield signedData.propset_ContentEncoding(cadesplugin.CADESCOM_BASE64_TO_BINARY);

          for (var i = 0; i < signInfo.length; i++) {
            yield signedData.propset_Content(this.correctBase64Data(signInfo[i].data));
            signInfo[i].signedData = yield signedData.SignCades(signer,
              cadesplugin.CADESCOM_CADES_BES, true, cadesplugin.CADESCOM_ENCODE_BASE64);
          }
        }
        finally {
          yield certStore.Close();
        }

        deferred.resolve(signInfo);
      }
      catch (e){
        deferred.reject(cadesplugin.getLastError(e));
      }
    }));
  },

  checkSignAsync: function(deferred, signInfo){
    cadesplugin.async_spawn(dojo.hitch(this, function *(args) {
      try {
        var signedData = yield cadesplugin.CreateObjectAsync("CAdESCOM.CadesSignedData");
        yield signedData.propset_ContentEncoding(cadesplugin.CADESCOM_BASE64_TO_BINARY);

        for (var i = 0; i < signInfo.length; i++) {
          try {
            yield signedData.propset_Content(this.correctBase64Data(signInfo[i].data));
            yield signedData.VerifyCades(signInfo[i].signedData, cadesplugin.CADESCOM_CADES_BES, true);
            signInfo[i].checkResult = true;
          }
          catch (e){
            signInfo[i].checkResult = false;
            signInfo[i].checkError = this.signIsInvalid(cadesplugin.getLastError(e));
          }
        }

        deferred.resolve(signInfo);
      }
      catch (e){
        deferred.reject(cadesplugin.getLastError(e));
      }
    }));
  },

  signXMLDataAsync: function(deferred, signInfo, certificateThumbprint, isTemplated){
    cadesplugin.async_spawn(dojo.hitch(this, function *(args) {
      try {
        var certStore = yield cadesplugin.CreateObjectAsync("CAdESCOM.Store");
        yield certStore.Open();
        try {
          var certs = yield certStore.Certificates;
          var certItem = yield certs.Find(
            cadesplugin.CAPICOM_CERTIFICATE_FIND_SHA1_HASH, certificateThumbprint);
          var cert = yield certItem.Item(1);

          var signer = yield cadesplugin.CreateObjectAsync("CAdESCOM.CPSigner");
          yield signer.propset_Certificate(cert);
          yield signer.propset_Options(cadesplugin.CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN);

          var signedData = yield cadesplugin.CreateObjectAsync("CAdESCOM.SignedXML");
          if (isTemplated)
            yield signedData.propset_SignatureType(cadesplugin.CADESCOM_XML_SIGNATURE_TYPE_TEMPLATE);
          else {
            var pubKey = yield cert.PublicKey();
            var algo = yield pubKey.Algorithm;
            var algoOid = yield algo.Value;
            var GOSTMethods = this.getGOSTMethodsByOid(algoOid, true);
            yield signedData.propset_SignatureType(cadesplugin.CADESCOM_XML_SIGNATURE_TYPE_ENVELOPED);
            yield signedData.propset_SignatureMethod(GOSTMethods.signMethod);
            yield signedData.propset_DigestMethod(GOSTMethods.digestMethod);
          }

          for (var i = 0; i < signInfo.length; i++) {
            yield signedData.propset_Content(signInfo[i].data);
            signInfo[i].signedData = yield signedData.Sign(signer);
          }
        }
        finally {
          yield certStore.Close();
        }

        deferred.resolve(signInfo);
      }
      catch (e){
        deferred.reject(cadesplugin.getLastError(e));
      }
    }));
  },

  checkXMLSignAsync: function(deferred, signInfo){
    cadesplugin.async_spawn(dojo.hitch(this, function *(args) {
      try {
        var signedData = yield cadesplugin.CreateObjectAsync("CAdESCOM.SignedXML");

        for (var i = 0; i < signInfo.length; i++) {
          try {
            yield signedData.Verify(signInfo[i].signedData);
            signInfo[i].checkResult = true;
          }
          catch (e){
            signInfo[i].checkResult = false;
            signInfo[i].checkError = cadesplugin.getLastError(e);
          }
        }

        deferred.resolve(signInfo);
      }
      catch (e){
        deferred.reject(cadesplugin.getLastError(e));
      }
    }));
  }
});