'use strict';

const options = {
	background: {
        color: [ 0, 0, 0, 0 ]
    },
    snow: {
        count: 50,
        life: {
            min: 30,
            max: 200
        },
        spawnFrequency: 60,
        color: [ 250, 250, 250 ],
        size: {
            min: 0.5,
            max: 3
        },
        direction: 'right',
        speed: {
            x: {
                min: -1,
                max: 1
            },
            y: {
                min: 2,
                max: 8
            }
        }
    }
};

const max = 700;

const { PI, random } = Math;
const TAU = 2 * PI;
const rand = n => n * random();
const randIn = (min, max) => rand(max - min) + min;
const fadeIn = (t, m) => t / m;
const fadeOut = (t, m) => (m - t) / m;


let canvas;
let ctx;
let tick;
let snowFlakes;

class SnowFlake {
    constructor() {
        this.position = [];
        this.velocity = [];
        this.color = [];
        this.init();
    }
    init() {
        this.ready = true;
        this.size = randIn(options.snow.size.min, options.snow.size.max);
        this.life = 0;
        this.ttl = randIn(options.snow.life.min, options.snow.life.max);
        this.position[0] = rand(canvas.a.width);
        this.position[1] = -this.size;
        this.velocity[0] = randIn(options.snow.speed.x.min, options.snow.speed.x.max);
        this.velocity[1] = randIn(options.snow.speed.y.min, options.snow.speed.y.max);
        this.color = [...options.snow.color, 1];
    }
    checkBounds() {
        return this.position[1] + this.size > canvas.a.height;
    }
    update() {
        (this.life++ > this.ttl || this.checkBounds()) && this.init();
        this.position[0] += this.velocity[0];
        this.position[1] += this.velocity[1];
        this.color[3] = fadeOut(this.life, this.ttl);
    }
    draw() {
        ctx.a.save();
        ctx.a.beginPath();
        ctx.a.fillStyle = rgbaString(...this.color);
        ctx.a.arc(...this.position, this.size, 0, TAU);
        ctx.a.fill();
        ctx.a.closePath();
        ctx.a.restore();

        this.update();
    }
}

function setup() {
    createCanvas();
    resize();
    createSnowFlakes();
    draw();
}

function createCanvas() {
    tick = 0;
    canvas = {
        a: document.createElement('canvas'),
        b: document.createElement('canvas')
    };
    canvas.b.style = `
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
    `;
    document.body.appendChild(canvas.b);
    ctx = {
        a: canvas.a.getContext('2d'),
        b: canvas.b.getContext('2d')
    };
}

function createSnowFlakes() {
    snowFlakes = [];

    let snowFlake;

    for (let i = 0; i < max; i++) {
        snowFlake = new SnowFlake();
        snowFlake.position[0] = rand(canvas.a.width);
        snowFlake.position[1] = rand(canvas.a.height);
        snowFlakes.push(snowFlake);
    }
}

function resize() {
    const { innerWidth, innerHeight } = window;

    canvas.a.width = canvas.b.width = innerWidth;
    canvas.a.height = canvas.b.height = innerHeight;
}

function rgbaString(r, g, b, a = 1) {
    return `rgba(${r},${g},${b},${a})`;
}

function draw() {
    tick++;
    ctx.a.clearRect(0, 0, canvas.a.width, canvas.a.height);
    ctx.b.clearRect(0, 0, canvas.b.width, canvas.b.height);

    ctx.b.fillStyle = rgbaString(...options.background.color);
    ctx.b.fillRect(0, 0, canvas.b.width, canvas.b.height);

    let i, snowFlake;

    console.log(tick % options.snow.spawnFrequency)

    for (i = 0; i < options.snow.count; i++) {
        snowFlake = snowFlakes[i];

        snowFlake.draw();
    }

    ctx.b.drawImage(canvas.a, 0, 0);

    window.requestAnimationFrame(draw);
}

window.addEventListener('load', setup);
window.addEventListener('resize', resize);