var ripple = (function(img_src, container) {
    var img = new Image,
        img_data,
        delay = 10,
        width,
        height,
        half_width,
        half_height,
        riprad = 3,
        oldind,
        newind,
        mapind,

        size,
        ripplemap = [],
        last_map = [],
        ripple,
        ripple_data,
        texture,
        texture_data,
        is_running = true,
        is_disturbed = false,
        timer_id,

        canvas = document.createElement('canvas'),
        /** @type {CanvasRenderingContext2D} */
            ctx;

    function init() {
        width = img.width;
        height = img.height;

        half_width = width >> 1;
        half_height = height >> 1;

        size = width * (height + 2) * 2;

        canvas.width = width;
        canvas.height = height;

        oldind = width;
        newind = width * (height + 3);

        /** @type {CanvasRenderingContext2D} */
        ctx = canvas.getContext('2d');
        container.appendChild(canvas);

        ctx.drawImage(img, 0, 0, width, height);
        for (var i = 0; i < size; i++) {
            last_map[i] = ripplemap[i] = 0;
        }

        texture = ctx.getImageData(0, 0, width, height);
        texture_data = texture.data;
        ripple = ctx.getImageData(0, 0, width, height);
        ripple_data = ripple.data;


        canvas.addEventListener('mousemove', function(/* Event */ evt) {
            if (evt.offsetY === undefined) {
                if (evt.layerY < 3 || evt.layerY > height - 3) {
                    return;
                }
            } else {
                if (evt.offsetY < 3 || evt.offsetY > height - 3) {
                    return;
                }
            }
            disturb(evt.offsetX || evt.layerX, evt.offsetY || evt.layerY);
        }, false);

        start();
    }

    function stop() {
        if (timer_id)
            clearInterval(timer_id);
    }

    function start() {
        stop();
        timer_id = setInterval(run, delay);
    }

    function run() {
        if (is_disturbed) {
            newframe(width, height);
            ctx.putImageData(ripple, 0, 0);
        }
    }

    function disturb(dx, dy) {
        dx <<= 0;
        dy <<= 0;
        is_disturbed = true;

        for (var j = dy - riprad; j < dy + riprad; j++) {
            for (var k = dx - riprad; k < dx + riprad; k++) {
                ripplemap[oldind + (j * width) + k] += 512;
            }
        }

//		newframe(width, height);
//		ctx.putImageData(ripple, 0, 0);
    }

    function newframe() {
        var i, a, b, data, cur_pixel, new_pixel, old_data;

        i = oldind;
        oldind = newind;
        newind = i;

        i = 0;
        mapind = oldind;


        var _width = width,
            _height = height,
            _ripplemap = ripplemap,
            _mapind = mapind,
            _newind = newind,
            _last_map = last_map,
            _rd = ripple.data,
            _td = texture.data,
            _half_width = half_width,
            _half_height = half_height,
            _is_disturbed = false;

        for (var y = 0; y < _height; y++) {
            for (var x = 0; x < _width; x++) {
                data = (
                    _ripplemap[_mapind - _width] +
                        _ripplemap[_mapind + _width] +
                        _ripplemap[_mapind - 1] +
                        _ripplemap[_mapind + 1]) >> 1;

                data -= _ripplemap[_newind + i];
                data -= data >> 5;

                _ripplemap[_newind + i] = 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
                    _is_disturbed = true;
                    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];
//					_rd[cur_pixel + 3] = _td[new_pixel + 3];
                }

                ++_mapind;
                ++i;
            }
        }

        mapind = _mapind;
        is_disturbed = _is_disturbed;
    }

    img.onload = init;
    img.src = img_src;

    return {
        start: start,
        stop: stop,
        disturb: disturb
    }
});
