

var Imagezoom = new Class({
    Implements: [Events, Options],

    options: {
        image: false,
        caption: "",
        enableCaptions: true,
        startElement: false,
        x: 10,
        y: 10,
        initWidth: 50,
        initHeight: 50,
        loadImage: false,
        loadDelay: 150,
        duration: 800,
        closeDuration: 500,
        transition: Fx.Transitions.Cubic.easeOut,
        startOpacity: 0.6,
        closeText: 'Close',
        infoText: 'Info',
        rel: 'imagezoom',
        showCaptionBar: true
    },

    initialize: function(options) {
        this.setOptions(options);

        this.box = new Element('div', {
                'class': "imagezoom",
                'styles': {
                    position: "absolute",
                    overflow: "hidden",
                    cursor: "pointer",
                    'background-color': "#F0F0F0"
                },
                'events': { 
                    'click': function() {
                        var fx = new Fx.Morph(this.box, { duration: 200 });
                        fx.start({ opacity: 0 }).chain(function() {
                            this.box.dispose();
                            this.options.container.fireEvent('onHide');
                        } .bind(this));
                    } .bind(this)                                        
                 }
            });
            
        this.box.addEvent('onHide', function() { this.fade("in"); } .bind(this.box));
        this.box.addEvent('onShow', function() { this.fade("out"); } .bind(this.box));        
            
        
        this.imagesHolder = new Element('div', {
            'styles': {
                position: 'absolute',
                overflow: 'hidden',
                top: this.options.container.getStyle('height'),
                left: 0,
                width: '0px',
                height: '0px',
                display: 'none'
            }
        }).injectInside(this.options.container);
    },

    show: function(doFire) {
        if (this.options.image != false) {
            if (doFire) {
                this.options.container.fireEvent('onShow');
            }
            this.box.setAttribute("id", "imagezoom-open-" + this.options.image);

            if (this.options.startElement != false)
                this.options.startElement.blur();

            var x = this.options.x;
            var y = this.options.y;
            var boxWidth = this.options.initWidth;
            var boxHeight = this.options.initHeight;

            if (this.options.startElement != false) {
                x = this.options.startElement.getPosition().x;
                y = this.options.startElement.getPosition().y;
                boxWidth = this.options.startElement.offsetWidth;
                boxHeight = this.options.startElement.offsetHeight;
            }

            this.box.setStyles({
                left: x + "px",
                top: y + "px",
                width: boxWidth + "px",
                height: boxHeight + "px"
            });

            var fx = new Fx.Morph(this.box);
            fx.set({ opacity: this.options.startOpacity });

            this.box.inject($(document.body))
            this.loadImage();
        }
    },

    loadImage: function() {
        delete this.imageObj;
        if (this.box.getElement(".loading") == null) {
            this.options.loadImage.className = "loading";
            this.options.loadImage.inject(this.box);
        }
        if ($('imagezoom-' + this.options.image)) {
            var el = $('imagezoom-' + this.options.image);
            if (el.width = "0") {
                this.imageObj = new Asset.image(this.options.image, { onload: this.insertImage.bind(this) });
            } else {
                this.imageObj = new Image();
                this.imageObj.src = this.options.image;
                this.insertImage.delay(this.options.loadDelay, this);
            }
        } else {
            this.imageObj = new Asset.image(this.options.image, { onload: this.insertImage.bind(this) });
            this.imageObj.setAttribute("id", "imagezoom-" + this.options.image);
            this.imageObj.injectInside(this.imagesHolder)
        }
    },

    insertImage: function() {
        this.box.removeEvents("click");
        this.box.setStyles({ cursor: "default", overflow: "visible" });
        var w = this.imageObj.width;
        var h = this.imageObj.height;
        this.imageObj.setStyles({ width: w + "px", height: h + "px" });
        this.imageObj.className = 'image';
        this.imageObj.setAttribute("title", this.options.title);
        this.imageObj.setAttribute("rel", this.options.caption);

        var fx = new Fx.Morph(this.box, { duration: this.options.duration, transition: this.options.transition });
        fx.start({
            top: (window.getSize().y / 2) + window.getScroll().y - (h / 2),
            left: (window.getSize().x / 2) + window.getScroll().x - (w / 2),
            width: w,
            height: h,
            opacity: 1
        }).chain(function() {
            var close = new Element('div', {
                'class': "close",
                'html': "<span>" + this.options.closeText + "</span>",
                'events': { 'click': function() { this.close(true); } .bind(this) }
            });

            var elements = [close, this.imageObj];
            var caption;
            if (this.options.info !== undefined) {
                if ((this.options.info != "") && (this.options.enableCaptions == true)) {
                    caption = new Element('div', {
                        'class': "caption",
                        'html': "<p>" + this.options.info + "</p>"
                    });
                    this.box.adopt(caption);

                    var cfx = new Fx.Morph(caption, { duration: 200 });
                    cfx.set({ opacity: 0 });

                    var info = new Element('div', {
                        'class': "info",
                        'html': "<span>" + this.options.infoText + "</span>",
                        'events': {
                            'mouseenter': function() { cfx.start({ opacity: 1 }); },
                            'mouseleave': function() { cfx.start({ opacity: 0 }); }
                        }
                    });

                    elements.push(info);
                }
            }

            if (this.options.detail1 !== undefined) {
                if (this.options.detail1 != "") {
                    var info = new Element('div', {
                        'class': "detail1",
                        'html': "<span>" + "Detail" + "</span>",
                        'events': {
                            'click': function() {  
                                var imagezoom = new Imagezoom({
                                    image: this.options.detail1,
                                    startElement: this.box,
                                    container: this.box,
                                    loadImage: this.options.loadImage,
                                    caption: this.options.caption,
                                    title: this.options.title
                                });

                                imagezoom.show(true);                            
                            }.bind(this)
                        }
                    });

                    elements.push(info);
                }
            }

            if (this.options.detail2 !== undefined) {
                if (this.options.detail2 != "") {
                    var info = new Element('div', {
                        'class': "detail2",
                        'html': "<span>" + "Detail" + "</span>",
                        'events': {
                            'click': function() {  
                                var imagezoom = new Imagezoom({
                                    image: this.options.detail2,
                                    startElement: this.box,
                                    container: this.box,
                                    loadImage: this.options.loadImage,
                                    caption: this.options.caption,
                                    title: this.options.title
                                });

                                imagezoom.show(true);                            
                            }.bind(this)
                        }
                    });

                    elements.push(info);
                }
            }

            if (this.options.detail3 !== undefined) {
                if (this.options.detail3 != "") {
                    var info = new Element('div', {
                        'class': "detail3",
                        'html': "<span>" + "Detail" + "</span>",
                        'events': {
                            'click': function() {  
                                var imagezoom = new Imagezoom({
                                    image: this.options.detail3,
                                    startElement: this.box,
                                    container: this.box,
                                    loadImage: this.options.loadImage,
                                    caption: this.options.caption,
                                    title: this.options.title
                                });

                                imagezoom.show(true);                            
                            }.bind(this)
                        }
                    });

                    elements.push(info);
                }
            }

            var loading = this.box.getElement(".loading");
            if (loading) {
                loading.dispose();
            }

            for (var i = 0; i < elements.length; i++) {
                var elFx = new Fx.Morph(elements[i], { duration: 600 });
                elFx.set({ opacity: 0 });
                this.box.adopt(elements[i]);
                elFx.start({ opacity: 1 });
            }

            this.toolTip = new Tips(this.imageObj);
            this.addSetNavigation(this.box);
            this.imageObj.addEvent("click", function() {
                this.close(true);
            } .bind(this));
        } .bind(this));
    },

    addSetNavigation: function(container) {
        var links = $$(document.links).filter(function(link) {
            return ((link.rel) && (link.rel.indexOf(this.options.rel) != -1))
        } .bind(this));
        var set = false;
        for (var i = 0; i < links.length; i++) {
            if ((links[i].href.indexOf(this.options.image) != -1) && (links[i].rel) && (links[i].rel.indexOf(this.options.rel + '[' != -1))) {
                var rel = links[i].getAttribute("rel");
                set = this.scanRel("after", this.options.rel + "[", this.scanRel("before", "]", rel));
            }
        }
        if (set != false) {
            var prevLink = false;
            var nextLink = false;
            var setLinks = new Array();
            for (i = 0; i < links.length; i++) {
                if (links[i].rel.indexOf(this.options.rel + "[" + set + "]") != -1) {
                    setLinks[setLinks.length] = links[i];
                }
            }
            for (i = 0; i < setLinks.length; i++) {
                var link = setLinks[i];
                if ((link.href.indexOf(this.options.image) != -1) && (link.rel) && (link.rel.indexOf(this.options.rel != -1))) {
                    if (i != 0)
                        prevLink = setLinks[i - 1];
                    if (i != setLinks.length - 1)
                        nextLink = setLinks[i + 1];
                }
            }
            if (prevLink != false) {
                this.createNavLink(container, "previous", prevLink);
            }
            if (nextLink != false) {
                this.createNavLink(container, "next", nextLink);
            }
        }
    },

    createNavLink: function(caption, className, link) {
        var button = $(document.createElement("div"));
        button.className = className;
        button.addEvent("click", function() {
            this.close(false);
            link.fireEvent('click');
        } .bind(this));
        button.inject(caption);
    },

    scanRel: function(where, needle, string) {
        var newstring = '';
        if (where == "after") {
            var startpos = string.indexOf(needle) + needle.length;
            var endpos = string.length;
        } else if (where == "before") {
            var startpos = 0;
            var endpos = string.indexOf(needle);
        }
        for (var i = startpos; i < endpos; i++) {
            newstring += string.charAt(i);
        }
        return newstring;
    },

    close: function(doFire) {
        if (doFire) {
            this.options.container.fireEvent('onHide');
        }
        this.box.empty();
        if (this.toolTip != null) {
            this.toolTip.hide();
        }
        var x = this.options.x;
        var y = this.options.y;
        var boxWidth = this.options.initWidth;
        var boxHeight = this.options.initHeight;
        if (this.options.startElement != false) {
            x = this.options.startElement.getPosition().x;
            y = this.options.startElement.getPosition().y;
            boxWidth = this.options.startElement.offsetWidth;
            boxHeight = this.options.startElement.offsetHeight;
        }
        var fx = new Fx.Morph(this.box, { duration: this.options.closeDuration });
        fx.start({
            left: x,
            top: y,
            width: boxWidth,
            height: boxHeight,
            opacity: this.options.startOpacity
        }).chain(function() {
            fx.start({
                opacity: 0
            }).chain(function() {
                this.box.dispose();
            } .bind(this));
        } .bind(this));
    }
})
	Imagezoom.implement(new Options, new Events);
