

    /* * * * * GadgetWorkspace * * * * */
    INDABA.controls.GadgetWorkspace = Class.create();
    
    INDABA.controls.GadgetWorkspace.prototype = {
        initialize : function(div) {
            this.root = $(div);
            this.workspace = $(this.root).getElementsByClassName("middle")[0];
            this.columns = [];          
            this.gadgets = [];
            this.currentColumn = null;
            this.creationQueue = [];
            
            var columnDivs = $(this.workspace).getElementsByClassName("gadgetColumn");
            this.selector = new INDABA.controls.GadgetSelector({
                root : $('gadget_selector'),
                workspace : this
            });
            for(var i=0; i < columnDivs.length; i++) {
                    this.columns[this.columns.length]={};
                    var index = this.columns.length-1;
                    this.columns[index] = new INDABA.controls.GadgetColumn(
                        columnDivs[i],
                        index,
                        this);                  
            }
            if(User.loggedIn) {
                document.observe("Gadget:onDrag",this.onGadgetDrag);
                document.observe("Gadget:onDragStart",this.onGadgetDragStart);
                document.observe("Gadget:onDragEnd",this.onGadgetDrop); 
                document.observe("Gadget:onDelete",this.onGadgetClose.bind(this));
                document.observe("GadgetSelector:onDrag",this.onGadgetDrag);
                document.observe("GadgetSelector:onDrop",this.onGadgetSelector_drop.bind(this));
            }
        },
        addLazyGadgetToDOM : function(g) {
            for(var i = 0; i < this.columns.length; i++) {
                if(this.columns[i].dropArea) {
                    this.columns[i].addGadget(g);
                }
            }
        },
        addLazyGadgetToQueue : function(g) {
            this.creationQueue.push(g);
            if(this.creationQueue.length == 1) {
                this.createNextGadget();
            }
        },
        createNextGadget : function() {
            if(this.creationQueue.length > 0) {
                var g = this.creationQueue[0];
                g.isTransient = false;
                this.sendUpdatedPositions('create',g);
            }
        },
        updateGadgetIds : function(ids) {
            for(var i = 0; i < this.columns.length; i++) {
                for(var e = 0; e < this.columns[i].gadgets.length; e++) {
                    var id = this.columns[i].gadgets[e].id;
                    if(typeof ids[id] !== "undefined") {
                        this.columns[i].gadgets[e].id = ids[id];
                    }
                }
            }
        },
        findGadgetById : function(id) {
            for(var i = 0; i < this.columns.length; i++) {
                for(var e= 0; e < this.columns[i].gadgets.length; e++) {
                    if(id === this.columns[i].gadgets[e].id) {
                        return this.columns[i].gadgets[e];
                    }
                }
            }
        },
        sendUpdatedPositions : function(action,gadget) {
            
            var s = function(e) { 
                if(e.responseJSON.success) {
                    INDABA.notification.NoteCenter.addNewMessage(
                        new INDABA.notification.UserMessage(INDABA.notification.MessageTypes.Success(),
                        "Successfully saved Gadget Positions",
                        {duration : 5}), INDABA.connection.AJAXQueue.isQueueEmpty()
                    );
                    if(e.responseJSON.update_gadgets) {
                        var newContent = e.responseJSON.update_gadgets._new;
                        
                        

                        gadget.setContent(newContent);
                        
                        // The line below will execute any scripts in <script> blocks inside of gadgets once they are dropped  - ethan
                        // newContent.evalScripts();
                        
                        this.creationQueue.splice(0,1);
                        
                        this.createNextGadget.bind(this);

                    }
                    if(e.responseJSON.update_gadget_ids) {
                        this.updateGadgetIds(e.responseJSON.update_gadget_ids);
                    }
                    if(e.responseJSON.available_gadgets) {
                        document.fire("Gadget:gadgetAdded",{
                            available_gadgets : e.responseJSON.available_gadgets
                        });
                    }
                }
                else {
                    INDABA.notification.NoteCenter.addNewMessage(
                        new INDABA.notification.UserMessage(INDABA.notification.MessageTypes.Error(),
                        "Could not save Gadget Positions.",
                        {duration : 10}, true)
                    );
                }
            };
        
            
            var f = function(e) {
                INDABA.notification.NoteCenter.addNewMessage(
                    new INDABA.notification.UserMessage(
                        INDABA.notification.MessageTypes.Error(),
                        "Could not save Gadget Positions.",
                        {duration : 10}));
                this.creationQueue.splice(0,1);
                this.createNextGadget.bind(this);
            };
            
            if(action ==="create") {
                INDABA.connection.AJAXQueue.addAction(new INDABA.connection.JSONPost({
                    url : '/gadgets/'+action,
                    postBody : $H(this.toJSON()).toJSON(),
                    callback : {
                        success : s,
                        successScope : this,
                        successParam : gadget,
                        failure : f,
                        failureScope : this
                    }
                }));
            }
            else {
                INDABA.connection.AJAXQueue.addAction(new INDABA.connection.JSONPost({
                    url : '/gadgets/'+action,
                    postBody : $H(this.toJSON()).toJSON(),
                    callback : { 
                        success : s,
                        successScope : this,
                        failure : f,
                        failureScope : this
                    }
                }));
            }
        },
        onGadgetClose : function(ev) {
            if(!User.loggedIn) {
                INDABA.notification.NoteCenter.addNewMessage(
                    new INDABA.notification.UserMessage(INDABA.notification.MessageTypes.Error()),
                    "You must be logged in to remove gadgets from your community page.",
                    {duration : 10});
                    return false;
            }
            
            Effect.Fade(ev.memo.gadget.root, {duration:0.5});
            
            var s = function(e) {
                if(e.responseJSON.success) {
                    if(e.responseJSON.update_gadget_ids) {
                        this.updateGadgetIds(e.responseJSON.update_gadget_ids);
                    }
                    ev.memo.gadget.root.parentNode.removeChild(ev.memo.gadget.root);
                    INDABA.notification.NoteCenter.addNewMessage(
                        new INDABA.notification.UserMessage(INDABA.notification.MessageTypes.Success(),
                        "Successfully removed the gadget.",
                        {duration : 5}));
                    return true;
                }
            };
            var f = function(e) {
                
            };
            
            INDABA.notification.NoteCenter.addNewMessage(
                    new INDABA.notification.UserMessage(
                        INDABA.notification.MessageTypes.Notice(),
                        "Removing gadget...",
                        {duration:25}));
            var col = ev.memo.gadget.column;
            col.removeGadget(ev.memo.gadget);
            
            INDABA.connection.AJAXQueue.addAction(new INDABA.connection.JSONPost({
                url : '/gadgets/destroy/'+ev.memo.gadget.id,
                postBody : $H(this.toJSON()).toJSON(),
                callback : {
                    success : s,
                    successScope : this,
                    failure : f,
                    failureScope : this
                }
            }));
            
        },
        onGadgetSelector_drop : function(ev) {
            if(!User.loggedIn) {
                INDABA.notification.NoteCenter.addNewMessage(
                    new INDABA.notification.UserMessage(INDABA.notification.MessageTypes.Error(),
                    "You must be logged in to add new gadgets to your community page."),
                    {duration : 10});
                    return false;
            }
            var dragEvent = ev.memo.dragEvent;
            var selector = ev.memo.gadget;
            var workspace = selector.workspace;
            var lazyGadget = new INDABA.controls.LazyGadget({
                gadgetType : ev.memo.type,
                readableType : ev.memo.readableType,
                column : workspace.columns[i],
                workspace : selector.workspace,
                isTransient : true
            });
            
            workspace.addLazyGadgetToDOM(lazyGadget);
            workspace.addLazyGadgetToQueue(lazyGadget);
            
                for(var i = 0; i < workspace.columns.length; i++) {
                    for(var e = 0; e < workspace.columns[i].length;e++) {
                        workspace.columns[i].gadgets[e].root.style.position = "static";
                    }
                }
                workspace.resetColumnHeights();

        },
        onGadgetDragStart : function(ev) {
            var gadget = ev.memo.gadget;
            var dragEvent = ev.memo.dragEvent;
            var validAreaObject = gadget.workspace;
            $(gadget.root).setStyle({
                position:"absolute"
            });

            var currentColumn = gadget.column.index;
            
            $(gadget.root).remove();
            $(validAreaObject.workspace).insert(gadget.root);
        },
        onGadgetDrag : function(ev) {
            var scrollOffset = document.viewport.getScrollOffsets();        
            var gadget = ev.memo.gadget;
            var dragEvent = ev.memo.dragEvent;
            var validAreaObject = gadget.workspace;
            var clientX = scrollOffset.left + dragEvent.clientX;
            var clientY = scrollOffset.top + dragEvent.clientY;
            
            if(validAreaObject.containsPoint(clientX,clientY)) {
                for(var i = 0; i < validAreaObject.columns.length; i++) {
                    if(validAreaObject.columns[i].containsX(clientX)) {
                        if(null === validAreaObject.currentColumn) {
                            validAreaObject.columns[i].onDragOver(gadget,validAreaObject.columns[i],dragEvent);
                            validAreaObject.currentColumn = i;
                        }                       
                        else if(validAreaObject.currentColumn !== i) {
                            validAreaObject.columns[validAreaObject.currentColumn].onDragOut(gadget,dragEvent);
                            validAreaObject.columns[i].onDragOver(gadget,validAreaObject.columns[i],dragEvent);
                            validAreaObject.currentColumn = i;
                        }
                        else {
                            validAreaObject.columns[i].onDragOver(gadget,validAreaObject.columns[i],dragEvent);
                        }
                    }
                }           
            }
        },
        onGadgetDrop : function(ev) {
            var dragEvent = ev.memo.dragEvent;
            var gadget = ev.memo.gadget;
            var column = gadget.column;
            var workspace = gadget.workspace;

            //find the droparea
            if(!(function(){
                    for(var i = 0; i < workspace.columns.length; i++) {
                        if(workspace.columns[i].dropArea) {
                            column.removeGadget(gadget);
                            workspace.columns[i].addGadget(gadget);
                            if(!User.loggedIn) {
                                INDABA.notification.NoteCenter.addNewMessage(
                                    new INDABA.notification.UserMessage(INDABA.notification.MessageTypes.Error(),
                                    "You must be logged in to save gadget positions.",
                                    {duration : 10}), true);
                                return true;
                            }
                            INDABA.notification.NoteCenter.addNewMessage(
                                new INDABA.notification.UserMessage(INDABA.notification.MessageTypes.Notice(),
                                    "Saving Gadget Positions...",
                                    {duration : 20}
                                ), true
                            );
                            workspace.sendUpdatedPositions("update_positions");
                            return true;
                        }
                    }
                    return false;
                })()) {
            // if no drop area, stick it back where it came from
                    column.resetGadget(gadget);
            }
            for(var i = 0; i < workspace.columns.length; i++) {
                for(var e = 0; e < workspace.columns[i].length; e++) {
                    workspace.columns[i][e].root.style.position = "static";
                }
            }   
            $(gadget.root).setStyle({
                position : "static",
                left : "",
                right : "",
                top : "",
                bottom : ""         
            });
            workspace.resetColumnHeights();
            

        },
        containsPoint : function(x,y) {
            var edges = {
                top : $(this.root).cumulativeOffset().top,
                left : $(this.root).cumulativeOffset().left,
                right : $(this.root).cumulativeOffset().left + $(this.root).getWidth(),
                bottom : $(this.root).cumulativeOffset().top + $(this.root).getHeight()
            };
            if(
                y > edges.top &&
                y < edges.bottom &&
                x > edges.left &&
                x < edges.right){
                    return true;
            }
            else {
                return false;
            }
        },
        calculateColumnHeights : function() {
        },
        resetColumnHeights : function() {
            for(var i = 0; i < this.columns.length; i++) {
                $(this.columns[i].root).setStyle({height:""});
            }
        },
        toJSON : function() {
            var arr = [];
            for(var i = 0; i < this.columns.length; i++) {
                arr = arr.concat(this.columns[i].toJSON());
            }
            return {gadgets : arr};
        },
        generateUniqueIDFromType : function(type) {
            return 0;
        }
    };
    
    /* * * * * GadgetColumn * * * * */
    
    INDABA.controls.GadgetColumn = Class.create();
    
    INDABA.controls.GadgetColumn.prototype = {
        initialize : function(div,index,workspace) {
            this.index = index;
            this.root = div;
            $(this.root).addClassName('c_'+this.index);
            this.gadgets = [];
            this.lazyGadgets = [];
            this.workspace = workspace;
            this.dropArea = null;
            var gadgetCollection = $(this.root).getElementsByClassName('gadget');
            for(var e = 0; e < gadgetCollection.length; e++) {
                this.gadgets[e] = new INDABA.controls.Gadget({
                    root : gadgetCollection[e],
                    column : this,
                    index : e,
                    workspace : this.workspace
                });
            }           
        },
        toJSON : function() {
            var arr = [];
            for(var i = 0; i < this.gadgets.length; i++) {
                if(!this.gadgets[i].isTransient) {
                    arr.push(this.gadgets[i].toJSON());
                }
            }
            return arr;
        },
        containsX : function(x) {
            var leftEdge = $(this.root).cumulativeOffset().left;
            var rightEdge = leftEdge + $(this.root).getWidth();
            if(x > leftEdge && x < rightEdge) {
                return true;
            }
            else {
                return false;
            }
        },
        getHeight : function() {
            return $(this.root).getHeight();
        },
        setHeight : function(h) {
              $(this.root).setStyle({
                  height : Number(h)+"px"
              });
        },
        removeGadget : function(g) {
            for(var i = 0; i < this.gadgets.length; i++) {
                if(this.gadgets[i] === g) {
                    this.gadgets.splice(i,1);
                }
            }
        },
        calculateGadgetIndices : function() {
            for(var i = 0; i < this.gadgets.length; i++) {
                this.gadgets[i].index = i;
                if(this.gadgets[i].column !== this) {
                    this.gadgets[i].column = this;
                }
            }
        },
        addGadget : function(g) {
            if(this.dropArea) {
                
                var pivot = $(this.dropArea.root).next(".gadget");
                this.dropArea.remove();
                this.dropArea = null;
                if(pivot) {
                    for(var i = 0; i < this.gadgets.length; i++) {
                        if(this.gadgets[i].root == pivot) {
                            this.gadgets.splice(i,0,g);
                            break;                          
                        }
                    }
                    $(pivot).insert({
                        before : g.root
                    });
                }
                else if(this.gadgets.length > 0) {
                    $(this.gadgets[this.gadgets.length-1].root).insert({
                        after : g.root
                    });
                    this.gadgets.push(g);
                }
                else {
                    this.gadgets[this.gadgets.length] = g;
                    $(this.root).insert(g.root);
                }
                this.calculateGadgetIndices();
            }
        },
        resetGadget : function(g) {
            if(g.index > 0) {
                $(this.gadgets[g.index-1].root).insert({
                    after:g.root
                });
            }
            else {
                $(this.gadgets[0].root).insert({
                    before:g.root
                });
            }
            this.calculateGadgetIndices();
        },
        onDragOver : function(gadget,column,dragEvent) {
            $(this.root).addClassName("hover");
            
            for(var i = 0; i < column.gadgets.length; i++) {
                var pos = column.gadgets[i].containsY(dragEvent.clientY + document.viewport.getScrollOffsets().top);
                if(pos && column.gadgets[i] !== gadget) {
                    if(!!column.dropArea && !column.dropArea.containsPoint(
                        document.viewport.getScrollOffsets().left + dragEvent.clientX,
                        document.viewport.getScrollOffsets().top + dragEvent.clientY)) {
                            column.dropArea.remove();
                    }
                    column.dropArea = new INDABA.controls.GadgetDropArea(
                    {
                        height : $(gadget.root).getHeight(),
                        element : column.gadgets[i].root,
                        position : pos
                    });                 
                }               
            }
            // if, after all that, there is still no drop area - the mouse is still on the column...
            // so build a drop area at the end of the column.
            if(!column.dropArea) {
                column.dropArea = new INDABA.controls.GadgetDropArea(
                    {
                        height : $(gadget.root).getHeight(),
                        element : column.root,
                        position : "inside"
                    });
            }
            
        },
        onDragOut : function(gadget,column,dragEvent) {
            $(this.root).removeClassName("hover");
            if(this.dropArea) {
                this.dropArea.remove();
                delete this.dropArea;
            }
        }
    };
    
    /* * * * * GadgetDropArea * * * * */
    
    INDABA.controls.GadgetDropArea = Class.create();
    
    INDABA.controls.GadgetDropArea.prototype = {
        initialize : function(config) {
            /*
            config {
                height : (int)+"px",
                element : element reference,
                position : "before" | "after"
            }
            */
                this.root = document.createElement("DIV");
                this.root.className = "gadgetDropZone";
                $(this.root).update('<p>Place Here</p>');
                
                $(this.root).setStyle({
                    height : config.height+"px"
                });
                
                $(this.root).setOpacity(0.7);
            
                if(config.position == "before") {
                    $(config.element).insert({
                        before : this.root
                    });             
                }
                else if(config.position == "inside") {
                    $(config.element).insert(this.root);
                }
                else {
                    $(config.element).insert({
                        after : this.root
                    });
                }

        },
        containsPoint : function(x,y) {
            var edges = {
                top : $(this.root).cumulativeOffset().top,
                left : $(this.root).cumulativeOffset().left,
                right : $(this.root).cumulativeOffset().left + $(this.root).getWidth(),
                bottom : $(this.root).cumulativeOffset().top + $(this.root).getHeight()
            };
            if(
                y > edges.top &&
                y < edges.bottom &&
                x > edges.left &&
                x < edges.right){
                    return true;
            }
            else {
                return false;
            }
        },
        remove : function() {
            $(this.root).remove();
        }
    };
    /* * * * * GadgetSelector * * * * */
    
    INDABA.controls.GadgetSelector = Class.create();
    
    INDABA.controls.GadgetSelector.prototype = {
        initialize : function(config) {
            this.root = $(config.root);
            if(User.loggedIn) {
                $(this.root).setStyle({
                    display:'block'
                });
            }
            this.currentPage = 0;
            this.gadgetsPerPage = 9;
            this.gadgetIcons = this.root.select('li');
            this.gadgetSelections = [];
            this.workspace = config.workspace;
            var onStartF = function(o,e) {
                if(User.loggedIn) {
                    o.element.addClassName('dragging');
                    document.fire("GadgetSelector:onDragStart", {gadget : o.gadgetSelector, type : o.gadgetType, dragEvent : e });
                }
            };
            var onEndF = function(o,e) {
                o.element.removeClassName('dragging');
                var gadgetType = o.gadgetType;
                if(gadgetType.indexOf('hide')) {
                    gadgetType = gadgetType.substring(0,gadgetType.indexOf('hide')-1);
                }
                document.fire("GadgetSelector:onDrop", { gadget : o.gadgetSelector, type : gadgetType, readableType : o.gadgetReadableType, dragEvent : e });
                
                return false;
            };
            var onDragF = function(o,e) {
                document.fire("GadgetSelector:onDrag", {gadget : o.gadgetSelector, type : o.gadgetType, dragEvent : e } );
            };
            var leftButton_click_listener = function(o,e) {
                var pg = this.currentPage;
                if(pg > 0) {
                    this.showPage(pg-1);
                }
            };
            var rightButton_click_listener = function(o,e) {
                var pg = this.currentPage;
                if(pg < this.maxPages()-1) {
                    this.showPage(pg+1);
                }
            };
            this.createArrowButtons();
            $(this.buttonLeft).observe('click',leftButton_click_listener.bind(this));
            $(this.buttonRight).observe('click',rightButton_click_listener.bind(this));
        
            
            for(var i = 0; i < this.gadgetIcons.length; i++) {
                var e = this.gadgetSelections.length;
                this.gadgetSelections[e] = new Draggable(
                    this.gadgetIcons[i],
                    {
                        ghosting : true,
                        handle : this.gadgetIcons[i],
                        scroll : window,
                        onStart : onStartF,
                        onEnd : onEndF,
                        onDrag : onDragF,
                        revert: function(e,o) {
                            $(e).setStyle({
                                position : "static",
                                left : "0",
                                right : "0"
                            });
                        }
                    }
                );
                this.gadgetSelections[e].gadgetSelector = this;
                this.gadgetSelections[e].gadgetType = this.gadgetIcons[i].className;
                var readableType = $(this.gadgetIcons[i]).select('span')[0];
                if(readableType) {
                    this.gadgetSelections[e].gadgetReadableType = readableType.innerHTML;
                }
            }
            this.showPage(this.currentPage);
            $(this.root.select('ul')[0]).setStyle({
                display:"inline-block"
            });

        },
        buttonLeft : null,
        buttonRight : null,
        createArrowButtons : function() {
            this.buttonLeft = document.createElement("A", {});
            this.buttonRight = document.createElement("A");
            this.buttonLeft.href = this.buttonRight.href = "javascript:void(0);";
            this.buttonLeft.className = "arrowButton arrowButtonLeft";
            this.buttonRight.className = "arrowButton arrowButtonRight";
            this.buttonLeft.innerHTML = "&lt;";
            this.buttonRight.innerHTML = "&gt;";
            this.root.select('ul')[0].insert({before : this.buttonLeft});
            this.root.select('ul')[0].insert({after : this.buttonRight});
        },
        maxPages : function() {
            return Math.ceil(this.gadgetIcons.length / this.gadgetsPerPage);
        },
        disableLeftButton : function() {
            $(this.buttonLeft).addClassName("disabled");
        },
        disableRightButton : function() {
            $(this.buttonRight).addClassName("disabled");
        },
        enableLeftButton : function() {
            $(this.buttonLeft).removeClassName("disabled");
        },
        enableRightButton : function() {
            $(this.buttonRight).removeClassName("disabled");
        },
        showPage : function(pageNum) {
            this.hidePage(this.currentPage);
            
            this.currentPage = pageNum;
            
            var ix = null;
            for(var i = 0; i < this.gadgetsPerPage; i++) {
                if (i+(this.gadgetsPerPage * this.currentPage) < this.gadgetIcons.length) {
                    $(this.gadgetIcons[ i + (this.gadgetsPerPage * this.currentPage) ]).removeClassName("hide");
                }
            }
            
            if(this.currentPage <= 0) {
                this.disableLeftButton();
            } else {
                this.enableLeftButton();
            }
            
            if(this.currentPage >= this.maxPages()-1) {
                this.disableRightButton();
            } else {
                this.enableRightButton();
            }
        },
        hidePage : function(pageNum) {
            for(var i = pageNum * this.gadgetsPerPage;
                i < pageNum*this.gadgetsPerPage + this.gadgetsPerPage &&
                i < this.gadgetIcons.length;
                i++) {  
                    if(!$(this.gadgetIcons[i]).hasClassName("hide")) {              
                        $(this.gadgetIcons[i]).addClassName("hide");
                    }
                }
        }
    };
    
    /* * * * * Lazy Initialized Gadget * * * * */
    INDABA.controls.LazyGadget = function(config) {
        var type = config.gadgetType;
        var readableType = config.readableType;
        var column = config.column;
        var workspace = config.workspace;
        var root = document.createElement("DIV");
        root.className = "gadget";

        var idEl = document.createElement("INPUT");
        idEl.type = "hidden";
        idEl.value = "_new";
        idEl.name = "gadget_id";
        root.appendChild(idEl);
        
        var typeEl = document.createElement("INPUT");
        typeEl.type = "hidden";
        typeEl.value = type;
        typeEl.name = "gadget_type";
        root.appendChild(typeEl);
        
        var anchor = document.createElement("A");
        anchor.href = "javascript:void(0)";
        anchor.innerHTML = readableType;
        
        var h3 = document.createElement("H3");
        h3.appendChild(anchor);
        root.appendChild(h3);
        
        var content = document.createElement("DIV");
        content.className = "content loading";
        content.innerHTML = "Loading...";
        root.appendChild(content);
        
        var foot = document.createElement("DIV");
        foot.className = "gadget_foot";
        root.appendChild(foot);
        
        var o = new INDABA.controls.Gadget({
            root : root,
            index : 0,
            column : column,
            workspace : workspace,
            isTransient : true
        });
        
        return o;
    };
    
    /* * * * * Gadget * * * * */    
    INDABA.controls.Gadget = Class.create();
    
    INDABA.controls.Gadget.prototype = {
        initialize : function(config) {
            if(config) {
                this.root = config.root || null;
                this.index = config.index || 0;
                this.column = config.column || 0;
                this.workspace = config.workspace || null;
                this.isTransient = config.isTransient || false;
            }
            if(null === this.root) {
                return null;
            }
            this.settings = {};

            this.type = "";
            this.id = "";
            this.uid = "";
            this.isDraggable = ($(this.root).hasClassName("pinned")) ? false : true;
            this.parseDOM();

            if(this.isDraggable && User.loggedIn) {
                this.createDraggable();
            }
            /*  scriptaculous is silly and needs for the display to be set in script or inline
                css for appear and fade to work. So, I have to initialize their display state 
                here.
            */
            if (this.closeButton) {
                $(this.closeButton).setStyle({
                    display: 'none'
                });
            }
            if (this.configButton) {
                $(this.configButton).setStyle({
                    display: 'none'
                });
            }
            if(this.isDraggable) {
                $(this.root).observe('mouseover',this.onMouseOver_listener.bind(this));
                $(this.root).observe('mouseout',this.onMouseOut_listener.bind(this));
            }
            var p = "";
            if(this.type === "RecommendedProjectsGadget") {
                p = "home_community_projects_for_user_gadget";
            }
            else if(this.type === "RecommendedUsersGadget") {
                p = "home_community_users_for_user_gadget";
            }
            if(p !== "") {
                Stream.observe("Recommender:"+p,this.setHeight.bind(this));
            }
        },
		mouseOutTimeout : null,
		closeButtonFade : null,
		closeButtonAppear : null,
		configButtonFade : null,
		configButtonAppear : null,
        onMouseOver_listener : function(e) {
            if ((el = Event.findElement(e, 'li')) && -1 == ['FeaturedProjectsGadget','FeaturedUsersGadget'].indexOf(this.type)) {
                el.addClassName('gdgt_item_hover');
            } else if ((el = Event.findElement(e, '.gadget_project')) && -1 == [].indexOf(this.type)) {
                el.addClassName('gdgt_item_hover');
            }
            var opacity = (User.loggedIn) ? 1.0 : 0.45;

            if (this.configSection && !this.configSection.visible()) {
	            if(!User.browser.ie) {
					if(this.closeButtonFade) {
						this.closeButtonFade.cancel();
						this.closeButtonFade = null;
					}
					if(this.configButtonFade) {
						this.configButtonFade.cancel();
						this.configButtonFade = null;
					}
					this.closeButtonAppear = new Effect.Appear(this.closeButton,{
						to : opacity,
						duration : 0.25,
						transition : Effect.Transitions.linear
					});
	                this.configButtonAppear = new Effect.Appear(this.configButton, {
	                    to : opacity,
	                    duration : 0.25,
	                    transition : Effect.Transitions.linear
	                });
	            }
	            else {
	                if($(this.closeButton)) {
	                    $(this.closeButton).setStyle({
	                        display:"block"
	                    });
	                }
	                if($(this.configButton)) {
	                    $(this.configButton).setStyle({
	                        display:"block"
	                    });
	                }   
	            }
			}
        },
        onMouseOut_listener : function(e) {
            if ((el = Event.findElement(e, 'li')) && -1 == ['FeaturedProjectsGadget','FeaturedUsersGadget'].indexOf(this.type)) {
                el.removeClassName('gdgt_item_hover');
            } else if ((el = Event.findElement(e, '.gadget_project')) && -1 == [].indexOf(this.type)) {
                el.removeClassName('gdgt_item_hover');
            }

            if (this.configSection && !this.configSection.visible()) {
				window.clearTimeout(this.mouseOutTimeout);
				this.mouseOutTimeout = setTimeout((function() {if(
                    !this.containsX(INDABA.util.Mouse.x) ||
                    !this.containsY(INDABA.util.Mouse.y)
                    ) {
                    if(!User.browser.ie) {
						if(this.closeButtonAppear) {
							this.closeButtonAppear.cancel();
							this.closeButtonAppear = null;
						}
						if(this.configButtonAppear) {
							this.configButtonAppear.cancel();
							this.configButtonAppear = null;
						}
                        this.closeButtonFade = new Effect.Fade(this.closeButton,{
                           	duration : 0.6,
                            transition : Effect.Transitions.linear
                        });
                        this.configButtonFade = new Effect.Fade(this.configButton, {
                            duration : 0.6,
                            transition : Effect.Transitions.linear
                        });
                    } else {
                        if($(this.closeButton)) {
                            $(this.closeButton).setStyle({
                                display:"none"
                            });
                        }
                        if($(this.configButton)) {
                            $(this.configButton).setStyle({
                                display:"none"
                            });
                        }
                    }
                }}).bind(this),500);
                
            }

        },
        createDraggable : function() {
            this.draggableObject = new Draggable(
                this.root,
                {
                    ghosting : false,
                    handle : this.dragHandle,
                    scroll : window,
                    onStart : function(o,e) {
                        document.fire("Gadget:onDragStart", {gadget : o.gadget, dragEvent : e });
                    },
                    onEnd : function(o,e) {
                        document.fire("Gadget:onDragEnd", { gadget : o.gadget, dragEvent : e });
                    },
                    onDrag : function(o,e) {
                        document.fire("Gadget:onDrag", {gadget : o.gadget, dragEvent : e } );
                    }
                }
            );
            this.draggableObject.gadget = this;
            $(this.dragHandle).setStyle({
                cursor:"move"
            });
            $($(this.dragHandle).select('a')[0]).setStyle({
                cursor:"move"
            });
        },
        destroyDraggable : function() {
            this.draggableObject.destroy();
            delete this.draggableObject;
        },
        close : function(e) {
            document.fire("Gadget:onDelete",{gadget : this});
            Event.stop(e);
        },
        parseDOM : function() {
            
            this.dragHandle = this.root.getElementsByTagName("H3")[0];

            var serverFields = this.root.getElementsByTagName("INPUT");
            this.configButton = $(this.root).select('.config_button')[0];
            this.configSection = $(this.root).select('.gadget_settings')[0];
            this.closeButton = $(this.root).select('.close_button')[0];
            this.applyConfigButton = null;

            if(this.configButton && this.configSection && User.loggedIn) {
                $(this.configButton).observe('mousedown',this.toggleConfig.bind(this));
				        this.applyConfigButton = $(this.configSection).select('button[name=save]')[0];
                Form.Element.enable(this.applyConfigButton);
				
                this.applyConfigButton.observe('click',this.updateSettings.bind(this));

                $(this.configSection).select('a.cancel')[0].observe('click',this.hideConfig.bind(this)); 
                
                if(this.closeButton) {
                    $(this.closeButton).observe('mousedown',this.close.bind(this));
                }
            }
            else {
                if(this.closeButton) {
                    $(this.closeButton).setStyle({
                        cursor:'default'
                    });
                }
                if(this.configButton) {
                    $(this.configButton).setStyle({
                        cursor:'default'
                    });
                }
            }
            for(var i = 0; i < serverFields.length; i++) {
                if(serverFields[i].name == "gadget_id") {
                    this.id = serverFields[i].value;
                }
                else if(serverFields[i].name == "gadget_type") {
                    this.type = serverFields[i].value;
                }
                else if(serverFields[i].name == "gadget_update_url") {
                    this.updateURL = serverFields[i].value;
                }
            }
            
            /*  add a class if it's events feed. This is hacky! Eventually we need to refactor
                some of these gadgets to use the decorator pattern. 
            */
            
            if(this.type === "RecentEventsGadget") {
                $(this.root).addClassName("recent_events_container");
            }
            
            /* fix the height of the content div by multiples of 108. */
        },
        setHeight : function() {
          if ($(this.root).hasClassName('pinned')) { return; }
            var c = $(this.root).select('.content')[0];
            var heightMultiple = 108;
            var marginHeight = parseInt(c.getStyle('margin-top'),10) + parseInt(c.getStyle('margin-bottom'),10);
            var r = (c.offsetHeight + marginHeight) % heightMultiple;
            if(r > 0) {
                $(c).setStyle({height : (c.offsetHeight - r + heightMultiple - marginHeight)+"px" });
            }
        },
        setConfigIsLoading : function(onoff) {
            if(true === onoff) {
                this.applyConfigButton.innerHTML = "<span>Loading...</span>";
                Form.Element.disable(this.applyConfigButton);
            }
            else {
                this.applyConfigButton.innerHTML = "<span>Save</span>";
                Form.Element.enable(this.applyConfigButton);
            }
        },
        updateSettings : function(event) {  
            this.setConfigIsLoading(true);
            var options = $(this.configSection).select('input');
            options = options.concat($(this.configSection).select('select'));
            for(var i = 0; i < options.length; i++) {
                if(options[i].type !== 'button') {
                    this.settings[options[i].name] = options[i].value;
                }
            }   
            INDABA.notification.NoteCenter.addNewMessage(
                new INDABA.notification.UserMessage(INDABA.notification.MessageTypes.Notice(),
                    "Saving Gadget Settings...",
                    {duration : 5}
                )
            );
            var s = function(t) {
                if(t.responseJSON.success) {
                    if(t.responseJSON.update_gadget_ids) {
                        workspace.updateGadgetIds(t.responseJSON.update_gadget_ids);
                    }
                    if(t.responseJSON.update_gadgets) {
                        var content = t.responseJSON.update_gadgets[this.id];
                        this.setContent(content);
                        INDABA.notification.NoteCenter.addNewMessage(
                            new INDABA.notification.UserMessage(INDABA.notification.MessageTypes.Success(),
                                "Gadget settings saved!",
                                {duration : 10}
                            ), true
                        );
                    }
                }
				        this.setConfigIsLoading(false);
            };
            var f = function(t) {
				      this.setConfigIsLoading(false);
            };
            var req = new INDABA.connection.URLPost({
                url:this.updateURL,
                callback : {
                    success : s,
                    successScope : this,
                    failure : f,
                    failureScope : this
                },
                data : this.settings
            });
            INDABA.connection.AJAXQueue.addAction(req);
        },
        toggleConfig : function(e) {
            if ($(this.configSection).visible()) {
                this.hideConfig();
            } else {
                this.showConfig();
            }
            Event.stop(e);
        },
        showConfig : function(event) {
            $(this.configButton).addClassName('active');
            $(this.configSection).slideDown({duration:0.40});
        },
        hideConfig : function(event) {
            $(this.configButton).removeClassName('active');
            $(this.configSection).slideUp({duration:0.20});
        },
        containsY : function(y) {
            var r = false;
            var containerTop = $(this.root).cumulativeOffset().top;
            var containerBottom = containerTop + $(this.root).getHeight();
            var centerLine = (containerTop + containerBottom) / 2;
            if(y > containerTop && y < containerBottom) {
                if(y > centerLine || !this.isDraggable) {
                    r = "after";
                }
                else {
                    r = "before";
                }
            }
            return r;
        },
        containsX : function(x) {
            var r = false;
            var containerLeft = $(this.root).cumulativeOffset().left;
            var containerRight = containerLeft + $(this.root).getWidth();
            return(x > containerLeft && x < containerRight);
        },
        setContent : function(content) {
            this.destroyDraggable();
            
            this.root.innerHTML = content;
            this.isTransient = false;
            this.parseDOM();
            this.createDraggable();
        },
        toJSON : function() {
            if(!this.isTransient) {
                return {
                    id : this.id,
                    column : this.column.index,
                    row : this.index,
                    type : this.type
                };
            }
        }
    };
    
/*******************************************
    Observers for gadgets
 ******************************************/

document.observe( "Recommender:home_community_users_for_user_gadget", function(event){
    $(event.memo.id).update(event.memo.content);
});

document.observe( "Recommender:home_community_projects_for_user_gadget", function(event){
    $(event.memo.id).update(event.memo.content);
});

/*******************************************
    Featured Gadgets JS
 ******************************************/

FeaturedGadget = Class.create();

FeaturedGadget.prototype = {
    
    initialize: function(c, ops) {
        if(!c || $(c).select('.empty').length > 0) {
            return false;
        }
        
        this._container = $(c);
        this._options = ops || {};
        
        /* set global height for the featured gadgets */
        
        
        this._config = {
            transition: {
                timeout: this._options.timeout || 12,
                queue: undefined,
                duration: this._options.transition_duration || 0.5
            }
        };

            this._timeout               = undefined;
        
            this._current_position      = this._options.position || 0;
            this._previous_position     = null;
        
       
            this._feature_container     = this._container.down('ul');
      
            this._scroller_container    = this._container.down('ul').next('ul');
       

            this._features       = this._feature_container.childElements();

            this._scrollers      = this._scroller_container.childElements().without( this._scroller_container.childElements().first(), this._scroller_container.childElements().last() );

            this.getSiblings();
            this.attachEvents();
        
            this.move( this._current_position );
    },
    
    attachEvents: function() {
        try {
            
            this._scroller_container.observe('click', function(e){
                var el = Event.findElement(e,'li');
                if (el) {
                    
                    if (el.hasClassName('left')) {
                        this.previous();
                    } else if (el.hasClassName('right')) {
                        this.next();
                    } else if (el.hasClassName('featured_sm')) {
                        this.move(this._scrollers.indexOf(el));
                    }
                }
            }.bind(this));
        } catch (e) { /* do nothing */ }
    },
    
    getSiblings: function() {
        try {
            this._previous              = (this._current_position === 0) ? null : this._features[this._current_position-1];
            this._current               = this._features[this._current_position];
            this._next                  = (this._current_position === this._features.length) ? null : this._features[this._current_position+1];
        } catch(e) { /* console.error(e); */ }
    },
    
    move: function(pos) {
        if (typeof(pos) === 'undefined' || pos < 0) { return false; }
        
        if (this._features.length > 1) {

            if (this._current.select('.truncate_with_more_link_full')[0] && 
                this._current.select('.truncate_with_more_link_full')[0].visible()) {
                    truncate_less(this._current.select('.truncate_with_more_link_full')[0]);
            }
 
            this._previous_position = this._current_position;
            this._current_position  = pos;
            
            this.getSiblings();
            this.highlightCurrent();
    
            var width   = this._features.first().getWidth();
            var newMargin  = pos * width;
        
            var morphEffect = new Effect.Morph(this._feature_container, {
                duration: this._config.transition.duration,
                scope: this._config.transition.queue,
                position: 'end',
                transition:Effect.Transitions.linear,
                style:{'marginLeft': '-'+newMargin+'px' }
            });

        }
        
    },
    
    next: function() {
        if (typeof(this._next) == 'undefined' || this._next === null) {
            this.move(0);
        } else {
            this.move(this._current_position + 1);
        }
    },
    
    previous: function() {
        if (typeof(this._previous) == 'undefined' || this._previous === null) {
            this.move(this._features.length - 1);
        } else {
            this.move(this._current_position - 1);
        }
    },

    highlightCurrent: function() {
        var morphEffect = new Effect.Morph(this._scrollers[this._previous_position], {
            style:'border:0;',
            duration:0.3,
            afterFinish: function(){
                this.removeClassName('selected');
            }.bind(this._scrollers[this._previous_position])
        });

        if(User.browser.ie && User.browser.version < 7) {
            $(this._scrollers[this._current_position]).addClassName('selected');
        }
        else {
            var secondMorph = new Effect.Morph($(this._scrollers[this._current_position]), {style:'selected', duration:0.3});
        }
    },
    
    
    pauseSlideshow: function() {
        if (typeof(this._timeout) !== 'undefined') {
            clearTimeout(this._timeout);
        }
    },
    
    stopSlideshow: function() {
        if (typeof(this._timeout) !== 'undefined') {
            clearTimeout(this._timeout);
        }
        this.move(0);
    }

};

/******************************************/

function truncate_more (el) {
    if (el && el.siblings().length > 0) {
        el.blindUp();
        el.fade({duration:0.75});
        el.siblings()[0].slideDown({duration:0.75});
    }
}

function truncate_less (el) {
    if (el && el.siblings().length > 0) {
        el.blindUp();
        el.fade({duration:0.75});
        el.siblings()[0].slideDown({duration:0.75});
    }
}

/******************************************/

var fgs = [];

Event.observe(window, "load", function(e){
    ['div.featured_users_gadget','div.featured_projects_gadget'].each( function(type){
        $$(type).each( function(container){
            if (container.visible()) {
                fgs.push( new FeaturedGadget(container) );
            }
        });
    });
    
    $$('.truncate_more_link').each( function(el){
        el.observe('click', function(e){
            if (el = Event.findElement(e, 'a').up('.truncate_with_more_link_truncated')) {
                truncate_more(el);
            }
        });
    });
    $$('.truncate_less_link').each( function(el){
        el.observe('click', function(e){
            if (el = Event.findElement(e, 'a').up('.truncate_with_more_link_full')) {
                truncate_less(el);
            }
        });
    });
    
});
