/* Minification failed. Returning unminified contents.
(412,37-38): run-time error JS1100: Expected ',': =
 */
eAssinatura.factory('assinaturaEletronicaService',
    [
        '$http', 'blockService', 'notifyService', 'locale', '$q',
        function ($http, blockService, notifyService, locale, $q) {

            var config = {};
            var Steps = {
                Initial: 0,
                Validate: 1,
                ValidateAndSign: 2,
                ParticipantFields: 2.5,
                ReadyToSign: 3,
                SignDirectly: 4,
                Sign: 5,
                Signed: 6
            };

            var BackendErrorCodes = {
                invalidAccessCode: 278,
                invalidSMSCode: 279
            };

            var canvas;
            var canvasInitialized = false;
            var signaturePad;
            var signRequest;

            var ValidateNullFields = function (identification) {
                var flag = true;
                if (config.identificationType.accessCode &&
                    (identification.accessCode == '' || identification.accessCode == undefined)) {
                    notifyService.error(locale.getString('Util.NotifyMessages.AccessCodeNull'));
                    flag = false;
                }
                if (config.identificationType.sms &&
                    (identification.smsCode == '' || identification.smsCode == undefined)) {
                    notifyService.error(locale.getString('Util.NotifyMessages.SmsCodeNull'));
                    flag = false;
                }
                if (config.identificationType.faceCheck &&
                    (identification.faceCheck == '' || identification.faceCheck == undefined)) {
                    notifyService.error(locale.getString('Util.NotifyMessages.FaceCheckNotConfirmed'));
                    flag = false;
                }
                return flag;
            };

            var GetSignatureStep = function (currentSignatureStep) {

                if (config.signerAlreadySigned ||
                    currentSignatureStep === Steps.ValidateAndSign ||
                    currentSignatureStep > Steps.ReadyToSign) {
                    return Steps.Signed;
                }

                if (currentSignatureStep === Steps.ReadyToSign) {
                    return Steps.Sign;
                }

                var stillNeedsParticipantFields = config.hasToFillParticipantFields &&
                                                  currentSignatureStep !== Steps.ParticipantFields;

                var hasIdentificationMethod = config.hasIdentificationMethod;
                if(!hasIdentificationMethod) {
                    if (stillNeedsParticipantFields) {
                        return Steps.ParticipantFields;
                    }

                    return config.clickThrough ? Steps.SignDirectly : Steps.ReadyToSign;
                }

                var hasToShowDocument = config.showPreview || config.showDownload;
                if (config.clickThrough && !hasToShowDocument) {
                    if (stillNeedsParticipantFields) {
                        return Steps.ParticipantFields;
                    }

                    return Steps.ValidateAndSign;
                }

                var userNotIdentified = !currentSignatureStep || currentSignatureStep === Steps.Initial;
                if(userNotIdentified) {
                    return Steps.Validate;
                }

                if (stillNeedsParticipantFields) {
                    return Steps.ParticipantFields;
                }

                return config.clickThrough ? Steps.SignDirectly : Steps.ReadyToSign;
            };

            // Adjust canvas coordinate space taking into account pixel ratio,
            // to make it look crisp on mobile devices.
            // This also causes canvas to be cleared.
            var ResizeCanvas = function () {
                // When zoomed out to less than 100%, for some very strange reason,
                // some browsers report devicePixelRatio as less than 1
                // and only part of the canvas is cleared then.
                var ratio = Math.max(window.devicePixelRatio || 1, 1);
                canvas.width = canvas.offsetWidth * ratio;
                canvas.height = canvas.offsetHeight * ratio;
                canvas.getContext("2d").scale(ratio, ratio);

                signaturePad.clear();
            };

            var RemoveBlanks = function (canvasObj) {
                var ctx = canvasObj.getContext('2d');

                var imgWidth = ctx.canvas.width;
                var imgHeight = ctx.canvas.height;
                var imageData = ctx.getImageData(0, 0, imgWidth, imgHeight),
                    data = imageData.data,
                    getAlpha = function (x, y) {
                        return data[(imgWidth * y + x) * 4 + 3];
                    },
                    scanY = function (fromTop) {
                        var offset = fromTop ? 1 : -1;

                        // loop through each row
                        for (var y = fromTop ? 0 : imgHeight - 1; fromTop ? (y < imgHeight) : (y > -1); y += offset) {

                            // loop through each column
                            for (var x = 0; x < imgWidth; x++) {
                                if (getAlpha(x, y)) {
                                    return y;
                                }
                            }
                        }
                        return null; // all image is white
                    },
                    scanX = function (fromLeft) {
                        var offset = fromLeft ? 1 : -1;

                        // loop through each column
                        for (var x = fromLeft ? 0 : imgWidth - 1; fromLeft ? (x < imgWidth) : (x > -1); x += offset) {

                            // loop through each row
                            for (var y = 0; y < imgHeight; y++) {
                                if (getAlpha(x, y)) {
                                    return x;
                                }
                            }
                        }
                        return null; // all image is white
                    };
                return canvasObj.toDataURL();
            };

            var SendSmsCall = function (url, request, isExternal) {
                isExternal ? blockService.block() : blockService.block('assinarEletronicoDocumento');
                $http.post(url, request)
                    .then(function (response) {
                        isExternal
                            ? blockService.unblock()
                            : blockService.unblock('assinarEletronicoDocumento');
                        notifyService.success(locale.getString('Util.NotifyMessages.SMSSendWithSuccess'));
                    },
                    function (response) {
                        isExternal
                            ? blockService.unblock()
                            : blockService.unblock('assinarEletronicoDocumento');
                        notifyService.errorModel(response.data,
                            locale.getString('Util.NotifyMessages.FailedToSignDocument'),
                            response.status);
                    });
            };

            var ValidateIdentificationCall = function (url, request, identification, isExternal, skipValidation) {
                var deferred = $q.defer();

                if (skipValidation || ValidateNullFields(identification))
                {
                    isExternal ? blockService.block() : blockService.block('assinarEletronicoDocumento');

                    $http.post(url, request)
                        .then(
                            function (response)
                            {
                                isExternal ? blockService.unblock() : blockService.unblock('assinarEletronicoDocumento');

                                deferred.resolve(GetSignatureStep(Steps.Validate));
                            },
                            function (response, status)
                            {
                                isExternal ? blockService.unblock() : blockService.unblock('assinarEletronicoDocumento');

                                var errorCode = response.data.code;

                                if (config.identificationType.sms && errorCode === BackendErrorCodes.invalidSMSCode)
                                {
                                    notifyService.error(locale.getString('Util.NotifyMessages.ErrorValidatingSmsCode'));
                                    return;
                                }

                                if (config.identificationType.accessCode && errorCode === BackendErrorCodes.invalidAccessCode)
                                {
                                    notifyService.error(locale.getString('Util.NotifyMessages.ErrorValidatingAccessCode'));
                                    return;
                                }

                                notifyService.error(response.data.message);
                            }
                        );
                }
                return deferred.promise;
            };

            var AddLocation = function (location) {
                signRequest.evidences.push({
                    name: 'Geolocation',
                    value: 'Latitude: ' +
                        location.coords.latitude +
                        ' Longitude: ' +
                        location.coords.longitude +
                        ' Accuracy: ' +
                        location.coords.accuracy
                });

                return signRequest;
            };

            var AddLocationErrorMessage = function (error) {
                var errorMsg = '';
                switch (error.code) {
                    case error.PERMISSION_DENIED:
                        errorMsg = "Location not shared by user.";
                        break;
                    default:
                        errorMsg = "Location not available.";
                        break;
                }

                signRequest.evidences.push({ name: 'Geolocation', value: errorMsg });
                return signRequest;
            };

            return {
                SendSms: function (requiredElectronicSignatureId, key, isExternal) {
                    var url = isExternal ? '/API/v2/Signature/SendSMSCodeExtern' : '/API/v2/Signature/SendSMSCode';
                    var request = { requiredElectronicSignatureId: requiredElectronicSignatureId, key: key };
                    SendSmsCall(url, request, isExternal);
                },

                SendSmsDossie: function (userId, key, isExternal) {
                    var url = '/API/v2/Signature/SendSMSCodeExternForDossier';
                    var request = { UserId: userId, key: key };
                    SendSmsCall(url, request, isExternal);
                },

                ValidateIdentification: function (requiredElectronicSignatureId,
                    identification,
                    key,
                    isExternal,
                    inPerson,
                    faceCheckSessionId) {

                    var url = '/API/v2/Signature/ValidateEletronic';
                    var request = {
                        electronicSignerId: requiredElectronicSignatureId,
                        accessCode: identification.accessCode,
                        key: key,
                        smsCode: identification.smsCode,
                        presential: inPerson,
                        isExternal: isExternal,
                        faceCheckSessionId: faceCheckSessionId
                    };

                    return ValidateIdentificationCall(url, request, identification, isExternal, false);
                },

                ValidateIdentificationDossier: function (userId,
                    identification,
                    dossieKey,
                    isExternal,
                    inPerson,
                    faceCheckSessionId) {
                    var url = '/API/v2/Signature/ValidateElectronicDossier';
                    var request = {
                        userId: userId,
                        accessCode: identification.accessCode,
                        dossieKey: dossieKey,
                        smsCode: identification.smsCode,
                        presential: inPerson,
                        faceCheckSessionId: faceCheckSessionId
                    };

                    return ValidateIdentificationCall(url, request, identification, isExternal, false);
                },

                ValidateIdentificationBatch: function (signatures, identifications, faceCheckSessionId) {
                    var signatureInfoList = [];

                    for (var i = 0; i < signatures.length; i++) {
                        signatureInfoList.push({
                            requiredElectronicSignatureId: signatures[i].requiredSignatureId,
                            accessCode: identifications[i].accessCode,
                            smsCode: identifications[i].smsCode,
                            presential: signatures[i].inPerson
                        });
                    }

                    var url = '/API/v2/Signature/ValidateElectronicBatch';
                    var request = {
                        signatureInfoList: signatureInfoList,
                        faceCheckSessionId: faceCheckSessionId
                    };
                    return ValidateIdentificationCall(url, request, null, false, true);
                },

                GetImageCanvas: function (useDefaultImage) {
                    if (signaturePad.isEmpty() && !useDefaultImage) {
                        notifyService.error(locale.getString('Util.NotifyMessages.NoSignatureIdentified'));
                        return;
                    } else {

                        //create a new canvas
                        var newCanvas = document.createElement('canvas');
                        var context = newCanvas.getContext('2d');

                        //set dimensions
                        newCanvas.width = canvas.width;
                        newCanvas.height = canvas.height;

                        //apply the old canvas to the new one
                        context.drawImage(canvas, 0, 0);

                        return RemoveBlanks(newCanvas);
                    }
                },

                Clear: function () {
                    if (signaturePad) {
                        signaturePad.clear();
                        signaturePad.setOriginalWidth(canvas.width);
                        signaturePad.setOriginalHeight(canvas.height);
                        signaturePad.setImgURL("");
                    }
                },

                //InitCanvas depende do quadro estar visivel (ng-show)
                InitCanvas: function () {
                    if (canvasInitialized) {
                        return;
                    }

                    var wrapper = window.document.getElementById("signature-pad");
                    canvas = wrapper.querySelector("canvas");

                    signaturePad = new SignaturePad(canvas,
                        {
                            penColor: "rgb(0, 0, 0)",
                            minWidth: 1,
                            maxnWidth: 1.5
                        });

                    var ResizeCanvas = function () {
                        // When zoomed out to less than 100%, for some very strange reason,
                        // some browsers report devicePixelRatio as less than 1
                        // and only part of the canvas is cleared then.
                        var ratio = Math.max(window.devicePixelRatio || 1, 1);

                        var oldWidth = canvas.width;
                        var oldHeight = canvas.height;

                        canvas.width = canvas.offsetWidth * ratio;
                        canvas.height = canvas.offsetHeight * ratio;

                        canvas.getContext("2d").scale(ratio, ratio);
                        signaturePad.clear();

                        signaturePad.fromDataURLScaling(signaturePad.getImgURL(), oldWidth, oldHeight);

                    };
                    window.onresize = ResizeCanvas;

                    ResizeCanvas();

                    signaturePad.setOriginalWidth(canvas.width);
                    signaturePad.setOriginalHeight(canvas.height);

                    canvasInitialized = true;
                    canvas.setAttribute("initialized", true);
                },

                GetCoordinates: function (deferred) {
                    if (navigator.geolocation) {
                        navigator.geolocation.getCurrentPosition(function (location) {
                            AddLocation(location);
                            deferred.resolve(signRequest);
                        }, function (error) {
                            AddLocationErrorMessage(error);
                            deferred.resolve(signRequest);
                        });
                    } else {
                        AddLocationErrorMessage({ PERMISSION_DENIED: 1, code: -1 });
                        deferred.resolve(signRequest);
                    }
                },

                FillSignatureRequest: function (assinaturaRequeridaId,
                    identification,
                    key,
                    imageDataUrl,
                    isExternal,
                    inPerson,
                    signerId,
                    faceCheckSessionId,
                    removeFaceCheckSessionId,
                    useDefault,
                    signatureTicket = null
                ) {

                    signRequest = {
                        evidences: [],
                        imageBytes: !isNullOrEmpty(imageDataUrl)
                            ? imageDataUrl.substr(imageDataUrl.indexOf(',') + 1)
                            : null,
                        mimeType: !isNullOrEmpty(imageDataUrl) ? 'image/png' : null,
                        key: key,
                        isExternal: isExternal,
                        electronicSignerId: assinaturaRequeridaId,
                        inPerson: inPerson,
                        removeFaceCheckSessionId: removeFaceCheckSessionId,
                        requiredEletronicSignatureId: assinaturaRequeridaId,
                        signatureTicket: signatureTicket
                    };
                    // O campo electronicSignerId deveria ser preenchido apenas quando isExternal = true, portanto a atribuição acima (electronicSignerId: assinaturaRequeridaId) está
                    // conceitualmente errada, porém existem APIs utilizando dessa forma e precisam ser refatoradas para que isso possa ser corrigido.

                    if (isExternal) {                        
                        signRequest.electronicSignerId = signerId;
                    }

                    signRequest.faceCheckSessionId = faceCheckSessionId;
                    signRequest.accessCode = identification.accessCode;
                    signRequest.smsCode = identification.smsCode;
                    signRequest.evidences.push({ name: 'Client Timestamp', value: new Date().toString() });
                    signRequest.useDefaultSignatureImage = !!useDefault;

                    var deferred = $q.defer();
                    this.GetCoordinates(deferred);

                    return deferred.promise;
                },

                FillSignatureDossieRequest: function (userId,
                    identification,
                    key,
                    imageDataUrl,
                    isExternal,
                    inPerson,
                    faceCheckSessionId,
                    dossieKey,
                    removeFaceCheckSessionId) {
                    signRequest = {
                        evidences: [],
                        imageBytes: !isNullOrEmpty(imageDataUrl)
                            ? imageDataUrl.substr(imageDataUrl.indexOf(',') + 1)
                            : null,
                        mimeType: !isNullOrEmpty(imageDataUrl) ? 'image/png' : null,
                        key: key,
                        isExternal: isExternal,
                        electronicSignerId: userId,
                        inPerson: inPerson,
                        dossieKey: dossieKey,
                        removeFaceCheckSessionId: removeFaceCheckSessionId
                    };

                    signRequest.faceCheckSessionId = faceCheckSessionId;
                    if (identification) {
                        signRequest.accessCode = identification.accessCode;
                        signRequest.smsCode = identification.smsCode;
                    }
                    signRequest.evidences.push({ name: 'Client Timestamp', value: new Date().toString() });

                    var deferred = $q.defer();
                    this.GetCoordinates(deferred);

                    return deferred.promise;
                },

                GetSignatureStep: GetSignatureStep,

                ValidateNullFields: ValidateNullFields,

                Initialize: function (info) {

                    canvasInitialized = false;

                    config.allowPreview = !info.somenteHash && (info.isPDF || info.isTxt);
                    config.showPreview = config.allowPreview &&
                        ((!info.visualizarDoc && info.mostrarVisualizar) ? null : info.visualizarDoc);
                    config.showDownload = !config.allowPreview && (info.visualizarDoc || info.mostrarVisualizar);
                    config.clickThrough = !info.permitirGrafiaEmAssinatura;
                    config.identificationType = { 'sms': info.sms, 'accessCode': info.accessCode, faceCheck: info.faceCheck };
                    config.signerAlreadySigned = info.signatarioAssinou;

                    config.hasParticipantFields = info.hasParticipantFields;
                    config.hasToFillParticipantFields = info.hasToFillParticipantFields;

                    config.hasIdentificationMethod = config.identificationType.accessCode || config.identificationType.sms || config.identificationType.faceCheck;

                    return {
                        'Preview': config.showPreview,
                        'Download': config.showDownload,
                        'ParticipantFields': config.hasParticipantFields,
                        'IdentificationMethod': config.hasIdentificationMethod
                    };
                },

                SignatureSteps: Steps

            };


        }
    ]);
;
