/*  SaveActionManager: Creates and keeps track of the action items
    ------------------------------------------------------- */
    hasActionUi = true;

    function SaveActionManager(args){
        //instance vars passed to constructor
        this.setGroupListData(args.groupListData);
        this.saveActionPath = args.saveActionPath;
        this.saveToNewGroupActionPath = args.saveToNewGroupActionPath;
        this.detailPath = args.detailPath;
        this.firstSaveInvitationText = args.firstSaveInvitationText;
        this.invitationToSaveText = args.invitationToSaveText;
        this.openMenuText = args.openMenuText;
        this.saveConfirmText = args.saveConfirmText;
        this.joinNowHTML = args.joinNowHTML;
        this.illegalCharError = args.illegalCharError;
        this.groupNameLengthError = args.groupNameLengthError;
        this.groupNameTakenError = args.groupNameTakenError;
        this.saveError = args.saveError;
        this.groupType = args.groupType;

        //general instance vars
        this.activeActionBox = null;
        this.actionButtonEls = getElements('saveButton', 'A' ,null); //can isolate this to prim content?
        this.saveActionBoxes = this.createActionBoxes();

        //init stuff
        this.defineActionItemsBehavior();
        this.openInitialActionBox();

        //Code to make whole 'Save for Later' buttons clickable
        var saveForLater = getElements('greenLabel', 'h6' ,null)[0];
        if(saveForLater){
            saveForLater.onmouseover = function() {
                var event, button;
                button = getElements('saveButton', 'A' ,null)[0];
                if(document.createEvent){
                   event = document.createEvent("MouseEvents");
                   event.initEvent("mouseover", true, false);
                   button.dispatchEvent(event);
                }
                else if(document.createEventObject){
                   event = document.createEventObject();
                   button.fireEvent("onmouseover", event);
                }
            };
        }
    }

    SaveActionManager.prototype.openInitialActionBox = function(){
        if( location.hash.match(/save_/) && this.groupListData.groups ){
            /*if 'save_' has been written into the url hash by the sign in or register
            component and the logged in user myConcierge ajax call has been made*/
            this.initialActionBoxId = unescape(location.hash.substring(6));
            var activeButtonEl, saveActionManager;
            saveActionManager = this;

            var closeLinkOnClickHandler=function(){saveActionManager.closeActiveItemAndReset();};

            var i;
            for(i=0; i<this.saveActionBoxes.length; i++){
                if(this.initialActionBoxId === this.saveActionBoxes[i].getButtonEl().id){
                    this.activeActionBox = this.saveActionBoxes[i];
                    activeButtonEl = this.activeActionBox.getButtonEl();
                    this.activeActionBox.createActionBoxEl();
                    this.onmouseout = this.onclick = activeButtonEl.onmouseover = null;
                    this.engageMenu();
                    this.activeActionBox.getCloseLink().onclick = closeLinkOnClickHandler;
                    this.scrollToActiveActionBox();
                    this.requestTracking();
                }
            }
        }
    };

    SaveActionManager.prototype.requestTracking = function(){
        var util, xhr, trackingPath;
        util = new ConciergeUtility();
        xhr = util.getXHR();
        trackingPath = '/ajax/trips/apptracking';
        xhr.open('GET', trackingPath, true);
        xhr.onreadystatechange = null;
        xhr.send( null );
    };

    SaveActionManager.prototype.scrollToActiveActionBox = function(){
        var offsetTop, actionBoxEl, totalOffset, element;
        totalOffset = 0;
        actionBoxEl = this.activeActionBox.getActionBoxEl();
        element = actionBoxEl;
        while(element.offsetParent){
            totalOffset += element.offsetTop;
            element = element.offsetParent;
        }
        totalOffset -= 188;
        window.scrollTo(0,totalOffset);
    };

    SaveActionManager.prototype.createActionBoxes = function(){
        var saveActionBoxes = [];
        var i;
        for(i=0; i<this.actionButtonEls.length; i++){
            saveActionBoxes.push( new ActionBox({buttonElement: this.actionButtonEls[i]}) );
        }
        return saveActionBoxes;
    };

    SaveActionManager.prototype.defineActionItemsBehavior = function(){  //add a function in here to delete the activeActionBox property onclick of its closelink
        var buttonEl, saveActionManager;
        saveActionManager = this;
        var i;
        for(i=0; i<this.saveActionBoxes.length; i++){
            buttonEl = this.saveActionBoxes[i].getButtonEl();
            buttonEl.onmouseover = buttonOverHandler;
        }

        function buttonOverHandler(event){
            if(saveActionManager.activeActionBox){
                return;
            }

            var evt, buttonEl;
            evt = event || window.event;
            buttonEl = evt.target || evt.srcElement;
            for(i=0; i<saveActionManager.saveActionBoxes.length; i++){
                if( buttonEl === saveActionManager.saveActionBoxes[i].getButtonEl() ){
                    saveActionManager.activeActionBox = saveActionManager.saveActionBoxes[i];
                    break;
                }
            }

            saveActionManager.activeActionBox.createActionBoxEl();
            saveActionManager.activeActionBox.writeToHeadline(saveActionManager.invitationToSaveText);
            saveActionManager.activeActionBox.getActionBoxEl().onmouseout = function(event){
                var evt, nextEl;
                evt = event || window.event;
                nextEl = evt.relatedTarget || evt.toElement;
                if( nextEl!==this && !isDescendant(this,nextEl)){
                    saveActionManager.closeActiveItemAndReset();
                }
            };

            saveActionManager.activeActionBox.getActionBoxEl().onclick = function(event){
                this.onmouseout = this.onclick = buttonEl.onmouseover = null;
                if(saveActionManager.groupListData.groups){
                    saveActionManager.engageMenu(); //if we have data, the user is logged in.. so open the menu
                } else {
                    saveActionManager.engageSignInOrRegisterComponent();
                }

                saveActionManager.activeActionBox.getCloseLink().onclick = function(){saveActionManager.closeActiveItemAndReset();};
            };
        }
    };

    SaveActionManager.prototype.engageSignInOrRegisterComponent = function(){
        var loginForm, joinInvite, clearer;
        clearer = document.createElement('DIV');
        clearer.className = 'clearer';
        loginForm = this.makeLoginForm();
        joinInvitation = this.makeJoinInvitation();
        this.activeActionBox.writeToHeadline('Sign In Or Register');
        this.activeActionBox.addClassName('signInOrRegister');
        this.activeActionBox.addElementToEnd(loginForm);
        this.activeActionBox.addElementToEnd(joinInvitation);
        this.activeActionBox.addElementToEnd(clearer);
        this.activeActionBox.expandActionBoxEl();
    };

    SaveActionManager.prototype.makeLoginForm = function(){
        var container, saveButtonId;
        saveButtonId = this.activeActionBox.getButtonEl().id ;
        container = document.createElement('DIV');
        container.id = 'sior_login_form';
        signInHTML = '<form method="post" action="/user/signin" name="loginForm">';
        if( !location.hash ){
            signInHTML += '<input type="hidden" name="returnto" value="' + location + '#save_' + saveButtonId + '" />';
        } else {
            signInHTML += '<input type="hidden" name="returnto" value="' + location.href.replace(location.hash, '') + '#save_' + saveButtonId + '" />';
        }
        signInHTML += '<h3>Member Sign-In</h3>' +
            '<div>' +
                '<p>You can now use your email address to login.</p>' +
                '<p>Email:<br /><input type="text" class="textField" name="username" ></p>' +
                '<p>Password:<br /><input type="password" class="textField" name="password"></p>' +
            '</div>' +
            '<p>' +
                '<span class="yellowOnBlackCssButton">' +
                    '<a href="javascript:document.loginForm.submit()">Sign In &#8250;</a>' +
                '</span>' +
                '<a class="forgotInfo" href="/user/forgotpassword?returnto=' + location + '">Forgot your sign-in information?</a>' +
                '<input id="submit" type="image" src="/images/x.gif"/>' +
            '</p>' +
        '</form>';
        container.innerHTML = signInHTML;
        return container;
    };

    SaveActionManager.prototype.makeJoinInvitation = function(){
        var container;
        container = document.createElement('DIV');
        container.id = 'sior_join_invite';
        container.innerHTML = this.joinNowHTML;
        return container;
    };

    SaveActionManager.prototype.engageMenu = function(){
        var existingGroupsEl, newGroupEl;
        if( this.groupListData.groups.length > 0 ){
            existingGroupsEl = this.createGroupListEl();
            newGroupEl = this.getCreateGroupLinkEl();
        } else{
            existingGroupsEl = this.getFirstSaveInvitationEl();
            newGroupEl = this.getCreationFormEl();
        }

        if(this.openMenuText){
            var actionManager = this;
            setTimeout( function(){actionManager.activeActionBox.writeToHeadline(actionManager.openMenuText);}, 0);
        }

        this.activeActionBox.addElementToEnd(existingGroupsEl);
        this.activeActionBox.addElementToEnd(newGroupEl);
        this.activeActionBox.expandActionBoxEl();
    };

    SaveActionManager.prototype.getFirstSaveInvitationEl = function(){
        var element = document.createElement("DIV");
        element.className = 'sysMsg';
        element.innerHTML = this.firstSaveInvitationText;
        return element;
    };

    SaveActionManager.prototype.createGroupListEl = function(){
        var groupListEl, itemEl, saveToGroupLinkEls;
        groupListEl = document.createElement('UL');
        groupListEl.className = 'groupList';
        groupListEl.className += " " + this.groupType.toLowerCase() + "List";
        this.saveToGroupLinkEls = this.createSaveToGroupLinkEls();
        var i;
        for(i=0; i<this.saveToGroupLinkEls.length; i++){
            itemEl = document.createElement('LI');
            itemEl.appendChild(this.saveToGroupLinkEls[i]);
            groupListEl.appendChild(itemEl);
        }
        return groupListEl;
    };

    SaveActionManager.prototype.createSaveToGroupLinkEls = function(){
        var actionItem, groupId, saveToGroupLinkEls, saveToGroupLinkEl, saveActionManager;
        saveActionManager = this;
        saveToGroupLinkEls = new Array();

        var onClickHandler=function(event){ saveActionManager.saveToExistingGroup(event);};

        var i;
        for(i=0; i<this.groupListData.groups.length; i++){
            saveToGroupLinkEl = document.createElement('A');
            saveToGroupLinkEl.innerHTML = this.groupListData.groups[i].groupTitle;
            saveToGroupLinkEl.id = this.groupType.toLowerCase() + "_" + this.groupListData.groups[i].groupId; //one way of passing group id.. try another way without using the dom
            saveToGroupLinkEl.onclick = onClickHandler;
            saveToGroupLinkEls.push(saveToGroupLinkEl);
        }
        return saveToGroupLinkEls;
    };

    SaveActionManager.prototype.getCreateGroupLinkEl = function(){
        var newLink, saveActionManager;
        saveActionManager = this;
        newLink = document.createElement('A');
        newLink.className = 'newLink';
        newLink.innerHTML = 'Create A New ' + this.groupType;
        newLink.onclick = function(){
            saveActionManager.activeActionBox.removeContent(newLink);
            saveActionManager.activeActionBox.addElementToEnd(saveActionManager.getCreationFormEl());
        };
        return newLink;
    };

    SaveActionManager.prototype.getCreationFormEl = function(){ //create backup standard form submission if request fails
        var creationForm, lowercaseGroupType, groupTitleLabel, groupTitleEntryField, saveButton, cancelButton, saveActionManager;
        saveActionManager = this;
        lowercaseGroupType = this.groupType.toLowerCase();
        creationForm = document.createElement('FORM');
        creationForm.name = creationForm.id = 'new_'+ lowercaseGroupType +'_form';
        groupTitleLabel = document.createElement("LABEL");
        groupTitleLabel.innerHTML = "new " + lowercaseGroupType + " title:";
        groupTitleLabel.setAttribute("FOR", lowercaseGroupType + '_text');
        groupTitleEntryField = document.createElement('INPUT');
        groupTitleEntryField.type = 'TEXT';
        groupTitleEntryField.name = lowercaseGroupType + '_title';
        groupTitleEntryField.id = lowercaseGroupType + '_text';
        groupTitleEntryField.setAttribute("MAXLENGTH", 50);
        saveButton = document.createElement('A');
        saveButton.innerHTML = 'Save';
        cancelButton = document.createElement('A');
        cancelButton.innerHTML = 'Cancel';
        creationForm.appendChild(groupTitleLabel);
        creationForm.appendChild(groupTitleEntryField);
        creationForm.appendChild(saveButton);
        creationForm.appendChild(cancelButton);
        creationForm.onsubmit = function(){
            saveActionManager.validateCreationForm(this, groupTitleEntryField);
            return false;
        };

        saveButton.onclick = function(){creationForm.onsubmit();};
        cancelButton.onclick = function(){saveActionManager.closeActiveItemAndReset();};
        return creationForm;
    };

    SaveActionManager.prototype.validateCreationForm = function(creationForm, groupTitleEntryField){
        var titleEntryValue, illegalChars, titleEntryLength, saveActionManager;
        saveActionManager = this;
        illegalChars = ['<', '>', '?', '/', '&'];

        titleEntryValue = groupTitleEntryField.value;
        titleEntryLength = titleEntryValue.length;
        if(titleEntryLength>50 || titleEntryLength<1){ //extend this to match on characters (space) casing & make 20 an argument
            provideErrorMessage('lengthError');
            return;
        }

        var i;
        for(i=0; i<this.groupListData.groups.length; i++){
            if(titleEntryValue.toLowerCase() === this.groupListData.groups[i].groupTitle.toLowerCase()){ //add checking against decoded title
                provideErrorMessage('nameTakenError');
                return;
            }
        }

        for(i=0; i<illegalChars.length; i++){
            if(titleEntryValue.indexOf(illegalChars[i]) !== -1){
                provideErrorMessage('illegalCharError');
                return;
            }
        }

        function provideErrorMessage(errorType){
            var errorMsgText, errorMsgEl, previousErrorMsgs;
            previousErrorMsgs = getElements('errorMsg', 'P', creationForm);
            errorMsgEl = document.createElement('P');
            errorMsgEl.className = 'errorMsg';
            switch(errorType){
            case 'lengthError':
                errorMsgText = saveActionManager.groupNameLengthError;
                break;
            case 'nameTakenError':
                errorMsgText =  saveActionManager.groupNameTakenError;
                break;
            case 'illegalCharError':
                errorMsgText = saveActionManager.illegalCharError;
                break;
            }
            errorMsgEl.innerHTML = errorMsgText;

            for(i=0; i<previousErrorMsgs.length; i++){
                creationForm.removeChild(previousErrorMsgs[i]);
            }

            creationForm.insertBefore(errorMsgEl, creationForm.firstChild);
        }

        this.createAndSaveToNewGroup(titleEntryValue);
    };

    SaveActionManager.prototype.createAndSaveToNewGroup = function(groupTitle){
        var util, fullRequestPath, saveActionManager, xhr;
        saveActionManager = this;
        fullRequestPath = this.saveToNewGroupActionPath + saveActionManager.activeActionBox.getContentType() +
                                  '/' + groupTitle + '/' + saveActionManager.activeActionBox.getContentId();
        util = new ConciergeUtility();
        xhr  = util.getXHR();
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4 && xhr.status === 200){
                newGroupData = eval('('+xhr.responseText+')');
                saveActionManager.handleSaveToNew(newGroupData, groupTitle);
            }
            if (xhr.readyState === 4 && xhr.status !== 200){
                saveActionManager.showErrorState(xhr.status);
            }
        };

        xhr.open("GET", fullRequestPath, true); //replace this with a post request
        this.showProgressIndication('Saving');
        xhr.send(null);
    };

    SaveActionManager.prototype.saveToExistingGroup = function(event){
        var evt, requestedGroupSaveLinkEl, saveActionPath, fullRequestPath, groupId, contentItemType, contentItemId, util, xhr, newGroupData, saveActioManager;
        evt = event || window.event;
        requestedGroupSaveLinkEl = evt.srcElement || evt.target;
        saveActionManager = this;

        var i;
        for(i=0; i<this.saveToGroupLinkEls.length; i++){
            if(this.saveToGroupLinkEls[i] === requestedGroupSaveLinkEl){
                groupId = this.saveToGroupLinkEls[i].id.split('_')[1]; //one way of getting the trip id.. try to do it without the dom
            }
        }

        saveActionPath = this.saveActionPath;
        contentItemType = this.activeActionBox.getContentType();
        contentItemId = this.activeActionBox.getContentId();
        fullRequestPath = saveActionPath + '/' + groupId + '/add' + contentItemType + '/' + contentItemId;
        saveActionManager.showProgressIndication();
        util = new ConciergeUtility();
        xhr  = util.getXHR();
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4 && xhr.status === 200){
                    newGroupData = eval('('+xhr.responseText+')');
                    saveActionManager.handleSaveToExisting(newGroupData, requestedGroupSaveLinkEl);
            }
            if (xhr.readyState === 4 && xhr.status !== 200){
                saveActionManager.showErrorState(xhr.status);
            }
        };

        xhr.open("GET", fullRequestPath, true);
        xhr.send(null);
    };

    SaveActionManager.prototype.showErrorState = function(status){
        var errorDiv;
        errorDiv = document.createElement('DIV');
        errorDiv.className = 'saveError';
        errorDiv.innerHTML = this.saveError;
        this.activeActionBox.removeAllContent();
        this.activeActionBox.addElementToBeginning(errorDiv);
    };

    SaveActionManager.prototype.handleSaveToExisting = function(newGroupData, requestedGroupSaveLinkEl){
        var groupTitle = requestedGroupSaveLinkEl.innerHTML;
        this.setGroupListData(newGroupData);
        this.showSuccessMessage(groupTitle);
        updateGroupListsOnPage(newGroupData);
    };

    SaveActionManager.prototype.handleSaveToNew = function(newGroupData, groupTitle){
        this.setGroupListData(newGroupData);
        this.showSuccessMessage(groupTitle);
        updateGroupListsOnPage(newGroupData);
    };

    SaveActionManager.prototype.showSuccessMessage = function(groupTitle){
        var successMsgEl, saveActionManager, closeLink, clearer, detailLink;
        successMsgEl = document.createElement('DIV');
        detailLink = document.createElement('A');
        successMsgEl.className = "sysMsg";
        successMsgEl.innerHTML = this.saveConfirmText + groupTitle;
        detailLink.innerHTML = "Go to your " + this.groupType + 's';
        detailLink.href = this.detailPath;
        this.activeActionBox.removeAllContent();
        this.activeActionBox.addElementToEnd(successMsgEl);
        if(detailLink){
            this.activeActionBox.addElementToEnd(detailLink);
        }

        saveActionManager= this;
        clearer = window.setTimeout(function(){saveActionManager.closeActiveItemAndReset();}, 3000);
        closeLink = saveActionManager.activeActionBox.getCloseLink();
        closeLink.onclick = function(){
            clearTimeout(clearer);
            saveActionManager.closeActiveItemAndReset();
        };
    };

    SaveActionManager.prototype.showProgressIndication = function(message){
        var progressEl, msgText;
        msgText = message || 'In Progress';
        progressEl = document.createElement('DIV');
        progressEl.className = 'inProgress';
        progressEl.innerHTML = msgText;
        this.activeActionBox.removeAllContent();
        this.activeActionBox.addElementToBeginning(progressEl);
    };

    SaveActionManager.prototype.closeActiveItemAndReset = function(){
        this.activeActionBox.destroyActionBoxEl();
        delete this.activeActionBox;
        this.defineActionItemsBehavior();
    };

    SaveActionManager.prototype.getActiveActionItem = function(buttonEl){
        var i;
        for(i=0; i<this.saveActionBoxes.length; i++){
            if(buttonEl === this.saveActionBoxes[i].buttonEl){
                return this.saveActionBoxes[i];
            }
        }
    };

    SaveActionManager.prototype.setGroupListData = function(groupListData){ //this will be used for updates via ajax response
        this.groupListData = groupListData;
    };

    /**************************************/

    function instantiateActionManager( tripsGroups){
        var invitationToSaveText, openMenuText, type, joinNowHTML, initialActionBoxId;
        tripsData.groups = tripsGroups;
        invitationToSaveText = (isCopy ? 'Copy This Item' : 'Save for Later');
        openMenuText = (isCopy ? 'Copy To Another Trip Plan:' : 'Save To A Trip Plan:');
        saveConfirmText = (isCopy ? 'Copied to ' : 'Saved to ');

        joinNowHTML =
        '<h3>Not A Member?</h3>' +
        '<p>Join Concierge.com to create Trip Plans, upload photos, post tips and reviews, and get answers to your travel questions.</p>' +
        '<p>It\'s fast and free!</p>' +
        '<span class="yellowOnBlackCssButton"><a href="/user/registration?application=trips&returnto=' + encodeURIComponent(location) + '">Join Now&nbsp;&#8250;</a></span>';

        tripsSaveManager = new SaveActionManager({
                groupListData:  tripsData, //global var set by response
                saveActionPath: '/myconcierge/trips',
                saveToNewGroupActionPath: '/myconcierge/trips/createtripadd',
                detailPath: '/myconcierge/trips/mostrecent',
                groupType: 'Trip',
                firstSaveInvitationText: 'You do not have any Trip Plans. Create one here:',
                illegalCharError: "Sorry. You've included a character that's not allowed. Please try a different title for your Trip Plan.",
                groupNameTakenError: "A Trip Plan with this name already exists.",
                groupNameLengthError: "Trip Plan name must contain between 1 and 50 characters.",
                saveError: "Error:  Unable to save item to your Trip Plan. Please try again later.",
                invitationToSaveText: invitationToSaveText,
                openMenuText: openMenuText,
                saveConfirmText: saveConfirmText,
                joinNowHTML: joinNowHTML
        });
    }

/************************************************************************************************************/


/************************************************************************************************************/

/*  ActionBox
    --------- */
    function ActionBox(args){
        this.buttonEl = args.buttonElement;
    }

    ActionBox.prototype.getContentId = function(){
        return this.buttonEl.id.split('_')[1];
    };

    ActionBox.prototype.getContentType = function(){
        return this.buttonEl.id.split('_')[0];
    };

    ActionBox.prototype.getButtonEl = function(){
        return this.buttonEl;
    };

    ActionBox.prototype.createActionBoxEl = function(){
        if(this.actionBoxEl){
            return;
        }

        this.actionBoxEl = document.createElement('DIV');
        this.actionBoxHeadline = document.createElement('H6');
        this.actionBoxContentEl = document.createElement('DIV');
        this.actionBoxEl.className = 'actionBox';
        this.actionBoxContentEl.className = 'actionBoxContent';
        this.buttonEl.parentNode.replaceChild(this.actionBoxEl, this.buttonEl);
        this.actionBoxEl.appendChild(this.actionBoxHeadline);
        this.actionBoxEl.appendChild(this.buttonEl);
        this.actionBoxEl.appendChild(this.actionBoxContentEl);
    };

    ActionBox.prototype.getActionBoxEl = function(){
        return this.actionBoxEl;
    };

    ActionBox.prototype.destroyActionBoxEl = function(){
        var actionBoxAncestors = getAncestors(this.actionBoxEl);
        var i;
        for(i=0; i<actionBoxAncestors.length; i++){
            actionBoxAncestors[i].style.zIndex = '';
        }

        this.actionBoxEl.parentNode.replaceChild(this.buttonEl, this.actionBoxEl);
        delete this.actionBoxEl;
        delete this.actionBoxHeadline;
        delete this.actionBoxContentEl;
        this.isOpen = false;
    };

    ActionBox.prototype.writeToHeadline = function(content){
        this.actionBoxHeadline.innerHTML = content;
    };

    ActionBox.prototype.addElementToEnd = function(element){ //rename
        this.actionBoxContentEl.appendChild(element);
    };

    ActionBox.prototype.addElementToBeginning = function(element){ //rename
        this.actionBoxContentEl.insertBefore(element,this.actionBoxContentEl.firstChild);
    };

    ActionBox.prototype.removeContent = function(element){
        if(element){
            this.actionBoxContentEl.removeChild(element);
        }
    };

    ActionBox.prototype.removeAllContent = function(){
        while(this.actionBoxContentEl.childNodes.length > 0){
            this.actionBoxContentEl.removeChild(this.actionBoxContentEl.firstChild);
        }
    };

    ActionBox.prototype.expandActionBoxEl = function(){
        if(!this.actionBoxEl || this.isOpen){
            return;
        }
        var actionBoxAncestors = getAncestors(this.actionBoxEl);
        var i;
        for(i=0; i<actionBoxAncestors.length; i++){
            actionBoxAncestors[i].style.zIndex = '1000';
        }

        this.actionBoxEl.className += ' expandedActionBox';
        this.addCloseLink();
        this.isOpen = true;
    };

    ActionBox.prototype.addCloseLink = function(){
        var thisActionBox = this;
        this.closeLink = document.createElement("A");
        this.closeLink.className = 'closeLink';
        this.closeLink.innerHTML = 'x';
        this.actionBoxEl.appendChild(this.closeLink);
    };

    ActionBox.prototype.getCloseLink = function(){
        return this.closeLink;
    };

    ActionBox.prototype.hideTooltip = function(event){
        var nextEl = event.relatedTarget || event.toElement;
        if(!this.actionBoxEl || !nextEl){
            return;
        }
        if( !isDescendant(this.actionBoxEl, nextEl) && nextEl !== this.actionBoxEl ){
            this.destroyActionBoxEl();
        }
    };

    ActionBox.prototype.addClassName = function( classname ){
        this.actionBoxEl.className += ' ' + classname;
    };

    ActionBox.prototype.removeClassName = function( classname ){
        this.actionBoxEl.className = this.actionBoxEl.className.replace(classname,'');
    };

/************************************************************************************************************/

/*  DeleteActionManager: Deletes an item from a group
    ------------------------------------------------- */
    function deleteActionManager(args){
        this.container = document.getElementById(args.containerId);
        this.deleteClass = args.deleteClass;
        this.confirmText = args.confirmText;
        this.actionPath = args.actionPath;
        this.deleteEls = this.getDeleteEls();
        this.deleteActionItems = this.setDeleteActionItems();
    }

    deleteActionManager.prototype.setDeleteActionItems = function(){
        var i;
        for(i=0; i<this.deleteEls.length; i++){
            new deleteActionItem({deleteEl: this.deleteEls[i], confirmText: this.confirmText, actionPath: this.actionPath});
        }
    };

    deleteActionManager.prototype.getDeleteEls = function(){
        return getElements(this.deleteClass, null, this.container);
    };

    function deleteActionItem(args){
        var deleteActionItem = this;
        this.deleteEl = args.deleteEl;
        this.contentEl = this.deleteEl.parentNode; //this can be made more general later
        this.contentType = this.getContentType();
        this.contentId = this.getContentId();
        this.confirmText = args.confirmText;
        this.actionPath = args.actionPath;
        this.deleteEl.onclick = function(){deleteActionItem.requestDelete();};
    }

    deleteActionItem.prototype.requestDelete = function(){
        var deleteConfirmation, util, fullRequestPath, deleteActionItem, newGroupData;
        deleteConfirmation = confirm(this.confirmText);
        if(!deleteConfirmation){
            return;
        }

        fullRequestPath = this.actionPath + this.contentType + '/' + this.contentId;
        deleteActionItem = this;
        util = new ConciergeUtility();
        xhr  = util.getXHR();
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4 && xhr.status === 200){
                newGroupData = eval('('+xhr.responseText+')');
                deleteActionItem.handleDelete(newGroupData);
            }
        };

        xhr.open("GET", fullRequestPath, true);
        xhr.send(null);
    };

    deleteActionItem.prototype.handleDelete = function(newGroupData){
        this.showDeleted();
        updateGroupListsOnPage(newGroupData);
    };

    deleteActionItem.prototype.showDeleted = function(){
        var removeMethod, deleteActionItem;
        deleteActionItem = this;
        removeMethod = function(){deleteActionItem.contentEl.parentNode.removeChild(deleteActionItem.contentEl);};
        fadeOut(this.contentEl, 10, removeMethod);
    };

    deleteActionItem.prototype.getContentType = function(){
        return this.deleteEl.id.split('_')[0];
    };

    deleteActionItem.prototype.getContentId = function(){
        return this.deleteEl.id.split('_')[1];
    };

/************************************************************************************************************/


/*  Price Key
    --------- */
    function PriceRatingItem(args){
        var instance = this;
        this.ratingElement = args.ratingElement;
        this.dynPos = this.getType();
        this.ratingElement.onmouseover = function(){instance.showKey();};
        this.ratingElement.onmouseout = function(){instance.hideKey();};
    }

    PriceRatingItem.prototype.getType = function(){
        if( isMember(this.ratingElement, 'dPos') ){
            return true;
        }

        return false;
    };

    PriceRatingItem.prototype.showKey = function(){
        this.keyActionBox = this.createPriceKey();
        this.ratingElement.appendChild(this.keyActionBox);
        setCssOpacity(this.keyActionBox,0);
        this.keyActionBox.style.visibility = 'visible';
        if(this.dynPos){
            var newTop, newLeft;
            newTop = this.ratingElement.offsetTop+17;
            newLeft = this.ratingElement.offsetLeft>105 ? this.ratingElement.offsetLeft-105 : this.ratingElement.offsetLeft + 40;
            this.keyActionBox.style.top = newTop + 'px';
            this.keyActionBox.style.left = newLeft + 'px';
        }

        var keyAncestors = getAncestors(this.keyActionBox);
        var i;
        for(i=0; i<keyAncestors.length; i++){
            keyAncestors[i].style.zIndex = '1000';
        }

        fade(this.keyActionBox, 5);
    };

    PriceRatingItem.prototype.hideKey = function(){
        if(!this.keyActionBox){
            return;
        }

        var keyAncestors = getAncestors(this.keyActionBox);
        var i;
        for(i=0; i<keyAncestors.length; i++){
            keyAncestors[i].style.zIndex = '';
        }

        this.ratingElement.removeChild(this.keyActionBox);
        delete this.keyActionBox;
    };

    var priceKeyText =
        '<p>$<span class="off">$$$</span> = <strong>$199 or less</strong></p>' +
        '<p>$$<span class="off">$$</span> = <strong>$200 to $299</strong></p>' +
        '<p>$$$<span class="off">$</span> = <strong>$300 to $399</strong></p>' +
        '<p>$$$$ = <strong>$400 or more</strong></p>';

    PriceRatingItem.prototype.createPriceKey = function(){
        if(this.keyActionBox){
            return;
        }

        var actionBox = document.createElement('DIV');
        actionBox.className = 'priceKey actionBox';

        var actionHeadline = document.createElement('H6');
        actionHeadline.innerHTML = 'Price Key';

        var keyList = document.createElement('DIV');
        keyList.className = 'actionBoxContent';
        keyList.innerHTML = priceKeyText;

        actionBox.appendChild(actionHeadline);
        actionBox.appendChild(keyList);
        return actionBox;
    };


    /**************************************/
    function instantiatePriceRatingItems(){
        var costRatingEls = getElements('costRating','DIV',null);
        var i;
        for(i=0; i<costRatingEls.length; i++){
            new PriceRatingItem({ratingElement: costRatingEls[i]});
        }
    }

    runOnLoad(instantiatePriceRatingItems);
/************************************************************************************************************/

/************************************************************************************************************/

/*  Expandable Units
    ---------------- */
    function expandableUnit(args){
        this.unitEl = args.unitEl;
        this.isExpanded = this.getInitialState(); //default is collapsed, classname of expanded asserts initial open state
        this.init();
    }
    expandableUnit.prototype.init = function(){
        var expandableUnit = this;
        this.knob = getElements('knob', null, this.unitEl)[0];
        this.knob.onclick = function(event){expandableUnit.switchState(event);};
    };

    expandableUnit.prototype.getInitialState = function(){
        if(this.unitEl.className.match("expanded") ){
            return true;
        } else if(this.unitEl.className.match("collapsed") ){
            return false;
        }

        this.unitEl.className += " collapsed";
        return false;
    };

    expandableUnit.prototype.switchState = function(event){
        if (this.isExpanded){
            this.collapse();
        } else {
            this.expand();
        }
    };

    expandableUnit.prototype.expand = function(){
        this.unitEl.className = this.unitEl.className.replace(/collapsed/, "expanded");
        this.isExpanded = true;
    };

    expandableUnit.prototype.collapse = function(){
        this.unitEl.className = this.unitEl.className.replace(/expanded/, "collapsed");
        this.isExpanded = false;
    };

    /*************************************/
    function instantiateExpandableUnits(){
        var expanders = getElements('expandable','DIV',null);
        var i;
        for(i=0; i<expanders.length; i++){
            new expandableUnit({
                unitEl: expanders[i]
            });
        }
    }
    runOnLoad(instantiateExpandableUnits);

