const epsilon = 0.1;

const Utils = {
    blobToBase64: blob => {
        const reader = new FileReader();
        reader.readAsDataURL(blob);
        return new Promise(resolve => {
            reader.onloadend = () => {
                resolve(reader.result);
            };
        });
    },

    adjustMinMax(r){
        return {
            x1: Math.min(r.x1, r.x2), x2: Math.max(r.x1, r.x2),
            y1: Math.min(r.y1, r.y2), y2: Math.max(r.y1, r.y2)
        }
    },

    intersectPointRect(p, r){
        //r = this.adjustMinMax(r);
        return p[0] >= r.x1 && p[0] <= r.x2 && p[1] >= r.y1 && p[1] <= r.y2;
    },

    intersectPointLine(p, l){
        //l = this.adjustMinMax(l);
        let dx = l.x2 - l.x1, dy = l.y2 - l.y1;
        let c = dy / dx;
        return this.intersectPointRect(p, l) && c * p[0] - p[1] <= epsilon
    },

    intersectLineRect(l, r){
        return this.intersectPointRect([l.x1, l.y1], r) ||
        this.intersectPointRect([l.x2, l.y2], r);
    },

    intersectRectRect(r1, r2){
        return this.intersectPointRect([r1.x1, r1.y1], r2) ||
            this.intersectPointRect([r1.x1, r1.y2], r2) ||
            this.intersectPointRect([r1.x2, r1.y1], r2) ||
            this.intersectPointRect([r1.x2, r1.y2], r2);
    },

    round(n, p = 2){
        let pp = Math.pow(10, p);
        return Math.round(n*pp)/pp; 
    },

    deg2rad(deg){
        return  deg * (Math.PI / 180);
    },

    rad2deg(rad){
        return rad * 180 / Math.PI;
    },

    shuffleArray(arr){
        return arr.map(value => ({ value, sort: Math.random() }))
        .sort((a, b) => a.sort - b.sort).map(({ value }) => value)
    },

    deepMerge(target, source, transformFn) {
        Object.entries(source).forEach(([key, value]) => {
            if (transformFn){
                value = transformFn(key, value)
            }
            if (value && typeof value === 'object') {
                let dflt = Array.isArray(value) ? [] : {};
                this.deepMerge(target[key] = target[key] || dflt, value, transformFn);
                return;
            }
            target[key] = value;
        });
        return target;
    },

    drawOnCanvas(svg, width, height){
        return new Promise((resolve, reject)=>{
            let url = URL.createObjectURL(new Blob([svg],{ type:"image/svg+xml;charset=utf-8" }));
            let img = new Image();
            let canvas = document.createElement('canvas');
            canvas.width = width;
            canvas.height = height;
            let ctx = canvas.getContext('2d');

            img.addEventListener('load', function () {
                ctx.drawImage(this, 0, 0, canvas.width, canvas.height); 
                URL.revokeObjectURL(url);
                resolve(canvas);
            }, { once: true })
        
            img.src = url;
        })
    },

    async wait(ms, opts = {}){
        await new Promise((resolve, reject)=>{
            opts.id = setTimeout(resolve, ms)
            opts.resolve = resolve;
            opts.reject = reject;
        })
    },

    async killWait(opts){
        if (opts.id){
            clearTimeout(opts.id);
            if (opts.onKill == 'resolve') {
                await opts.resolve()
            }else {
                await opts.reject()
            }
            delete opts.id;
            delete opts.resolve;
            delete opts.reject;
        }
    },

    async waitFor(expFn){
        while (!expFn()){
            await Utils.wait(200);
        }
    },
    
    escapeRegExp(string) {
        return string && string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
    },

    toSafeJSON(data){
        data = Utils.deepMerge({}, data, (k, v)=>{
            return k.startsWith('__') ? undefined : v;
        })
        return JSON.stringify(data);
    }
}

export default Utils;