(function(){
    var yuiDom = YAHOO.util.Dom;
    var yuiEvent = YAHOO.util.Event;
    var yuiAnim = YAHOO.util.Anim;

    SW.domWidget.add({
        id:"zoomImage",
        classSettings:{},
        idSettings:{},
        /**
         * base setttings, if none are provided
         */
        settings:{
            thumbnailImageClassName:"zoomThumb",
            zoomImageClassName:"zoomImage",
            showDelay:0.1,
            hideDelay:0.3,
            showDuration:.2,
            hideDuration:.1,
            showTransition:YAHOO.util.Easing.easeIn,
            hideTransition:YAHOO.util.Easing.easeIn,
            hideNowOnClick:true,
            showAttributes:{
                opacity:{from:0,to:1}
            },
            hideAttributes:{
                opacity:{from:1,to:0}
            },
            setPosition:function(config,e){
                var coords = yuiDom.getXY(config.thumbnailImage);
                yuiDom.setStyle(config.zoomImage,"top",(coords[1] + 12) +"px");
                yuiDom.setStyle(config.zoomImage,"left",(coords[0] + 20) +"px");
            },
            showOnStart:function(config){
                yuiDom.setStyle(config.zoomImage,"opacity",0);
            },
            showOnComplete:function(config){
                // do nothing
            },
            hideOnStart:function(config){
                // do nothing
            },
            hideOnComplete:function(config){
                // do nothing
            },
            onThumbnailImageClick:function(config){
                // do nothing
            },
            onZoomImageClick:function(config){
                // do nothing
            }
        },
        /**
         * global settings, affects all tool tips on a page.
         * @See SW.domWidget.zoomImage.settings
         * @param {Object} globalSettings
         */
        initialize:function(globalSettings){
            this.addSettings(globalSettings,"global",null);
        },
        /**
         * class name based settings. The class must be applied to the trigger,
         * for example <span class="toolTipTrigger customToolTip"></span>.
         * These settinsg will only apply to the "customToolTip".
         * @See SW.domWidget.zoomImage.settings
         * @param {Object} className
         * @param {Object} classSettings
         */
        addClassSettings:function(className,classSettings){
            classSettings.thumbnailIamgeClassName = className;
            this.addSettings(classSettings,"class",className);
        },
        /**
         * id based settings can be useful for specific placement of toolTip for a
         * single element (ie, when the toolTip might display over a select box)
         * @See SW.domWidget.zoomImage.settings
         * @param {Object} id
         * @param {Object} idSettings
         */
        addIdSettings:function(id,idSettings){
            this.addSettings(idSettings,"id",id);
        },
        /**
         * internal function for adding settings.
         * @param {Object} settings
         * @param {Object} type
         * @param {Object} id
         */
        addSettings:function(settings,type,id){
            var curSettings,setting;
            switch(type){
                case "global":
                    curSettings = this.settings;
                    break;
                case "class":
                    curSettings = this.classSettings[id] = {};
                    break;
                case "id":
                    curSettings = this.idSettings[id] = {};
                    break;
            }
            if(curSettings && settings){
                for(setting in settings){
                    curSettings[setting] = settings[setting];
                }
            }
        },
        /**
         * internal method to lookup a specific setting
         * @param {Object} config
         * @param {Object} setting
         */
        getSetting:function(config,setting){
            if(config.idSettings && typeof config.idSettings[setting] != "undefined"){
                return config.idSettings[setting];
            }
            if(config.classSettings && typeof config.classSettings[setting] != "undefined"){
                return config.classSettings[setting];
            }
            return this.settings[setting];
        },
        load:function(){
            this.getElements();
        },
        update:function(root){
            this.getElements(root);
        },
        /**
         * find the tool tips
         * @param {Object} root
         */
        getElements:function(root){
            var self = this;
            var el,config,className,id;
            root = root || document;

            for(id in this.idSettings){
                el = yuiDom.get(id);
                if(el){
                    config = {
                        idSettings:this.idSettings[id]
                    };
                    for(className in this.classSettings){
                        if(yuiDom.hasClass(el,className)){
                            config.classSettings = this.classSettings[className];
                            break;
                        }
                    }
                    self.setup(el);
                }
            }

            for(className in this.classSettings){
                config = {
                    classSettings:this.classSettings[className]
                };
                yuiDom.getElementsByClassName(className,"img",root).forEach(function(element){
                    self.setup(element);
                });
            }

            config = {};
            yuiDom.getElementsBy(self.isZoomImg,"img",root).forEach(function(element){
                self.setup(element);
            });
        },
        /**
         * initialize single tool tip
         * @param {Object} trigger
         */
        setup:function(thumb){
            var classSettings = null,idSettings = null;
            var zoomImg;
            var animIn,animOut;
            var self = this;
            var primaryElements = [];
            if(!this.getConfig(thumb)){
                if(thumb.id && this.idSettings[thumb.id]){
                    idSettings = this.idSettings[thumb.id];
                }
                for(var prop in this.classSettings){
                    if(yuiDom.hasClass(thumb,prop)){
                        classSettings = this.classSettings[prop];
                        break;
                    }
                }
                /**
                 * config object is attached to all important elements using this.setConfig();
                 * this contains all pertinent information about this instance.
                 */
                var config = {
                    src:thumb.getAttribute("zoomsrc"),
                    thumbnailImage:thumb,
                    zoomImage:null,
                    isShowing:false,
                    isOver:false,
                    showTimeout:null,
                    hideTimeout:null,
                    classSettings:classSettings,
                    idSettings:idSettings
                };

                zoomImg = document.createElement("img");
                yuiDom.addClass(zoomImg,this.getSetting(config,"zoomImageClassName"));
                yuiDom.addClass(thumb,this.getSetting(config,"thumbnailImageClassName"));

                config.zoomImage = zoomImg;
                document.body.appendChild(zoomImg);

                animIn = new yuiAnim(zoomImg,this.getSetting(config,"showAttributes"),this.getSetting(config,"showDuration"),this.getSetting(config,"showTransition"));
                animIn.onStart.subscribe(function(){
                    self.getSetting(config,"showOnStart")(config);
                    yuiDom.addClass(config.zoomImage,"zoomImageShowing");
                });
                animIn.onComplete.subscribe(function(){
                    self.getSetting(config,"showOnComplete")(config);
                });
                animOut = new yuiAnim(zoomImg,this.getSetting(config,"hideAttributes"),this.getSetting(config,"hideDuration"),this.getSetting(config,"hideTransition"));
                animOut.onStart.subscribe(function(){
                    self.getSetting(config,"hideOnStart")(config);
                });
                animOut.onComplete.subscribe(function(){
                    self.getSetting(config,"hideOnComplete")(config);
                    yuiDom.removeClass(config.zoomImage,"zoomImageShowing");
                });

                config.animIn = animIn;
                config.animOut = animOut;

                primaryElements.push(thumb);
                primaryElements.push(zoomImg);
                this.setConfig(primaryElements,config);
                // in future, could allow config to set mouseover or click for showing
                yuiEvent.addListener(thumb,"mouseover",this.bridge.setShow);
                yuiEvent.addListener(thumb,"mouseout",this.bridge.setHide);
                yuiEvent.addListener(thumb,"click",this.bridge.clickThumb);
                yuiEvent.addListener(zoomImg,"mouseover",this.bridge.clearHide);
                yuiEvent.addListener(zoomImg,"mouseout",this.bridge.setHide);
                yuiEvent.addListener(zoomImg,"click",this.bridge.clickImage);
            }
        },
        /**
         * main internal methods to show and hide tool tips (using timeouts)
         */
        show:function(config){
            if(yuiDom.hasClass(config.zoomImage,"zoomImageShowing")){
                return;
            }
            if(config.isOver && !config.isShowing){
                config.isShowing = true;
                config.animIn.animate();
            }
        },
        hide:function(config){
            config.isShowing = false;
            config.animOut.animate();
        },
        setShow:function(config){
            var self = this;
            config.isOver = true;
            this.clearHide(config);
            if(!config.isShowing){
                if(config.zoomImage.src == ""){
                    config.zoomImage.src = config.src;
                }
                config.showTimeout = setTimeout(function(){
                    self.show(config);
                },this.getSetting(config,"showDelay")*1000);
            }
        },
        setHide:function(config){
            var self = this;
            config.isOver = false;
            if(!config.hideTimeout && config.isShowing){
                clearTimeout(config.showTimeout);
                config.showTimeout = null;
                config.hideTimeout = setTimeout(function(){
                    self.hide(config);
                },this.getSetting(config,"hideDelay")*1000);
            }
        },
        clearHide:function(config){
            if(config.hideTimeout){
                clearTimeout(config.hideTimeout);
                config.hideTimeout = null;
            }
        },
        hideNow:function(config){
            this.hide(config);
        },
        isZoomImg:function(image){
            var zoomSrc = image.getAttribute("zoomsrc");
            return (zoomSrc!=null && zoomSrc!="");
        },
        /**
         * bridging methods to seperate event handlers from main methods
         */
        bridge:{
            setShow:function(e){
                var self = SW.domWidget.zoomImage;
                var config = self.getConfig(this);

                if(!config.isShowing){
                    self.getSetting(config,"setPosition")(config,e);
                }

                self.setShow(config);
            },
            setHide:function(e){
                var self = SW.domWidget.zoomImage;
                var config = self.getConfig(this);
                self.setHide(config);
            },
            clearHide:function(e){
                var self = SW.domWidget.zoomImage;
                var config = self.getConfig(this);
                self.clearHide(config);
            },
            hideNow:function(e){
                var self = SW.domWidget.zoomImage;
                var config = self.getConfig(this);
                self.hideNow(config);
                yuiEvent.stopEvent(e);
            },
            stopEvent:function(e){
                yuiEvent.stopEvent(e);
            },
            clickThumb:function(e){
                var self = SW.domWidget.zoomImage;
                var config = self.getConfig(this);
                self.getSetting(config,"onThumbnailImageClick")(config,e);
            },
            clickImage:function(e){
                var self = SW.domWidget.zoomImage;
                var config = self.getConfig(this);
                if(self.getSetting(config,"hideNowOnClick")){
                    self.hideNow(config);
                }
                self.getSetting(config,"onZoomImageClick")(config,e);
            }
        }
    });

    SW.domWidget.zoomImage.setEnabled(true);

})();

