// Some exterior variables and functions, like curr_color_r
// are defined into "brush-helper.js" & "presets.js"



function chrome(a) 
{
    this.init(a)
}

chrome.prototype =
{
    context: null,
    prevMouseX: null,
    prevMouseY: null,
    points: null,
    count: null,
    
    reset: function()
    {
        this.points = new Array();
        this.count = 0;
    },
    
    initContext: function( ctx )
    {
        ctx.lineJoin = "round";
        ctx.lineCap  = "round";
        ctx.lineWidth = curr_line_width;
        ctx.globalCompositeOperation = curr_composite_op;
    },
    
    init: function (a) 
    {
        this.context = a;
        this.reset();
    },
    
    destroy: function () { },
    
    strokeStart: function (x, y) 
    {
        this.initContext( this.context );
        this.prevMouseX = x;
        this.prevMouseY = y;
    },
    
    stroke: function (x, y) 
    {
        var b, a, g;
        this.points.push([x, y]);
        this.context.beginPath();
        this.context.moveTo(this.prevMouseX, this.prevMouseY);
        this.context.lineTo(x, y);
        this.context.stroke();
                
        for( var i = 0; i < this.points.length; i++ )
        {
            b = this.points[i][0] - this.points[this.count][0];
            a = this.points[i][1] - this.points[this.count][1];
            g = b * b + a * a;

            if (g < 1000) 
            {
                //this.context.strokeStyle = color_rnd_str( 0.1 );
                this.context.strokeStyle = color_rnd_str_verb( curr_color_r, curr_color_g, curr_color_b, 0.1*curr_opacity );
                
                this.context.beginPath(); 
                this.context.moveTo(this.points[this.count][0] + (b * 0.2), this.points[this.count][1] + (a * 0.2)); 
                this.context.lineTo(this.points[i][0] - (b * 0.2), this.points[i][1] - (a * 0.2)); 
                this.context.stroke()
            }
        }

        this.prevMouseX = x; 
        this.prevMouseY = y;
        this.count++;
    },

    strokeEnd: function (x, y) { }
};

function fur(a) 
{
    this.init(a)
}

fur.prototype =
{
    context: null,
    points: null,
    count: null,

    prevMouseX: null,
    prevMouseY: null,
    
    reset: function()
    {
        this.points = new Array();
        this.count = 0;
    },
    
    initContext: function( ctx )
    {
        ctx.lineJoin = "round";
        ctx.lineCap = "round";
        ctx.lineWidth = curr_line_width;
        ctx.strokeStyle = curr_color_str(0.1*curr_opacity);
    },
    
    init: function (a) 
    {
        this.context = a;
        this.reset();
    },

    destroy: function () { },
    
    strokeStart: function (x, y) 
    {
        this.initContext( this.context );
        this.prevMouseX = x;
        this.prevMouseY = y;
    },
    
    stroke: function (x, y) 
    {
        var b, a, g;
        this.points.push([x, y]);
        
        this.context.beginPath();
        this.context.moveTo(this.prevMouseX, this.prevMouseY);
        this.context.lineTo(x, y); 
        this.context.stroke();
        
        for( var i = 0; i < this.points.length; i++ ) 
        {
            b = this.points[i][0] - this.points[this.count][0];
            a = this.points[i][1] - this.points[this.count][1];
            g = b * b + a * a;
            
            if (g < 2000 && Math.random() > g / 2000) 
            {
                this.context.beginPath();
                this.context.moveTo(x + (b * 0.5), y + (a * 0.5));
                this.context.lineTo(x - (b * 0.5), y - (a * 0.5));
                this.context.stroke();
            }
        }
        
        this.prevMouseX = x;
        this.prevMouseY = y;
        this.count++;
    },

    strokeEnd: function (x, y) { }
};


function longfur(a) 
{
    this.init(a)
}

longfur.prototype =
{
    context: null,
    points: null,
    count: null,
    
    reset: function()
    {
        this.points = new Array();
        this.count = 0;
    },
    
    initContext: function( ctx )
    {
        ctx.lineJoin = "round";
        ctx.lineCap = "round";
        ctx.lineWidth = curr_line_width;
        ctx.globalCompositeOperation = curr_composite_op;
        ctx.strokeStyle = curr_color_str(0.05*curr_opacity);
    },
    
    init: function (a) 
    {
        this.context = a;
        this.reset();
    },
    
    destroy: function () { },
    
    strokeStart: function (x, y) 
    {
        this.initContext( this.context );
    },
    
    stroke: function (x, y) 
    {
        var e, b, a, h;
        this.points.push([x, y]);
        
        for( var i = 0; i < this.points.length; i++ ) 
        {
            e = -Math.random();
            b = this.points[i][0] - this.points[this.count][0];
            a = this.points[i][1] - this.points[this.count][1];
            h = b * b + a * a;

            if (h < 4000 && Math.random() > h / 4000) 
            {
                this.context.beginPath();
                this.context.moveTo(this.points[this.count][0] + (b * e), this.points[this.count][1] + (a * e));
                this.context.lineTo(this.points[i][0] - (b * e) + Math.random() * 2, this.points[i][1] - (a * e) + Math.random() * 2);
                this.context.stroke();
            }
        }
        
        this.count++;
    },
    
    strokeEnd: function (x, y) { }
};


function circles(a) 
{
    this.init(a);
}

circles.prototype =
{
    context: null,
    prevMouseX: null,
    prevMouseY: null,
    points: null,
    count: null,

    reset: function()
    {
        this.points = new Array();
    },

    initContext: function( ctx )
    {
        ctx.lineJoin = "round";
        ctx.lineCap = "round";
        ctx.lineWidth = curr_line_width;
        ctx.globalCompositeOperation = curr_composite_op;
        ctx.strokeStyle = curr_color_str(0.1*curr_opacity);
    },

    init: function (ctx) 
    {
        this.context = ctx;
        this.reset();
    },
    
    destroy: function () { },
    
    strokeStart: function (x, y) 
    {
        this.initContext( this.context );
        this.prevMouseX = x;
        this.prevMouseY = y;
    },
    
    stroke: function ( x, y ) 
    {
        this.points.push([x, y]);
        
        var l = x - this.prevMouseX;
        var k = y - this.prevMouseY;
        var h = Math.sqrt(l * l + k * k) * 2;
        var f = Math.floor(x / 100) * 100 + 50;
        var c = Math.floor(y / 100) * 100 + 50;
        var j = Math.floor(Math.random() * 10);
        var a = h / j;
        
        for (var g = 0; g < j; g++) 
        {
            this.context.beginPath();
            this.context.arc(f, c, (j - g) * a, 0, Math.PI * 2, true);
            this.context.stroke();
        }
        
        this.prevMouseX = x;
        this.prevMouseY = y;
    },
    
    strokeEnd: function (ctx, x, y) { }
};

function grid(a) 
{
    this.init(a)
}

grid.prototype =
{
    context: null,
    
    reset: function()
    {
    },
    
    initContext: function( ctx )
    {
        ctx.lineJoin = "round";
        ctx.lineCap = "round";
        ctx.lineWidth = curr_line_width;
        ctx.globalCompositeOperation = curr_composite_op;
        //if( darker_supported ) 
        //{
        //    ctx.globalCompositeOperation = "darker"
        //}
        ctx.strokeStyle = curr_color_str(0.01*curr_opacity);
    },
    
    init: function (a) 
    {
        this.context = a;
    },
    
    destroy: function () { },
    
    strokeStart: function (x, y) 
    {
        this.initContext( this.context );
    },
    
    stroke: function (x, y) 
    {
        var a = Math.round(x / 100) * 100;
        var g = Math.round(y / 100) * 100;
        var c = (a - x) * 10;
        var b = (g - y) * 10;

        for( var e = 0; e < 50; e++ ) 
        {
            this.context.beginPath();
            this.context.moveTo(a, g);
            this.context.quadraticCurveTo(x + Math.random() * c, y + Math.random() * b, a, g);
            this.context.stroke()
        }
    },
    
    strokeEnd: function (x, y) { }
};


function bargs(c) {
    var b, a = [];
    for (b = 1; b < arguments.length; b++) {
        a.push(arguments[b]);
    }

    return function () {
        return c.apply(this, a)
    }
}

function ribbon(a) 
{
    this.init(a)
}

ribbon.prototype =
{
    context: null,
    mouseX: null,
    mouseY: null,
    painters: null,
    interval: null,
    
    reset: function()
    {
        if( this.interval )
            clearInterval( this.interval );
    
        this.mouseX = SCREEN_WIDTH / 2; 
        this.mouseY = SCREEN_HEIGHT / 2;
        this.painters = new Array(); 
        
        for( var i = 0; i < 50; i++ ) 
        {
            this.painters.push( { dx: SCREEN_WIDTH / 2, dy: SCREEN_HEIGHT / 2, ax: 0, ay: 0, div: 0.1, ease: Math.random() * 0.2 + 0.6 } )
        }
        
        var self = this;
        
        this.shouldDraw = false;
        this.interval = setInterval(bargs(function (c) { c.update(); return false }, this), 1000 / 60)
        //this.interval = setInterval( function (){ self.update(); return false }, 1000 / 60 );
    },
    
    initContext: function( ctx )
    {
        ctx.lineJoin = "round";
        ctx.lineCap = "round";
        ctx.lineWidth = curr_line_width;
        ctx.strokeStyle = curr_color_str(0.05*curr_opacity);
        ctx.globalCompositeOperation = curr_composite_op;        
    },
    
    init: function (a) 
    {
        this.context = a;
        this.reset();
    },
    
    destroy: function () 
    {
        clearInterval( this.interval );
    },
    
    strokeStart: function (x, y) 
    {
        this.shouldDraw = false;
        //if( this.interval )
        //    clearInterval( this.interval );
    
        this.initContext( this.context );
    
        this.mouseX = x;
        this.mouseY = y;
        
        for (var i = 0; i < this.painters.length; i++) 
        {
            this.painters[i].dx = x;
            this.painters[i].dy = y;
        }
        
        this.shouldDraw = true;
    },

    stroke: function (x, y) 
    {
        this.mouseX = x;
        this.mouseY = y;
        this.shouldDraw = true;
    },

    strokeEnd: function (x, y) { },
    
    update: function () 
    {
        var d = 0;
        
        if( this.shouldDraw )
        for (var i = 0; i < this.painters.length; i++) 
        {
            var painter = this.painters[i];
            
            this.context.beginPath();
            this.context.moveTo( painter.dx, painter.dy );
            painter.ax = (painter.ax + (painter.dx - this.mouseX) * painter.div) * painter.ease;
            painter.ay = (painter.ay + (painter.dy - this.mouseY) * painter.div) * painter.ease;
            painter.dx -= painter.ax;
            painter.dy -= painter.ay;
            d += painter.ax*painter.ax + painter.ay*painter.ay;
            this.context.lineTo( painter.dx, painter.dy); 
            this.context.stroke();
        }
        
        if( d < 1 )
        {
            this.shouldDraw = false;
        }
    }
};


function shaded(a) 
{
    this.init(a)
}

shaded.prototype =
{
    context: null,
    prevMouseX: null,
    prevMouseY: null,
    points: null,
    count: null,
    
    reset: function()
    {
        this.points = new Array();
        this.count = 0;
    },
    
    initContext: function( ctx )
    {
        ctx.lineJoin = "round";
        ctx.lineCap = "round";
        ctx.lineWidth = curr_line_width;
        ctx.globalCompositeOperation = curr_composite_op;
    },
    
    init: function (a) 
    {
        this.context = a;
        this.reset();
    },

    destroy: function () { },
    
    strokeStart: function (x, y) 
    {
        this.initContext( this.context );
        this.prevMouseX = x;
        this.prevMouseY = y;
    },
    
    stroke: function (x, y) 
    {
        var b, a, g;
        this.points.push([x, y]);
        
        for (var i = 0; i < this.points.length; i++) 
        {
            b = this.points[i][0] - this.points[this.count][0];
            a = this.points[i][1] - this.points[this.count][1];
            g = b * b + a * a;

            if (g < 1000) 
            {
                var alpha = (1 - (g / 1000)) * 0.1;
                this.context.strokeStyle = curr_color_str(alpha*curr_opacity);
                this.context.beginPath();
                this.context.moveTo(this.points[this.count][0], this.points[this.count][1]);
                this.context.lineTo(this.points[i][0], this.points[i][1]);
                this.context.stroke();
            }
        }
        
        this.prevMouseX = x;
        this.prevMouseY = y;
        this.count++;
    },
    
    strokeEnd: function (b, a) { }
};

function sketchy(a) 
{
    this.init(a)
}

sketchy.prototype =
{
    context: null,
    prevMouseX: null,
    prevMouseY: null,
    points: null,
    count: null,
    
    reset: function()
    {
        this.points = new Array(); 
        this.count = 0;
    },
    
    initContext: function( ctx )
    {
        ctx.lineJoin = "round";
        ctx.lineCap = "round";
        ctx.lineWidth = curr_line_width;
        ctx.strokeStyle = curr_color_str( 0.05*curr_opacity );
        ctx.globalCompositeOperation = curr_composite_op;
    },
    
    init: function (a) 
    {
        this.context = a;
        this.reset();
    },

    destroy: function () { },
    
    strokeStart: function (x, y) 
    {
        this.initContext( this.context );
        this.prevMouseX = x;
        this.prevMouseY = y;
    },
    
    stroke: function (x, y) 
    {
        var b, a, g;
        this.points.push([x, y]);
        
        this.context.strokeStyle = curr_color_str( 0.05*curr_opacity );

        this.context.beginPath();
        this.context.moveTo(this.prevMouseX, this.prevMouseY);
        this.context.lineTo(x, y);
        this.context.stroke();

        for( var i = 0; i < this.points.length; i++ ) 
        {
            b = this.points[i][0] - this.points[this.count][0];
            a = this.points[i][1] - this.points[this.count][1];
            g = b * b + a * a;
            
            if (g < 4000 && Math.random() > g / 2000)
            {
                this.context.beginPath();
                this.context.moveTo(this.points[this.count][0] + (b * 0.3), this.points[this.count][1] + (a * 0.3));
                this.context.lineTo(this.points[i][0] - (b * 0.3), this.points[i][1] - (a * 0.3));
                this.context.stroke();
            }
        }

        this.prevMouseX = x;
        this.prevMouseY = y;
        this.count++;
    },

    strokeEnd: function (x, y) { }
};


function squares(a) 
{
    this.init(a);
}

squares.prototype =
{
    context: null,
    prevMouseX: null,
    prevMouseY: null,
    
    reset: function()
    {
    },
    
    initContext: function( ctx )
    {
        ctx.lineJoin = "round";
        ctx.lineCap  = "round";
        ctx.globalCompositeOperation = curr_composite_op;
        ctx.strokeStyle = curr_color_str( curr_opacity );
        ctx.fillStyle = curr_color_bg_str( curr_opacity );
        ctx.lineWidth = curr_line_width;
    },
    
    init: function (a) 
    {
        this.context = a;
    },

    destroy: function () { },
    
    strokeStart: function (x, y) 
    {
        this.initContext( this.context );
        this.prevMouseX = x;
        this.prevMouseY = y;
    },

    stroke: function (x, y) 
    {
        var b = x - this.prevMouseX;
        var a = y - this.prevMouseY;
        var g = 1.57079633;
        var e = Math.cos(g) * b - Math.sin(g) * a;
        var c = Math.sin(g) * b + Math.cos(g) * a;
        
        this.context.beginPath();
        this.context.moveTo(this.prevMouseX - e, this.prevMouseY - c);
        this.context.lineTo(this.prevMouseX + e, this.prevMouseY + c);
        this.context.lineTo(x + e, y + c);
        this.context.lineTo(x - e, y - c);
        this.context.lineTo(this.prevMouseX - e, this.prevMouseY - c);
        this.context.fill();
        this.context.stroke();
        this.prevMouseX = x;
        this.prevMouseY = y;
    },

    strokeEnd: function (x, y) { }
};

function web(a) 
{
    this.init(a)
}

web.prototype =
{
    context: null,
    prevMouseX: null,
    prevMouseY: null,
    points: null,
    count: null,
    
    reset: function()
    {
        this.points = new Array();
        this.count = 0
    },
    
    initContext: function( ctx )
    {
        ctx.lineJoin = "round";
        ctx.lineCap = "round";
        ctx.lineWidth = curr_line_width;
        ctx.globalCompositeOperation = curr_composite_op;
        //ctx.strokeStyle = "rgba(0, 0, 0, 0.5)";
        ctx.strokeStyle = curr_color_str( 0.5*curr_opacity );
    },
    
    init: function (a) 
    {
        this.context = a;
        this.reset();
    },
    
    destroy: function () { },
    
    strokeStart: function (x, y) 
    {
        this.initContext( this.context );
        this.prevMouseX = x;
        this.prevMouseY = y;
    },
    
    stroke: function (x, y) 
    {
        var b, a, g;
        this.points.push([x, y]);
        
        this.context.strokeStyle = curr_color_str( 0.5*curr_opacity );

        this.context.beginPath();
        this.context.moveTo(this.prevMouseX, this.prevMouseY); 
        this.context.lineTo(x, y);
        this.context.stroke();
        
        this.context.strokeStyle = curr_color_str( 0.1*curr_opacity );
        
        for (var i = 0; i < this.points.length; i++) 
        {
            b = this.points[i][0] - this.points[this.count][0];
            a = this.points[i][1] - this.points[this.count][1];
            g = b * b + a * a;
            
            if (g < 2500 && Math.random() > 0.9) 
            {
                this.context.beginPath();
                this.context.moveTo(this.points[this.count][0], this.points[this.count][1]);
                this.context.lineTo(this.points[i][0], this.points[i][1]);
                this.context.stroke();
            }
        }

        this.prevMouseX = x;
        this.prevMouseY = y;
        this.count++;
    },
    
    strokeEnd: function (x, y) { }
};


function koch(a) 
{
    this.init(a)
}

koch.prototype =
{
    context: null,
    
    reset: function()
    {
    },
    
    initContext: function( ctx )
    {
        ctx.lineJoin = "round"; 
        ctx.lineCap = "round";
        ctx.lineWidth = curr_line_width;
        ctx.strokeStyle = curr_color_str(0.1*curr_opacity);
    },
    
    init: function (a) 
    {
        this.context = a;
        this.reset();
    },
    
    destroy: function () { },
    strokeStart: function (b, a) 
    {
        this.initContext( this.context );
    },
    
    draw_line: function( x1, y1, x2, y2, v )
    {
        if( 0 == v )
        {
            this.context.beginPath();
            this.context.moveTo(x1, y1);
            this.context.lineTo(x2, y2);
            this.context.stroke();
        }
        else
        {
            var dx = x2-x1;
            var dy = y2-y1;
            var x01 = x1 + dx * 0.3333;
            var x02 = x1 + dx * 0.6667;
            var y01 = y1 + dy * 0.3333;
            var y02 = y1 + dy * 0.6667;
            var x0m = x1 + dx + dy/2;
            var y0m = y1 + dy - dx/2;
            
            this.draw_line( x1, y1, x01, y01, v-1 );
            this.draw_line( x01, y01, x0m, y0m, v-1 );
            this.draw_line( x0m, y0m, x02, y02, v-1 );
            this.draw_line( x02, y02, x2, y2, v-1 );
        }
    },
    
    draw_snow: function( x, y, r, n, a, v )
    {
        var d = Math.PI*2 / n;
        var prev_a = a;
        var next_a = a + d;
        
        var i = 0;
        for( i = 0; i < n; ++i )
        {
            var x1 = x + Math.sin( prev_a ) * r;
            var x2 = x + Math.sin( next_a ) * r;
            var y1 = y + Math.cos( prev_a ) * r;
            var y2 = y + Math.cos( next_a ) * r;
            prev_a = next_a;
            next_a += d;
            
            this.draw_line( x1, y1, x2, y2, v );
        }
    },
    
    stroke: function (x, y) 
    {
        var a = Math.random() * Math.PI * 2;
        var r = Math.random() * 10 + 10;
        var n = Math.round(Math.random() * 4) + 3;
        var v = Math.round(Math.random() * 3) + 2;

        this.draw_snow( x, y, r, n, a, v );
    },

    strokeEnd: function (b, a) { }
};






function drunk_master(a) 
{
    this.init(a)
}

drunk_master.prototype =
{
    context: null,
    prevMouseX: null,
    prevMouseY: null,
    //points: null,
    //count: null,
    
    reset: function()
    {
    },
    
    initContext: function( ctx )
    {
        ctx.lineJoin = "round";
        ctx.lineCap = "round";
        ctx.lineWidth = curr_line_width;
        ctx.strokeStyle = curr_color_str(0.1*curr_opacity); 
    },
    
    init: function (a) 
    {
        this.context = a;
        this.reset();
    },
    
    destroy: function () { },
    strokeStart: function (x, y) 
    {
        this.initContext( this.context );
        this.prevMouseX = x;
        this.prevMouseY = y;
    },

    draw_line: function( x1, y1, x2, y2, turn, v )
    {
        turn = Math.random() * Math.PI * 2;
        
        var dx = x2-x1;
        var dy = y2-y1;

        if( 0 == v )
        {
            this.context.beginPath();
            this.context.moveTo(x1, y1);
            this.context.lineTo(x2, y2);
            this.context.lineTo(x2+(dx>1?dx:1), y2+(dy>1?dy:1));
            
            this.context.stroke();
        }
        else
        {
            var x01 = x1 + dx * 0.3333;
            var x02 = x1 + dx * 0.6667;
            var y01 = y1 + dy * 0.3333;
            var y02 = y1 + dy * 0.6667;
            
            //var x0m = x1 + dx - dy/2;
            //var y0m = y1 + dy - dx/2;
            
            var x0m = x1 + dx / 2;
            var y0m = y1 + dy / 2;
            
            var len = Math.sqrt( dx*dx + dy*dy );
            var a = Math.atan2( dx, dy );
            
            // turn around x0m, y0m by "turn", R = len/3
            var offset = len / 3;
            x0m += Math.sin( a + turn ) * offset;
            y0m += Math.cos( a + turn ) * offset;
            
            this.draw_line( x1,  y1,  x01, y01,  turn, v-1 );
            this.draw_line( x01, y01, x0m, y0m,  turn, v-1 );
            this.draw_line( x0m, y0m, x02, y02,  turn, v-1 );
            this.draw_line( x02, y02, x2,  y2,   turn, v-1 );
        }
    },
    
    stroke: function (x, y) 
    {
        var dx = x - this.prevMouseX;
        var dy = y - this.prevMouseY;
        var dst = Math.sqrt( dx*dx + dy*dy );

        var turn = 0;
        
        var n = Math.round(Math.random() * dst / 3);
        
        if( n > 5 ) n = 5;

        this.draw_line( this.prevMouseX, this.prevMouseY, x, y, turn, n );
        
        this.prevMouseX = x;
        this.prevMouseY = y;
    },

    strokeEnd: function (b, a) { }
};


function eraser(a, width) 
{
    this.init(a, (width) )
}

eraser.prototype =
{
    context: null,
    prevMouseX: null,
    prevMouseY: null,
    width: 1,
    
    cursor: "default",
    
    reset: function()
    {
    },
    
    initContext: function( ctx )
    {
        ctx.lineJoin = "round"; //['round','bevel','miter']; 
        ctx.lineCap  = "butt"; //['butt','round','square'];
        ctx.lineWidth   = this.width; //curr_line_width;
        ctx.strokeStyle = color_str( curr_color_bg_r, curr_color_bg_g, curr_color_bg_b, 0.3*curr_opacity);
        ctx.globalCompositeOperation = "source-over";
    },
    
    init: function (a, width) 
    {
        this.context = a;
        this.width = width;
        this.reset();
    },
    
    destroy: function () { },
    
    strokeStart: function (x, y) 
    {
        this.prevMouseX = x;
        this.prevMouseY = y;
        this.initContext( this.context );
    },

    strokeLine: function( x1, y1, x2, y2, w )
    {
        this.context.lineWidth = w;
        this.context.beginPath();
        this.context.moveTo( x1, y1 );
        this.context.lineTo( x2, y2 );
        this.context.stroke();
    },

    stroke: function (x, y) 
    {
        //this.context.beginPath();
        //this.context.moveTo( this.prevMouseX, this.prevMouseY );
        //this.context.lineTo( x, y );
        //this.context.stroke();
        
        this.strokeLine( this.prevMouseX, this.prevMouseY, x, y, this.width );
        this.strokeLine( this.prevMouseX, this.prevMouseY, x, y, this.width * 0.75 );
        this.strokeLine( this.prevMouseX, this.prevMouseY, x, y, this.width / 2 );
        
        this.prevMouseX = x;
        this.prevMouseY = y;
    },

    strokeEnd: function (x, y) { }
};





