// itelligent.com.mx, Diciembre 2010

$.fn.pzoom = function (configuration) {

    var options = {
        target: 'img',
        mouseover: {
            p: .015,
            step: 50
        },
        mouseout: {
            p: .17,
            step: 80
        }
    }

    $.extend(options, configuration)

    $(this).each(function () {

        // prepara el contenedor y sus referencias
        var p_width = $(this).width()
        var p_height = $(this).height()

        $(this).css({
            'position': 'relative',
            'top': '0px',
            'left': '0px',
            'overflow': 'hidden'
        })

        var __set = (function (p_width, p_height) { return function (target, width, height) {
            var top = -1 * Math.ceil((height - p_height) / 2);
            var left  = -1 * Math.ceil((width - p_width) / 2);

            var p = $(target).position()

            if(p.top == top || p.left == left)
                return {
                    top: top + 'px',
                    left: left + 'px'
                }

            return {
                'width': width + 'px',
                'height': height + 'px',
                'top': top + 'px',
                'left': left + 'px'
            }
        }})(p_width, p_height)

        // prepara el objetivo y sus referencias
        var parent = $(this)
        var objimg = $(this).find(options.target)

        var ts_width = objimg.width()
        var ts_height = objimg.height()

        objimg
            .css({
                'position': 'absolute',
                'display': 'block'
            })
            .css(__set(objimg[0], ts_width, ts_height))

        // setTimeout y su callback
        var sto = null
        var sto_function = null


        objimg
            .mouseover(function () {
                if($(this).data('__pzoom') == -1)
                    return

                if(sto) {
                    clearTimeout(sto)
                    sto = null
                }

                $(this).data('__pzoom', -1)

                // progresion
                sto_function = (function (target, reference, other) { return function () {
                    if(!$(target).data('__pzoom'))
                        return

                    // estado del objetivo
                    var width = $(target).width()
                    var height = $(target).height()

                    var n_width = n_height = null;
                    var p = options.mouseover.p;

                    do {

                        eval('n_' + reference + ' = ' + reference + ' - Math.ceil((' + reference + ' - p_' + reference + ') * p)')
                        eval('n_' + other + ' = Math.round(n_' + reference + ' * ts_' + other + ' / ts_' + reference + ')')

                        if((n_width - p_width) < 1 || (n_height - p_height) < 1)
                            return

                        p += .01
                    } while((n_width - p_width) % 2 || (n_height - p_height) % 2)

                    $(target).css(__set(target, n_width, n_height))

                    sto = setTimeout(sto_function, options.mouseover.step)

                }})(this, ts_width >= ts_height ? 'height' : 'width', ts_width >= ts_height ? 'width' : 'height')

                sto_function();
            })
            .mouseout(function () {
                if($(this).data('__pzoom') == 1)
                    return;

                if(sto) {
                    clearTimeout(sto)
                    sto = null
                }

                $(this).data('__pzoom', 1)

                sto_function = (function (target, reference, other) { return function () {
                    if(!$(target).data('__pzoom'))
                        return

                    // estado del objetivo
                    var width = $(target).width()
                    var height = $(target).height()

                    var n_width = n_height = null;
                    var p = options.mouseout.p;

                    do {

                        eval('n_' + reference + ' = ' + reference + ' + Math.ceil((ts_' + reference + ' - ' + reference + ') * p)')
                        eval('n_' + other + ' = Math.round(n_' + reference + ' * ts_' + other + ' / ts_' + reference + ')')

                        if((ts_width - n_width) < 1 || (ts_height - n_height) < 1) {
                            $(target).data('__pzoom', 0)
                            return;
                            break;
                        }

                        p += .01
                    } while((n_width - p_width) % 2 || (n_height - p_height) % 2)

                    $(target).css(__set(target, n_width, n_height))

                    sto = setTimeout(sto_function, options.mouseout.step)

                }})(this, ts_width >= ts_height ? 'height' : 'width', ts_width >= ts_height ? 'width' : 'height')

                sto_function();
            })

    })
    
    return this;
}

