(function (paw) {
    function PawCameraCapture($previewElt, onCaptured, settings) {
        var self = this;

        this.$previewElt = $previewElt;
        this.onCaptured = onCaptured;
        this.settings = paw.lang.append({
            exportFormat: 'image/jpeg'
        }, settings || {});

        this.$cameraInput = null;
        this.imageDataURL = null;
        this.$canvas = null;
        this.jcropAPI = null;

        this.$previewImage = null;
        this.previewCroppedImg = null;

        this.previewImg = null;
        this.originImg = null;
        this.originFinal = null;

        this.filename = null;

        this.onCameraInputChange = function (e) {
            if (e.target.files.length === 0) {
                return;
            }
            var file = e.target.files[0];
            self.filename = file.name;

            if (file) {
                var reader = new FileReader();
                reader.readAsDataURL(file);
                reader.onload = function () {
                    self.imageDataURL = reader.result;

                    if (paw.utils.value.isFunction(self.onCaptured)) {
                        self.onCaptured.apply(self);
                    }
                    self.destroy();
                };
                reader.onerror = function (error) {
                    console.error('Error reading the file:', error);
                    out('Error reading the file:' + error)
                };
            }
        };
    }

    PawCameraCapture.calcScaledDimensions = function (width, height, maxWidth, maxHeight) {
        var aspectRatio = width / height;
        if (width > maxWidth || height > maxHeight) {
            if (width > height) {
                width = maxWidth;

                var sh = width / aspectRatio;
                if (sh > maxHeight) {
                    height = maxHeight;
                    var sw = height * aspectRatio;
                    width = sw;
                }
                else {
                    height = sh;
                }
            } else {
                height = maxHeight;
                var sw = height * aspectRatio;
                if (sw > maxWidth) {
                    width = maxWidth;

                    var sh = width / aspectRatio;
                    height = sh;
                }
                else {
                    width = sw;
                }

            }
        }
        return {
            width: width,
            height: height
        };
    };

    PawCameraCapture.prototype.capture = function () {
        
        this.$cameraInput = $('<input id="cameraInput" style="display: none;" type="file" accept="image/*" name="cameraInput" capture="environment" />');
        this.$cameraInput.on('change', this.onCameraInputChange);
        $('body').append(this.$cameraInput);

        try {
            var input = document.getElementById('cameraInput');
            input.click();
        } catch (error) {
            console.error('Error accessing the camera:', error);
        }
    };

    PawCameraCapture.prototype.destroy = function () {
        this.$cameraInput.off('change', this.onCameraInputChange);
        this.$cameraInput.remove();
    };

    PawCameraCapture.prototype.preview = function () {
        var self = this;
        return this.renderImage().then(function () {
            self.activateCropTool();
        })
    };

    PawCameraCapture.prototype.activateCropTool = function () {
        var self = this;
        this.$previewImage.Jcrop({
            // start off with jcrop-light class
            bgOpacity: 0.5,
            bgColor: 'white',
            addClass: 'jcrop-light',
            onSelect: function (c) {
                self.jcropAPI = this;
            }
        }, function () {
            api = this;
            api.setSelect([0, 0, self.$previewImage.width(), self.$previewImage.height()]);
            api.setOptions({ bgFade: true });
            api.ui.selection.addClass('jcrop-selection');
        });
    };

    PawCameraCapture.prototype.finalize = function () {
        var self = this;
        return this.crop().then(function (blob) {
            return {
                blob: blob,
                filename: self.filename
            };
        });
    };

    PawCameraCapture.prototype.crop = function () {
        var self = this;
        return this.cropImage(this.originImg.src).then(function (croppedImg) {
            self.originFinal = croppedImg;
            return self.originFinal;
        });
    };

    PawCameraCapture.prototype.cropImage = function (imageDataUrl) {
        var self = this;
        var d = paw.utils.async.defer();
        if (this.jcropAPI) {
            var cropData = this.jcropAPI.tellSelect();
            var image = new Image();
            image.src = imageDataUrl;
            image.onload = function () {
                var sw = cropData.w / self.previewImg.width;
                var sh = cropData.h / self.previewImg.height;
                var sx = cropData.x / self.previewImg.width;
                var sy = cropData.y / self.previewImg.height;

                var w = sw * image.width;
                var h = sh * image.height;
                var x = sx * image.width;
                var y = sy * image.height;

                var croppedCanvas = document.createElement('canvas');
                var ctx = croppedCanvas.getContext('2d');
                croppedCanvas.width = w;
                croppedCanvas.height = h;
                ctx.drawImage(image, x, y, w, h, 0, 0, w, h);

                croppedCanvas.toBlob(function (imageBlob) {
                    d.resolve(imageBlob);
                }, self.settings.exportFormat);
            };
        } else {
            console.error('Jcrop API not available');
            d.reject();
        }
        return d.promise;
    };

    PawCameraCapture.prototype.renderImage = function () {
        var self = this;
        var d = paw.utils.async.defer();
        self.originImg = new Image();
        self.originImg.onload = function () {
            var dims = PawCameraCapture.calcScaledDimensions(
                self.originImg.width,
                self.originImg.height,
                self.$previewElt.innerWidth(),
                self.$previewElt.innerHeight());

            self.previewImg = new Image();
            self.previewImg.src = self.originImg.src;
            self.previewImg.onload = function(){
                self.previewImg.width = dims.width;
                self.previewImg.height = dims.height;
                self.$previewElt.html(self.previewImg);
                self.$previewImage = $(self.previewImg);
            d.resolve(self.$previewImage);
        };
        };

        self.originImg.src = this.imageDataURL;
        return d.promise;
    };

    PawCameraCapture.prototype.toBlob = function () {
        if (paw.utils.value.notSet(this.originFinal)) {
            return null;
        }
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        
        ctx.globalCompositeOperation = "source-over";

        canvas.width = this.originFinal.width;
        canvas.height = this.originFinal.height;
        ctx.drawImage(this.originFinal, 0, 0);
        return canvas.toBlob();
    };

    paw.mod.camera.CameraCapture = PawCameraCapture;
})(paw);