/**
 * Water ripple effect.
 * Original code (Java) by Neil Wallis 
 * @link http://www.neilwallis.com/java/water.html
 * 
 * @author Sergey Chikuyonok (serge.che@gmail.com)
 * @link http://chikuyonok.ru
 */
(function(){
    var canvas = document.getElementById('c'),
        /** @type {CanvasRenderingContext2D} */
        ctx = canvas.getContext('2d'),
        width = 960,
        height = 400,
        half_width = width >> 1,
        half_height = height >> 1,
        size = width * (height + 2) * 2,
        delay = 30,
        oldind = width,
        newind = width * (height + 3),
        riprad = 3,
        ripplemap = [],
        last_map = [],
        ripple,
        texture,
        line_width = 20,
        step = line_width * 2, 
        count = height / line_width;
        
    canvas.width = width;
    canvas.height = height;
    
    /*
     * Water ripple demo can work with any bitmap image
     */
    var texture, ripple;
    var img = new Image();
    img.onload = function() {
        ctx.drawImage(img, 0, 0, width, height);
        texture = ctx.getImageData(0, 0, width, height);
        ripple = ctx.getImageData(0, 0, width, height);
        
        for (var i = 0; i < size; i++) {
            last_map[i] = ripplemap[i] = 0;
        }
        
        // Start animation loop after image loads
        canvas.onmousemove = function(/* Event */ evt) {
            disturb(evt.offsetX || evt.layerX, evt.offsetY || evt.layerY);
        };
        
        // Touch support for mobile drag
        var touch = {};
        canvas.ontouchstart = function(evt) {
            var t = evt.touches[0];
            var rect = canvas.getBoundingClientRect();
            var scaleX = canvas.width / rect.width;
            var scaleY = canvas.height / rect.height;
            touch.x = (t.clientX - rect.left) * scaleX;
            touch.y = (t.clientY - rect.top) * scaleY;
            disturb(touch.x, touch.y);
        };
        
        canvas.ontouchmove = function(evt) {
            evt.preventDefault();
            var t = evt.touches[0];
            var rect = canvas.getBoundingClientRect();
            var scaleX = canvas.width / rect.width;
            var scaleY = canvas.height / rect.height;
            var x = (t.clientX - rect.left) * scaleX;
            var y = (t.clientY - rect.top) * scaleY;
            
            // Draw ripples along the touch path for drag effect
            var dx = x - touch.x;
            var dy = y - touch.y;
            var dist = Math.sqrt(dx * dx + dy * dy);
            var steps = Math.ceil(dist);
            
            for (var i = 0; i <= steps; i++) {
                var px = touch.x + (dx * i / steps);
                var py = touch.y + (dy * i / steps);
                disturb(px, py);
            }
            
            touch.x = x;
            touch.y = y;
        };
        
        setInterval(run, delay);
        
        // generate random ripples
        var rnd = Math.random;
        setInterval(function() {
            disturb(rnd() * width, rnd() * height);
        }, 700);
    };
    img.src = 'image.png';
    
    /**
     * Main loop
     */
    function run() {
        newframe();
        ctx.putImageData(ripple, 0, 0);
    }
    
    /**
     * Disturb water at specified point
     */
    function disturb(dx, dy) {
        dx <<= 0;
        dy <<= 0;
        
        for (var j = dy - riprad; j < dy + riprad; j++) {
            for (var k = dx - riprad; k < dx + riprad; k++) {
                ripplemap[oldind + (j * width) + k] += 128;
            }
        }
    }
    
    /**
     * Generates new ripples
     */
    function newframe() {
        var a, b, data, cur_pixel, new_pixel, old_data;
        
        var t = oldind; oldind = newind; newind = t;
        var i = 0;
        
        // create local copies of variables to decrease
        // scope lookup time in Firefox
        var _width = width,
            _height = height,
            _ripplemap = ripplemap,
            _last_map = last_map,
            _rd = ripple.data,
            _td = texture.data,
            _half_width = half_width,
            _half_height = half_height;
        
        for (var y = 0; y < _height; y++) {
            for (var x = 0; x < _width; x++) {
                var _newind = newind + i, _mapind = oldind + i;
                data = (
                    _ripplemap[_mapind - _width] + 
                    _ripplemap[_mapind + _width] + 
                    _ripplemap[_mapind - 1] + 
                    _ripplemap[_mapind + 1]) >> 1;
                    
                data -= _ripplemap[_newind];
                data -= data >> 5;
                
                _ripplemap[_newind] = data;

                //where data=0 then still, where data>0 then wave
                data = 1024 - data;
                
                old_data = _last_map[i];
                _last_map[i] = data;
                
                if (old_data != data) {
                    //offsets
                    a = (((x - _half_width) * data / 1024) << 0) + _half_width;
                    b = (((y - _half_height) * data / 1024) << 0) + _half_height;
    
                    //bounds check
                    if (a >= _width) a = _width - 1;
                    if (a < 0) a = 0;
                    if (b >= _height) b = _height - 1;
                    if (b < 0) b = 0;
    
                    new_pixel = (a + (b * _width)) * 4;
                    cur_pixel = i * 4;
                    
                    _rd[cur_pixel] = _td[new_pixel];
                    _rd[cur_pixel + 1] = _td[new_pixel + 1];
                    _rd[cur_pixel + 2] = _td[new_pixel + 2];
                }
                
                ++i;
            }
        }
    }
    
})();