var StyleWriter = new Class({
    // css classes on the fly, based on by Aaaron Newton's version
    createStyle: function(css, id) {
        try {
            if (document.id(id) && id) return;

            var style = new Element('style', {id: id||'',type:'text/css'}).inject($$('head')[0]);
            if (Browser.Engine.trident)
                style.styleSheet.cssText = css;
            else
                style.set('text', css);

        } catch(e) {C.log("failed:", e);}
    }
});

var largerBox = new Class({
    author: "Dimitar Christoff",
    homepage: "http://fragged.org/",
    version: "3.01b",
    changed: "18/11/2009 13:33:45",

    Implements: [Options,Events,StyleWriter],
    options: {
        links: [],                          // pass on array of anchors that contain links to images.
        imageStyles: {
            border: "1px solid #000",       // border style around image,
            background: "#fff",             // useful to have one for underneath a png or gif with transparency
            zIndex: 1000000000,             // default z-index for the enlarged images
            position: "absolute"            // don't change this.
        },
        imageClass: "largerBox",
        imageBorder: 3,
        imageEvents: {
            mouseenter: $empty(),           // function on mouseover.
            mouseleave: $empty()
        },
        shadows: {                          // enlarged image shadow filters, tweak as needed
            enabled: true,
            gecko: {                        // Firefox
                "-moz-box-shadow": "1px 1px 2px #000"
            },
            webkit: {                       // Chrome and Safari
                "-webkit-box-shadow": "1px 1px 2px #000"
            },
            trident: {                      // IE
                "filter": "progid:DXImageTransform.Microsoft.Shadow(color=#000000,direction=135,strength=2)"
            },
            presto: {                       // Opera 10+
                "box-shadow": "1px 1px 2px #000"
            }
        },
        modal: {                            // options to do with modal div.
            enabled: true,
            background: "#fff",             // default colour for modal tint
            zIndex: 1000000000 - 1,
            opacity: .7,
            events: $empty()                // for example, onclick you may want to close all.
        },
        controls: {
            enabled: true,
            useBase64: true,                // look at embeddedStyles at bottom.
            opacity: .6
        },
        closeButton: "/images/button-close.png"
    },
    cache: [],                              // store all loaded images.
    initialize: function(options) {
        this.setOptions(options);
        this.container = $(this.options.container) || $(document.body); // could change this, i suppose.
        this.elements = this.options.links.length ? this.options.links : [];

        // test for base64 support and halt initialize until it's done
        this.testImage = new Element("img", {
            src: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==",
            events: {
                load: function() {
                    this.reInitialize();
                }.bind(this),
                error: function() {
                    this.reInitialize();
                }.bind(this)
            }
        }).inject(this.container);
    },
    reInitialize: function() {
        // initialize, continued after we know of base64 support
        $extend(Browser.Features, {
            base64: this.testImage.width == 1 && this.testImage.height == 1
        });

        if (this.testImage)
            this.testImage.destroy();

        // can we use base64 at all?
        if (this.options.controls.useBase64)
            this.options.controls.useBase64 = (this.options.controls.useBase64 && Browser.Features.base64) ? true : false;

        // kick start it all!
        this.attachAllEvents();

        // add overflow class to css
        this.createStyle(this.options.controls.useBase64 ? this.embeddedStyles[1].join("\n") : this.embeddedStyles[0].join("\n") , "largerBox");
    },
    attachAllEvents: function() {
        // attach all events to this.elements.
        // call this if you have loaded new data into the .elements member to re-init
        this.elements.each(function(el) {
            this.attachEvents(el);
        }.bind(this));
    },
    attachEvents: function(el) {
        // attach events to a single image element.
        el.addEvents({
            mouseenter: function(e) {
                // if we want some hover effect like mini-zoom, shake, etc.
                this.options.imageEvents.mouseenter(el);
            }.bind(this),
            mouseleave: function(e) {
                this.options.imageEvents.mouseleave(el);
            }.bind(this),
            click: function(e) {
                // stop click on href.
                if ($type(e) !== false)
                    new Event(e).stop();

                this.animating = false;
                this.openImage(el);
                this.titleText = el.get("title") || "";
            }.bind(this)
        });
    },
    openImage: function(el) {
        // generic wrapper that kick-starts the opening of an image
        if (this.modal)
            return false;

        if (this.options.modal.enabled)
            this.toggleModal();

        var url = el.get("href"), basename = url.replace(/^.*[\/\\]/g, '');

        // using caching system or import fresh
        if ($type(this.cache[basename]) === "element") {
            this.cache[basename].image.setStyles(this.cache[basename].size);
            this.animateBox(this.cache[basename], el);
        }
        else {
            this.loadImage(url, el); // this will load and then run .animateBox();
        }
    },
    loadImage: function(url, el) {
        new Asset.image(url, {
            onload: function(im) {
                var coords = el.getFirst().getCoordinates(), basename = url.replace(/^.*[\/\\]/g, '');

                this.cache[basename] = {
                    size: {
                        width: im.width,
                        height: im.height
                    },
                    image: im.set({
                        styles: $merge(this.options.imageStyles, coords),
                        events: {
                            click: function() {
                                // this.closeBox(image, coords);

                            }.bind(this)
                        }
                    })
                };

                this.animateBox(this.cache[basename], el);
            }.bind(this)
        });
    },
    animateBox: function(imageObj, link) {
        // gorw the box large!
        if (this.animating)
            return;

        // always works from a cached object, need to preserve .size of original
        // because .width of a static image is set to 0 in IE.
        this.larger = imageObj.image.clone().inject(this.container);
        this.larger.removeEvents().cloneEvents(imageObj.image);

        // find appropriate screen position
        var centerCoords = this.getCenter(imageObj.size.width, imageObj.size.height);

        // save the source coordinates for the close animation
        this.larger.store("coords", link.getFirst().getCoordinates());

        // create an FX instance and store it into image
        this.larger.store("imageEffects", new Fx.Morph(this.larger, {
            transition: Fx.Transitions.Sine.easeOut,
            duration: 300
        }));

        // next/previous, record index of image in array
        this.currentImage = this.elements.indexOf(link);

        // start animation variable
        this.animating = true;

        // run the morph
        this.larger.retrieve("imageEffects").start({
            width: centerCoords.width,
            height: centerCoords.height,
            left: centerCoords.x,
            top: centerCoords.y,
            borderWidth: this.options.imageBorder
        }).chain(function() {
            this.larger.addClass(this.options.imageClass);
            this.animating = false;
            this.addControls(centerCoords);
            this.onComplete();
        }.bind(this));
    },
    onComplete: function() {
        this.fireEvent("complete");

        if ($type(this.options.shadows[Browser.Engine.name]) === "object" && this.options.shadows.enabled === true)
            this.larger.setStyles(this.options.shadows[Browser.Engine.name]);

    },
    addControls: function(coords) {
        // draws the close button, title, next and previous.
        if (!this.animating)
        this.controls = new Element("div", {
            id: "boxClose",
            "class": "cur",
            styles: {
                top: coords.y - 12,
                left: coords.x + coords.width - 12,
                zIndex: this.options.imageStyles.zIndex+2
            },
            title: "click to close",
            events: {
                click: function() {
                    this.closeAuto();
                }.bind(this)
            }
        }).inject(this.container);

        // title and left/ right
        if (this.options.controls.enabled) {
            if (this.titleText.length || this.elements.length) {
                this.titleOverlay = new Element("div", {
                    styles: {
                        width: coords.width - 4,
                        height: 30,
                        padding: 2,
                        background: "#000",
                        position: "absolute",
                        top: coords.y + coords.height - 31,
                        left: coords.x + 3,
                        color: "white",
                        opacity: 0,
                        zIndex: this.options.imageStyles.zIndex+1
                    },
                    html: "<div style='float: left; margin-left: 10px;font-weight:bold;padding-top: 6px'>"+this.titleText+"</div>",
                    events: {
                        mouseleave: function() {
                            this.titleOverlay.fade(.000000009);
                        }.bind(this),
                        mouseenter: function() {
                            this.titleOverlay.fade(this.options.controls.opacity);
                        }.bind(this)
                    }
                }).inject(this.container).fade(0, this.options.controls.opacity);

                if (this.elements.length) {
                    this.goLeft = new Element("div", {
                        id: "arrowLeft",
                        "class": "cur",
                        events: {
                            click: function() {
                                this.getPrevious();
                            }.bind(this)
                        }
                    }).inject(this.titleOverlay, "top");


                    // if (Browser.Engine.trident)
                       // alert(this.goLeft.getStyle("background-image"));

                    this.goRight = new Element("div", {
                        id: "arrowRight",
                        "class": "cur",
                        events: {
                            click: function() {
                                this.getNext();
                            }.bind(this)
                        }
                    }).inject(this.titleOverlay);

                }
            }
        }
    },
    closeBox: function() {
        // shrink image back to coords stored previously
        if (this.animating || !this.larger)
            return false;

        this.animating = true;
        this.modal.removeEvents();
        this.larger.retrieve("imageEffects").setOptions({
            duration: 130
        }).start($merge({
            borderWidth: 0,
            opacity: .4
        }, this.larger.retrieve("coords"))).chain(function() {
            this.animating = false;
        }.bind(this));

        // flash effect
        this.larger.fade(0);

        (function() {
            if (this.options.modal.enabled)
                this.toggleModal();

            if (this.larger) {
                this.larger.destroy();
                delete this.larger;
            }

            this.fireEvent("close");
        }).delay(500, this);
    },
    closeAuto: function() {
        // auto clean up controls and opened images
        if (this.animating)
            return false;

        if (this.controls)
            this.controls.destroy();

        if (this.options.controls.enabled && this.titleOverlay)
            this.titleOverlay.destroy();

        if (this.larger)
            this.closeBox(this.larger);

    },
    getNext: function() {
        // find next image if any
        var next = this.currentImage == this.elements.length - 1 ? 0 : this.currentImage + 1;
        var closeFunc = function() {
            this.removeEvent("close", closeFunc);
            (function() {
                this.elements[next].fireEvent("click");
            }).delay(200, this);
        }.bind(this);

        if (this.larger) {
            this.addEvents({
                close: closeFunc
            });
            this.closeAuto();
        }
    },
    getPrevious: function() {
        // find previous image
        var previous = this.currentImage == 0 ? this.elements.length - 1 : this.currentImage - 1;
        var closeFunc = function() {
            this.removeEvent("close", closeFunc);
            (function() {
                this.elements[previous].fireEvent("click");
            }).delay(200, this);
        }.bind(this);

        if (this.larger) {
            this.addEvents({
                close: closeFunc
            });
            this.closeAuto();
        }
    },
    getCenter: function(width, height) {
        // returns a coordinates JSON for positioning of a box in the centre of the browser
        var winSize = window.getSize(), winScroll = window.getScroll(), windowHeight = window.getScrollHeight()-1, coords = {
            y: Math.round(winScroll.y + (winSize.y / 2) - (height / 2)),
            x: Math.round(winSize.x / 2 - width / 2),
            width: width,
            height: height
        };

        if (coords.y + height + 20 > windowHeight)
            coords.y = windowHeight - 20 - height;

        if (coords.y <= 0)
            coords.y = 20;

        return coords;
    },
    toggleModal: function() {
        // modal view for the whole screen
        if (this.modal) {
            this.container.removeClass("overflowHidden");
            if (Browser.Engine.trident)
                $(document.html).removeClass("overflowHidden");

            this.modal.destroy();
            delete this.modal;
            return false;
        }

        this.container.addClass("overflowHidden");
        if (Browser.Engine.trident)
            $(document.html).addClass("overflowHidden");

        this.modal = new Element("div", {
            styles: {
                position: "absolute",
                top: 0,
                left: 0,
                width: "100%",
                height: "100%",
                background: this.options.modal.background,
                zIndex: this.options.modal.zIndex
            },
            opacity: this.options.modal.opacity,
            events: this.options.modal.events
        }).inject(this.container);

        return this.modal; // can chain into it.
    },
    embeddedStyles: [
        [ // first set is w/o base64 support, css with real files.
            ".overflowHidden { overflow: hidden; }",
            "#arrowLeft {float:left;width:34px;height:100%;background:url(/images/arrow-left.gif) no-repeat center center;}",
            "#arrowRight {float:right;width:34px;height:100%;background:url(/images/arrow-right.gif) no-repeat center center;}",
            "#boxClose {position:absolute;width:32px;height:32px;background:url(/images/button-close.png) no-repeat center center}"
        ],
        [   // css for base64 support
            ".overflowHidden { overflow: hidden; }",
            "#arrowLeft {float:left;width:34px;height:100%;background:url(data:image/gif;base64,R0lGODlhIwAhALMAAAAAADQ0NENDQ25ubouLi6ioqLa2ttPT0/Dw8P///wAAAAAAAAAAAAAAAAAAAAAAACwAAAAAIwAhAAAIpQABCBxIsCCAAAYTKlw4cECCAQwjMnSY4KHEiwQpVrSIUaLGjRw7Kvy4EYEAkSNBljyJ0iDJiiZbulQJk6XMhjQTxLyJk+ZOngBe6rTJU+jPojmTKqXZc6nTpAKFPp0qsMDUqyoHWsWKleBWrk8LfgV5AKjYnGXNakWrdi3NtG3HbjTQtmrOAnUByK2It+7eBH3j5iSQVy5cv3PzegWsuCDExmYDAgA7) no-repeat center center;}",
            "#arrowRight {float:right;width:34px;height:100%;background:url(data:image/gif;base64,R0lGODlhIwAhALMAAAAAADQ0NENDQ25ubouLi6ioqLa2ttPT0/Dw8P///wAAAAAAAAAAAAAAAAAAAAAAACwAAAAAIwAhAAAIpwABCBxIsODAAAYTKlw4cECCAQwjMnSY4KHEiwQpVrSIUaLGjRw7LhSAAORGiCJHljQZMqVBkixbuiQIkyXKmQVrmryJc6BOkDx7Avh5UijNlTsLxlzK1CbBplCb3oxKNSbKqlg3FhCYFetWrl2jfjV6IOZYoWVZnu2Z1uRanG1Bvp1pwKxRgQXs3s2r9i4Avm79EtDrN26CuULrVkRsNC/ju0H99gwIADs%3D) no-repeat center center;}",
            "#boxClose {position:absolute;width:32px;height:32px;background:url(data:image/png;base64,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) no-repeat center center}"
        ]
    ]
}); // end largerBox

var C = {
    // console wrapper
    debug: true, // global debug on|off
    quietDismiss: true, // may want to just drop, or alert instead
    log: function() {
        if (!C.debug) return false;


        if (typeof console == 'object' && typeof console.log != "undefined")
            try {
                console.log.apply(this, arguments); // safari's console.log can't accept scope...
            } catch(e) {
                // so we loop instead.
                for (var i = 0, l = arguments.length; i < l; i++)
                    console.log(arguments[i]);
            }
        else
            if (!C.quietDismiss) {
                var result = "";
                for (var i = 0, l = arguments.length; i < l; i++)
                    result += arguments[i] + " ("+typeof arguments[i]+") ";

                alert(result);
            }
    }
}; // end console wrapper.
