// подпись документа
function signDocAfterRequest(cert_id,doc_id,check_sign,emulate_sign)
{   $j('#podpis').removeClass('button_green') ;
    sign_log("4. Запрос документа "+doc_id+" с сервера.....") ;
    $j.ajax({url:'/cab/ajax.php',async:false,type:'POST',dataType:'xml',cache:false,data:{cmd:'cryptopro/get_doc_content',doc_id:doc_id,cert_id:cert_id,check_sign:check_sign,emulate_sign:emulate_sign,sign_uid:sign_uid},success:get_doc_content_success});
}

// подпись МО
function signMoAfterRequest(cert_id,mo_id,check_sign,emulate_sign)
{   $j('#podpis').removeClass('button_green') ;
    sign_log("4. Запрос данных МО "+mo_id+" с сервера.....") ;
    console.log('emulate_sign='+emulate_sign) ;
    var send_data={cmd:'mo_ecp/get_mo_content',
                        mo_id:mo_id,
                        cert_id:cert_id,
                        check_sign:check_sign,
                        emulate_sign:emulate_sign,
                        sign_uid:sign_uid
                       }
    $j.ajax({url:'/cab/ajax.php',async:false,type:'POST',dataType:'xml',cache:false,data:send_data,success:get_mo_content_success});
}

// подпись произвольных данных
function signData(cert_id,data_uid,data_to_sign,check_sign,emulate_sign,result_function)
{   $j('#podpis').removeClass('button_green') ;
    if (emulate_sign==1) result=ESMO_emulate_sign(data_uid,'data',result_function)
    else result=ESMO_Common_SignCadesBES_File(cert_id,check_sign,data_uid,'data',data_to_sign,result_function);

    sign_log('sign result:<br>'+result) ;



}

function get_doc_content_success(data2,status,link)
{
    if (status=='success')
         {  var responseXML = link.responseXML;
             if (responseXML==null) return(false) ;
             if (responseXML==undefined) return ;
             var data=convert_XML_to_obj(responseXML) ;

             if (data.doc_content)
             {   //fileContent=data.doc_content ;
                 sign_log("5. Документ "+data.doc_id+" получен с сервера") ;

                 if (data.emulate_sign) ESMO_emulate_sign(data.doc_id,'doc')
                 else ESMO_Common_SignCadesBES_File(data.cert_id,data.check_sign,data.doc_id,'doc',data.doc_content,undefined);
             }

         }
}

function get_mo_content_success(data2,status,link)
{
    if (status=='success')
         {  var responseXML = link.responseXML;
             if (responseXML==null) return(false) ;
             if (responseXML==undefined) return ;
             var data=convert_XML_to_obj(responseXML) ;

             if (data.mo_content)
             {   //fileContent=data.mo_content ;
                 sign_log("5. МО "+data.mo_id+" получен с сервера") ;
                 console.log('data:'+data) ;

                sign_log("data.emulate_sign="+data.emulate_sign) ;

                if (data.emulate_sign==1) ESMO_emulate_sign(data.mo_id,'mo',data.mo_content)
                else ESMO_Common_SignCadesBES_File(data.cert_id,data.check_sign,data.mo_id,'mo',data.mo_content,undefined);
            }

         }
}

var MD5 = function(d){var r = M(V(Y(X(d),8*d.length)));return r.toLowerCase()};function M(d){for(var _,m="0123456789ABCDEF",f="",r=0;r<d.length;r++)_=d.charCodeAt(r),f+=m.charAt(_>>>4&15)+m.charAt(15&_);return f}function X(d){for(var _=Array(d.length>>2),m=0;m<_.length;m++)_[m]=0;for(m=0;m<8*d.length;m+=8)_[m>>5]|=(255&d.charCodeAt(m/8))<<m%32;return _}function V(d){for(var _="",m=0;m<32*d.length;m+=8)_+=String.fromCharCode(d[m>>5]>>>m%32&255);return _}function Y(d,_){d[_>>5]|=128<<_%32,d[14+(_+64>>>9<<4)]=_;for(var m=1732584193,f=-271733879,r=-1732584194,i=271733878,n=0;n<d.length;n+=16){var h=m,t=f,g=r,e=i;f=md5_ii(f=md5_ii(f=md5_ii(f=md5_ii(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_ff(f=md5_ff(f=md5_ff(f=md5_ff(f,r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+0],7,-680876936),f,r,d[n+1],12,-389564586),m,f,d[n+2],17,606105819),i,m,d[n+3],22,-1044525330),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+4],7,-176418897),f,r,d[n+5],12,1200080426),m,f,d[n+6],17,-1473231341),i,m,d[n+7],22,-45705983),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+8],7,1770035416),f,r,d[n+9],12,-1958414417),m,f,d[n+10],17,-42063),i,m,d[n+11],22,-1990404162),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+12],7,1804603682),f,r,d[n+13],12,-40341101),m,f,d[n+14],17,-1502002290),i,m,d[n+15],22,1236535329),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+1],5,-165796510),f,r,d[n+6],9,-1069501632),m,f,d[n+11],14,643717713),i,m,d[n+0],20,-373897302),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+5],5,-701558691),f,r,d[n+10],9,38016083),m,f,d[n+15],14,-660478335),i,m,d[n+4],20,-405537848),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+9],5,568446438),f,r,d[n+14],9,-1019803690),m,f,d[n+3],14,-187363961),i,m,d[n+8],20,1163531501),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+13],5,-1444681467),f,r,d[n+2],9,-51403784),m,f,d[n+7],14,1735328473),i,m,d[n+12],20,-1926607734),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+5],4,-378558),f,r,d[n+8],11,-2022574463),m,f,d[n+11],16,1839030562),i,m,d[n+14],23,-35309556),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+1],4,-1530992060),f,r,d[n+4],11,1272893353),m,f,d[n+7],16,-155497632),i,m,d[n+10],23,-1094730640),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+13],4,681279174),f,r,d[n+0],11,-358537222),m,f,d[n+3],16,-722521979),i,m,d[n+6],23,76029189),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+9],4,-640364487),f,r,d[n+12],11,-421815835),m,f,d[n+15],16,530742520),i,m,d[n+2],23,-995338651),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+0],6,-198630844),f,r,d[n+7],10,1126891415),m,f,d[n+14],15,-1416354905),i,m,d[n+5],21,-57434055),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+12],6,1700485571),f,r,d[n+3],10,-1894986606),m,f,d[n+10],15,-1051523),i,m,d[n+1],21,-2054922799),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+8],6,1873313359),f,r,d[n+15],10,-30611744),m,f,d[n+6],15,-1560198380),i,m,d[n+13],21,1309151649),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+4],6,-145523070),f,r,d[n+11],10,-1120210379),m,f,d[n+2],15,718787259),i,m,d[n+9],21,-343485551),m=safe_add(m,h),f=safe_add(f,t),r=safe_add(r,g),i=safe_add(i,e)}return Array(m,f,r,i)}function md5_cmn(d,_,m,f,r,i){return safe_add(bit_rol(safe_add(safe_add(_,d),safe_add(f,i)),r),m)}function md5_ff(d,_,m,f,r,i,n){return md5_cmn(_&m|~_&f,d,_,r,i,n)}function md5_gg(d,_,m,f,r,i,n){return md5_cmn(_&f|m&~f,d,_,r,i,n)}function md5_hh(d,_,m,f,r,i,n){return md5_cmn(_^m^f,d,_,r,i,n)}function md5_ii(d,_,m,f,r,i,n){return md5_cmn(m^(_|~f),d,_,r,i,n)}function safe_add(d,_){var m=(65535&d)+(65535&_);return(d>>16)+(_>>16)+(m>>16)<<16|65535&m}function bit_rol(d,_){return d<<_|d>>>32-_}

function ESMO_emulate_sign(doc_id,sign_mode,result_function,dataToSign)
{   sign_log("6. Документ "+doc_id+" передан на подпись ЭМУЛЯТОРУ ЭЦП") ;

    // извлекаем данные из подписи
    var ajax_params={}
    ajax_params.cert={} ;
    ajax_params.cert.sert_id=cert_SerialNumber ;
    ajax_params.cert.SerialNumber=cert_SerialNumber ;
    ajax_params.cert.Thumbprint=cert_Thumbprint ;
    ajax_params.cert.SubjectName=cert_SubjectName ;
    ajax_params.cert.IssuerName=cert_IssuerName ;
    ajax_params.cert.ValidFromDate=cert_ValidFromDate;
    ajax_params.cert.ValidToDate=cert_ValidToDate;


    //var dataToSign = fileContent; // fileContent - объявлен в Code.js
    //var dataToSign64=Base64.encode(dataToSign) ;

    //Signature=MD5(dataToSign64) ;
    Signature=MD5(dataToSign) ;

    // сохраняем подпись в прикрепленном файле
    ajax_params.sign=Signature ;
    if (sign_mode=='file') { ajax_params.fname=openFileButton.value ;   save_signature(ajax_params,sign_mode) ; }
    if (sign_mode=='doc')  { ajax_params.doc_id=doc_id ;                save_signature(ajax_params,sign_mode) ; }
    if (sign_mode=='mo')  { ajax_params.mo_id=doc_id ;                  save_signature(ajax_params,sign_mode) ; }
    if (sign_mode=='data')  { ajax_params.data_uid=doc_id ;           save_signature(ajax_params,sign_mode) ; }

    //console.log('Signature='+Signature) ;

    result_function({status:'success'});

}

function save_signature(ajax_params,sign_mode)
{  sign_log('9. Сохраняем подпись в файл, sign_mode='+sign_mode) ;
   if (sign_mode=='mo') ajax_params.cmd='mo_ecp/save_signature' ;
   else ajax_params.cmd='ecp/save_signature' ;
   ajax_params.sign_mode=sign_mode ;
   ajax_params.sign_uid=sign_uid ;
   ajax_params.card_view_mode=card_view_mode ;
   send_ajax_request(ajax_params);
}

// подпись отдельного файла
function signFile(cert_id,check_sign,emulate_sign)
{   sign_log("Выполняем подпись отдельного файла") ;
    if ('' == openFileButton.value)  { alert('Файл не выбран.'); return; }
    else if ('' == fileContent || undefined == fileContent)  { alert('Выбран пустой файл'); return; }
    else
    {   $j('#podpis').removeClass('button_green') ;
        sign_log("Файл отправлен на подпись") ;
        ESMO_Common_SignCadesBES_File(cert_id,check_sign,0,'file',fileContent,undefined);
    }
}

// подпись произвольгой строки
function check_token(cert_id,check_sign,content)
{   let dataToSign=Base64.encode(content) ; // данные на подпись должны отправляется в кодировке Base64
    $j('div#check_result').html('Ожидайте, выполняется проверка наличия токена ЭЦП и срока действия сертификата пользователя <strong>'+$j(this).attr('account_name')+'</strong>') ;
    $j('div#check_result').html('<img src="/images/loading14.gif" width="400px">') ;
    sign_log("Выполняем проверку наличия токена и срок действия сертификата") ;

    {   $j('#podpis').removeClass('button_green') ;
        sign_log("Контрольные данные отправлены на подпись") ;
        ESMO_Common_SignCadesBES_File(cert_id,check_sign,0,'check_token',dataToSign,undefined);
    }
}

// подпись документа
function ESMO_Common_SignCadesBES_File(cert_uid,check_sign,doc_id,sign_mode,dataToSign,result_function)
{   if (sign_mode=='mo') sign_log("6. МО "+doc_id+" передан на подпись КриптоПро") ;
    else                 sign_log("6. Документ "+doc_id+" передан на подпись КриптоПро") ;
    var canAsync = !!cadesplugin.CreateObjectAsync;
    if (canAsync) {include_async_code().then(function (){return ESMO_SignCadesBES_Async_File(cert_uid,check_sign,doc_id,sign_mode,dataToSign,result_function);});}
}

// сделано на основе функции /AddOns/cryptopro/js_2.1.0/async_code.js  SignCadesBES_Async_File
function ESMO_SignCadesBES_Async_File(cert_uid,check_sign,doc_id,sign_mode,dataToSign,result_function)
{
    cadesplugin.async_spawn(function*(arg)
    {   //sign_log("6.1 ESMO_SignCadesBES_Async_File") ;
        cert_uid=arg[0];
        check_sign=arg[1];
        doc_id=arg[2];
        sign_mode=arg[3];
        dataToSign=arg[4]; // данные для подписи, в формате base64
        result_function=arg[5];

        //sign_log('data_to_sign:<br>'+dataToSign) ;

        var thumbprint = cert_uid.split(" ").reverse().join("").replace(/\s/g, "").toUpperCase();

        try
        {     var oStore = yield cadesplugin.CreateObjectAsync("CAdESCOM.Store");
              if (!oStore) { alert("store failed");
                             return;
                           }
              yield oStore.Open();
        }
        catch (ex)
        {
             alert("Ошибка при открытии хранилища: " + cadesplugin.getLastError(ex));
             return;
        }

        var certCnt;
        var certs;

        try {   certs = yield oStore.Certificates;
                certCnt = yield certs.Count;
            }
        catch (ex)
            {
                 var errormes = document.getElementById("boxdiv").style.display = '';
                 return;
             }

        if(certCnt == 0)
        {
             var errormes = document.getElementById("boxdiv").style.display = '';
             return;
        }

        var all_certs = yield oStore.Certificates;
        var oCerts = yield all_certs.Find(cadesplugin.CAPICOM_CERTIFICATE_FIND_SHA1_HASH, thumbprint);
        var count_found=yield oCerts.Count ;
        //console.log('certificate count found='+count_found) ;
        if (count_found == 0)
        {
            let errormes = "Сертификат не найден в списке личных сертификатов пользователя. Выберите другой сертификат для подписи документа.";
            alert(errormes);
            sign_log(errormes);
            if (result_function) result_function({status:'error', message: errormes});
            return;
        }
        certificate = yield oCerts.Item(1);
        //console.log('certificate:',certificate);
        //console.log('dataToSign:',dataToSign);


        var Signature;
        try
        {
            var errormes = "";
            try
            {
                var oSigner = yield cadesplugin.CreateObjectAsync("CAdESCOM.CPSigner");
            }
            catch (err)
            {
                errormes = "Failed to create CAdESCOM.CPSigner: " + err.number;
                throw new Error(errormes);
            }
            var oSigningTimeAttr = yield cadesplugin.CreateObjectAsync("CADESCOM.CPAttribute");

            var CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME = 0;
            yield oSigningTimeAttr.propset_Name(CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME);
            var oTimeNow = new Date();
            yield oSigningTimeAttr.propset_Value(oTimeNow);
            var attr = yield oSigner.AuthenticatedAttributes2;
            yield attr.Add(oSigningTimeAttr);


            var oDocumentNameAttr = yield cadesplugin.CreateObjectAsync("CADESCOM.CPAttribute");
            var CADESCOM_AUTHENTICATED_ATTRIBUTE_DOCUMENT_NAME = 1;
            yield oDocumentNameAttr.propset_Name(CADESCOM_AUTHENTICATED_ATTRIBUTE_DOCUMENT_NAME);
            yield oDocumentNameAttr.propset_Value("Document Name");
            yield attr.Add(oDocumentNameAttr);

            //console.log(oSigner) ;

            if (oSigner)
            {
                yield oSigner.propset_Certificate(certificate);
            }
            else
            {
                errormes = "Failed to create CAdESCOM.CPSigner";
                throw new Error(errormes);
            }

            var oSignedData = yield cadesplugin.CreateObjectAsync("CAdESCOM.CadesSignedData");
            var CADES_BES = 1;

            // ВНИМАНИЕ!!! данные файла уже в  Base64 при передаче через AJAX
            //var dataToSign = Base64.encode(fileContent); // fileContent - объявлен в Code.js
            //var dataToSign = fileContent; // fileContent - объявлен в Code.js
            //console.log('mode='+mode) ;
            if (dataToSign)
            {   // Данные на подпись ввели
                yield oSigner.propset_Options(cadesplugin.CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN);
                yield oSignedData.propset_ContentEncoding(cadesplugin.CADESCOM_BASE64_TO_BINARY); //
                yield oSignedData.propset_Content(dataToSign);

                try
                {
                    var StartTime = Date.now();
                    //Signature = yield oSignedData.SignCades(oSigner, cadesplugin.CADESCOM_CADES_BES,true);
                    Signature = yield oSignedData.SignCades(oSigner, CADES_BES,true);

                    sign_log("Подпись успешно сформирована") ;
                    sign_log('Signature:<br>'+Signature) ;
                    var EndTime = Date.now();
                    sign_log("Время выполнения: " + (EndTime - StartTime) + " мс") ;

                    // извлекаем данные из подписи
                    var ajax_params={}
                    ajax_params.cert={} ;
                    var Adjust = new CertificateAdjuster();
                    var pubKey = yield certificate.PublicKey();
                    var algo = yield pubKey.Algorithm;
                    var fAlgoName = yield algo.FriendlyName;
                    var oPrivateKey = yield certificate.PrivateKey;
                    var sProviderName = yield oPrivateKey.ProviderName;
                    var Validator = yield certificate.IsValid();

                    ajax_params.cert.sert_id=yield certificate.SerialNumber ;
                    ajax_params.cert.SerialNumber=yield certificate.SerialNumber ;
                    ajax_params.cert.Thumbprint=yield certificate.Thumbprint ;
                    ajax_params.cert.SubjectName=Adjust.GetCertName(yield certificate.SubjectName) ;
                    ajax_params.cert.IssuerName=Adjust.GetIssuer(yield certificate.IssuerName) ;
                    ajax_params.cert.ValidFromDate=Adjust.GetCertDate(yield certificate.ValidFromDate);
                    ajax_params.cert.ValidToDate=Adjust.GetCertDate(yield certificate.ValidToDate);
                    ajax_params.cert.version=yield certificate.Version;
                    ajax_params.cert.algorithm=fAlgoName;
                    ajax_params.cert.provname=sProviderName;
                    ajax_params.cert.IsValid=yield Validator.Result;;
                    ajax_params.cert.HasPrivateKey=yield certificate.HasPrivateKey() ;

                    // сохраняем подпись в прикрепленном файле
                    ajax_params.sign=Signature ;
                    if (sign_mode=='file') { ajax_params.fname=openFileButton.value ;   save_signature(ajax_params,sign_mode) ; }
                    if (sign_mode=='doc')  { ajax_params.doc_id=doc_id ;                save_signature(ajax_params,sign_mode) ; }
                    if (sign_mode=='mo')  { ajax_params.mo_id=doc_id ;                save_signature(ajax_params,sign_mode) ; }
                    if (sign_mode=='data')  { ajax_params.data_uid=doc_id ;           save_signature(ajax_params,sign_mode) ; }

                    //console.log('Signature='+Signature) ;
                    //console.log('check_sign='+check_sign) ;

                    if (check_sign==1)
                     {   console.log('dataToSign='+dataToSign) ;
                         try
                         {   var VerifyResult=yield oSignedData.VerifyCades(Signature,cadesplugin.CADESCOM_CADES_BES,true);
                             console.log(VerifyResult) ;
                             sign_log('Подпись проверена, подтверждена') ;
                         }
                         catch (err)
                             {
                                 alert("Failed to verify signature. Error: " + GetErrorMessage(err));
                                 sign_log('Ошибка проверки подписи:'+ GetErrorMessage(err)) ;
                             }

                     }

                    $j('#button_go_back').addClass('button_green') ;

                       if (sign_mode=='doc')
                       {   // даем 2 сек на запись файла
                           setTimeout(function(){document.location=doc_url ;},2000);
                       }

                       if (sign_mode=='file')
                       {   $j('div#sign_result').html('Вы можете скачать отделенную цифровую подпись по этой ссылке: <a href="/temp/'+basename(fileName)+'.sig">Скачать</a>') ;
                       }

                      // if (sign_mode=='data')
                      // {   $j('div#sign_result').html('Вы можете скачать отделенную цифровую подпись по этой ссылке: <a href="/temp/'+basename(fileName)+'.sig">Скачать</a>') ;
                      // }

                    if (sign_mode=='check_token')
                       {

                           //$j('div#check_result').html('Проверка завершена') ;
                           //if ($j('div#check_result').attr('success_url')!="") $j('div#check_result').html('Проверка завершена, переводим на страницу '.j('div#check_result').attr('success_url')) ;
                           // отправляем данные сертификата, с помощью которого была сделана подпись, на сервер для их верификации
                           // сервер в ответе AJAX впишет ответ в check_result
                           ajax_params.cmd='cryptopro/check_params_sert_of_account' ;
                           ajax_params.account_id=$j('div#check_result').attr('account_id') ;
                           send_ajax_request(ajax_params) ;
                           //ESMO_save_cur_certificate_params(ajax_params.cert.sert_id,{cmd:'cryptopro/check_params_sert_of_account',account_id:account_id}) ;
                           //if ($j('div#check_result').attr('success_url')!="") document.location=$j('div#check_result').attr('success_url') ;

                       }

                    // Вызываем callback с результатом успеха
                    if (result_function) result_function({status:'success', signature: Signature});



                }
                catch (err)
                {
                    errormes = "Не удалось создать подпись из-за ошибки: " + cadesplugin.getLastError(err);
                    throw new Error(errormes);
            }
        }
        }
        catch(err)
        {    sign_log(errormes) ;
            if (result_function) result_function({status:'error', message: errormes});
            //sign_log(err.type+': '+err.message) ;
        }

        yield oStore.Close();

    }, cert_uid,check_sign,doc_id,sign_mode,dataToSign,result_function); //cadesplugin.async_spawn
}

