var NodeEffectInterface = {
    show: function (effect) {
        if (this.style.visibility == 'hidden') {
            this.style.visibility = 'visible';
            if (effect instanceof Function) {
                effect.call(this, this, this.show);
            }
        }
    },

    hide: function (effect) {
        if (this.style.visibility != 'hidden') {
            if (effect instanceof Function) {
                effect.call(this, this, this.hide);
            } else {
                this.style.visibility = 'hidden';
            }
        }
    },

    display: function (effect, display) {
//        if (this.style.display == 'none') {
            this.style.display = display ? display : (this._display ? this._display : 'block');
            if (effect instanceof Function) {
                effect.call(this, this, this.display);
            }
//        }
    },

    collapse: function (effect) {
        if (this.style.display != 'none') {
            if (effect instanceof Function) {
                effect.call(this, this, this.collapse);
            } else {
                this._display = this.style.display;
                this.style.display = 'none';
            }
        }
    },

    toggleDisplay: function (effect) {
        if (e.offsetWidth == 0) {
            this.display(effect);
        } else {
            this.collapse(effect);
        }
    },

    remove: function (effect) {
        if (this.parentNode) {
            if (effect instanceof Function) {
                effect(this, this.remove);
            } else {
                this.parentNode.removeChild(this);
            }
        }
    },

    setOpacity: function (opacity) {
        if (IE) {
            this.style.filter = 'Alpha(Opacity="' + (opacity * 100) + '")';
        } else {
            this.style.opacity = opacity;
        }
    },

    getOpacity: function (opacity) {
        if (IE) {
            // ???
        } else {
            return this.style.opacity;
        }
    }
};

var Effects = new Singletone ({
    opacity_delay: 10,
    opacity_step: 0.025,
    blink_delay: 100,
    blink_number: 3,

    opacity: function (object, start, end, finalize, current) {
        self = Effects;

        if (typeof current == 'undefined') {
            current = start;
            object._opacity = object.getOpacity();
        }

        current += self.opacity_step * Math.sign(end - start);
        object.setOpacity(current);

        if (Math.sign(end - start) != 0 && (Math.sign(end - start) == Math.sign(end - current) || !Math.sign(end - current))) {
            setTimeout(function() {self.opacity(object, start, end, finalize, current)}, self.opacity_delay);
        } else {
            object.setOpacity(end);
            if (finalize instanceof Function) {
                finalize.call(object);
                object.setOpacity(object._opacity);
            }
        }
    },

    appear: function (object, finalize) {
        Effects.opacity(object, 0, 1, finalize);
    },

    vanish: function (object, finalize) {
        Effects.opacity(object, 1, 0, finalize);
    },


    blink: function (object, finalize, start, counter) {
        self = Effects;

        if (typeof counter == 'undefined') {
            counter = 0;
            start = !['hidden', 'off'].has(object.style.visibility);
        }
        counter ++;

        if (counter < self.blink_number * 2) {
            object.style.visibility = (counter + start) % 2 ? 'hidden' : 'visible';
            setTimeout(function() {self.blink(object, finalize, start, counter)}, self.blink_delay);
        } else {
            object.style.visibility = start ? 'visible' : 'hidden';
            if (finalize instanceof Function) {
                finalize.call(object);
            }
        }
    },

    move: function (e, x, y, step_x, step_y, acc_x, acc_y, finalize, offset) {
        self = Effects;

        var cur_x = e.coordinates().x;
        var cur_y = e.coordinates().y;
        
        if (!offset) {
            var temp = document.createElement('DIV');
            temp.style.left = '0px';
            temp.style.top = '0px';
            temp.style.position = 'absolute';
            e.parentNode.appendChild(temp);
            var offset = temp.coordinates();
            temp.remove();
        }

        if (!x && x !== 0) {
            x = cur_x;
        }
        if (!y && y !== 0) {
            y = cur_y;
        }
        if (!step_x) {
            step_x = 1;
        }
        if (!step_y) {
            step_y = 1;
        }
        if (!acc_x) {
            acc_x = 1;
        }
        if (!acc_y) {
            acc_y = 1;
        }

        var moved_x = false;
        if (Math.abs(cur_x - x) >= step_x) {
            e.style.left = (cur_x + Math.sign(x - cur_x) * step_x) + 'px';
            moved_x = true;
        } else {
            e.style.left = x - offset.x + 'px';
        }

        var moved_y = false;
        if (Math.abs(cur_y - y) >= step_y) {
            e.style.top = (cur_y + Math.sign(y - cur_y) * step_y) + 'px';
            moved_y = true;
        } else {
            e.style.top = y - offset.y + 'px';
        }

        if (moved_x || moved_y) {
            e.moving = setTimeout(function() {self.move(e, x, y, step_x * acc_x, step_y * acc_y, acc_x, acc_y, finalize, offset)}, 0);
        } else {
            if (finalize instanceof Function) {
                finalize.call(e);
            }
        }
    }

});
