//
var Y = YAHOO.util;
String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$/g,"");
};

/*
 * Intercepts ENTER key. If button was pressed from a form element other than TEXTAREA,
 * click the first button with the class name "defaultSubmit" within the parent form.
 */
Y.Event.on(document, 'keydown', function(e) {
    if (e.keyCode == 13) {  // enter key
        var el = Y.Event.getTarget(e);
        if (el.tagName != 'TEXTAREA') {
            var frm = (el.tagName == 'FORM') ? el : Y.Dom.getAncestorByTagName(el, 'FORM');
            if (frm) {
                var button = Y.Dom.getElementsByClassName('defaultSubmit', '', frm)[0];
                if (button && 'click' in button) {
                    Y.Event.preventDefault(e);
                    button.click();
                }
            }
        }
    }
});

(function() {
    fitbit.namespace("fitbit.app");
    fitbit.app = {
    };
    
    fitbit.app.objectsCounter = 0;
    fitbit.app.calendarPathSeparator = "/";

    fitbit.app.Calendar = function( calendarId, dateSelectHandler, path ) {
        var dialog, calendar;
        var weekStartsOn = null;

        this.show = function(positionDivId, pageDate, selectedDates, maxDate, renderDivId, todayDate, minDate) {
            if (calendarId == null) {
                calendarId = "calendar";
            }

            if (!dialog) {
                // Hide Calendar if we click anywhere in the document other than the calendar
                Y.Event.on(document, "click", function(e) {
                    var positionElement = Y.Dom.get(positionDivId);
                    var el = Y.Event.getTarget(e);
                    var dialogEl = dialog.element;
                    //alert( "->" + el != dialogEl );
                    if (el != dialogEl && !Y.Dom.isAncestor(dialogEl, el) && el != positionElement && !Y.Dom.isAncestor(positionElement, el)) {
                        dialog.hide();
                    }
                });

                dialog = new YAHOO.widget.Dialog(calendarId + "Container", {
                    visible: false,
                    context:[positionDivId, "tl", "bl"],
                    //buttons:[ {text:"Select", isDefault:true, handler: okHandler},
                    //          {text:"Cancel", handler: cancelHandler}],
                    width:"16em",  // Sam Skin dialog needs to have a width defined (7*2em + 2*1em = 16em).
                    draggable:false,
                    close:true
                });

                if (fitbit.i18n) {
                    dialog.setHeader(fitbit.i18n.getResource('com.fitbit.app.label.select_date'));            
                }
                else {
                    dialog.setHeader('Select a date');
                }

                dialog.setBody('<div id="' + calendarId + '"></div>');
                if ( renderDivId != undefined && renderDivId != null ) {
                    dialog.cfg.setProperty("height", "18em");
                    dialog.render( renderDivId );
                } else {
                    dialog.render(document.body);
                }

                dialog.showEvent.subscribe(function() {
                    if (YAHOO.env.ua.ie) {
                        // Since we're hiding the table using yui-overlay-hidden, we
                        // want to let the dialog know that the content size has changed, when
                        // shown
                        dialog.fireEvent("changeContent");
                    }
                });
            }

            if (!calendar) {
                calendar = new YAHOO.widget.Calendar(calendarId, {
                    iframe:false,          // Turn iframe off, since container has iframe support.
                    hide_blank_weeks:true  // Enable, to demonstrate how we handle changing height, using changeContent
                });
                calendar.path = path;
                calendar.calendarId = calendarId;

                if (pageDate != null) {
                    var date = new Date(0, 0, 0);
                    date.setISO8601UTC(pageDate);
                    calendar.cfg.setProperty("pagedate", (date.getMonth() + 1) + "/" + date.getFullYear());
                }

                if (selectedDates == null && pageDate != null) {
                    var tDate = new Date(0, 0, 0);
                    tDate.setISO8601UTC(pageDate);
                    calendar.cfg.setProperty("selected", (tDate.getMonth() + 1) + "/" + (tDate.getDate()) + "/" + tDate.getFullYear());
                } else if (selectedDates != null) {
                    calendar.cfg.setProperty("selected", selectedDates);
                }
                if (maxDate != undefined && maxDate != null) {
                    calendar.cfg.setProperty("maxdate", maxDate);
                }
                if (minDate != undefined && minDate != null) {
                    calendar.cfg.setProperty("mindate", minDate);
                }
                if (todayDate != null) {
                    calendar.today = todayDate;
                }

                if ( weekStartsOn != null ) {
                    calendar.cfg.setProperty("start_weekday", weekStartsOn);
                }

                if (fitbit.i18n) {
                    if (fitbit.i18n.WEEKDAYS) {
                        calendar.cfg.setProperty("WEEKDAYS_SHORT", fitbit.i18n.WEEKDAYS);
                    }
                    if (fitbit.i18n.MONTHS) {
                        calendar.cfg.setProperty("MONTHS_LONG", fitbit.i18n.MONTHS);
                    }
                }

                calendar.render();

                calendar.renderEvent.subscribe(function() {
                    // Tell Dialog it's contents have changed, Currently used by container for IE6/Safari2 to sync underlay size
                    dialog.fireEvent("changeContent");
                });

                calendar.selectEvent.subscribe(dateSelectHandler, calendar, true);
            }

            dialog.show();
        };

        this.hide = function() {
            dialog.hide();
        };

        this.setWeekStartsOn = function( day ) {
            weekStartsOn = day;
        };

    };

    fitbit.app.dateSelectHandler = function ( type, args, calendar ) {
        /*
        fitbit.util.setContent(
            Y.Dom.get( calendar.calendarId + "Header" ),
            "<img src='/images/loadingf2f2f2.gif'/>" + "&nbsp;Please wait ..."
        );
        */

        var dateResult = fitbit.util.getDateFromYUIDateArray(args[0][0]);
        var bizPath = ( calendar.path != undefined && calendar.path != "" ? calendar.path : "" );
        location.href = bizPath + "/" + dateResult.getFullYear() + fitbit.app.calendarPathSeparator + dateResult.getPaddedMonth() + fitbit.app.calendarPathSeparator + dateResult.getPaddedDate();
    };

    fitbit.app.showCalendar = function( path, calendarId, positionDivId, pageDate, noMaxDate, dateSeparator, userWeekStartsOn) {
        if(dateSeparator != null || dateSeparator != '') {
            fitbit.app.calendarPathSeparator = dateSeparator;
        }
        var cal = new fitbit.app.Calendar( calendarId, fitbit.app.dateSelectHandler, path );
        var today = new Date();
        today.setISO8601UTC( pageDate );

        var maxDate = today;
        if ( noMaxDate ) {
            maxDate = null;
        }
        if ( userWeekStartsOn ) {
            cal.setWeekStartsOn( userWeekStartsOn );
        }
        cal.show(positionDivId, pageDate, null, maxDate, null, today);
    };

    fitbit.app.showWeeklyCalendar = function( path, calendarId, positionDivId, todayDate, pageDate, minDate, maxDate, dateSeparator, selectedDates, userWeekStartsOn ) {
        if(dateSeparator != null || dateSeparator != '') {
            fitbit.app.calendarPathSeparator = dateSeparator;
        }
        var cal = new fitbit.app.Calendar( calendarId, fitbit.app.dateSelectHandler, path );
        var today = new Date();
        today.setISO8601UTC( todayDate );

        var max = null;
        if ( maxDate != null ) {
            max = new Date();
            max.setISO8601UTC( maxDate );
        }

        var min = null;
        if ( minDate != null ) {
            min = new Date();
            min.setISO8601UTC( minDate );
        }

        cal.setWeekStartsOn( userWeekStartsOn );
        cal.show(positionDivId, pageDate, selectedDates, max, null, today, min);
    };

    fitbit.app.TabSet = function(tabContainerId, activeClazz , disableClazz ) { //alert(clazz);
        if ( activeClazz == undefined ) {
            activeClazz = "selected";
        }

        if ( disableClazz == undefined ) {
            disableClazz = "disabled";    
        }

        this.tabChangeEvent = new Y.CustomEvent("tabChange",  this);

        var tabsContainer = Y.Dom.get(tabContainerId);
        if (!tabsContainer) {
            return;
        }
        var activeTab = Y.Dom.getElementsByClassName(activeClazz, "a", tabsContainer)[0];
        var tabs = new Array();
        var parentElements = null;
        if (activeTab != undefined) {
            parentElements = Y.Dom.getChildren(activeTab.parentNode.parentNode);
            var activeTabHref = activeTab.getAttribute('href', 2);
            var activeContent = Y.Dom.get( activeTabHref.substr( activeTabHref.indexOf("#") + 1 ) );
        } else {
            parentElements = tabsContainer.getElementsByTagName("li");            
        }
        var _tabChangeEvent = this.tabChangeEvent;

        var handleOnMouseDown = function(e, tab) {
            if (tab != activeTab && !Y.Dom.hasClass(tab, disableClazz) ) {
                Y.Dom.addClass(tab, activeClazz);
                Y.Dom.addClass(tab.parentNode, activeClazz);
                if (activeTab != undefined) {
                    Y.Dom.removeClass(activeTab, activeClazz);
                    Y.Dom.removeClass(activeTab.parentNode, activeClazz);
                    Y.Dom.addClass(activeContent, "invisible");
                }
                activeTab = tab;                
                var destHref = activeTab.getAttribute('href', 2);
                var href = destHref.substr( destHref.indexOf("#") + 1 );
                activeContent = Y.Dom.get(href);
                Y.Dom.removeClass(activeContent, "invisible");

                _tabChangeEvent.fire(href);
            }
        };

        var handleOnClick = function(e) {
            Y.Event.preventDefault(e);
        };

        for (var i = 0; i <parentElements.length; i++) {
            var tab = Y.Dom.getChildren(parentElements[i])[0];

            Y.Event.on(tab, "mousedown", handleOnMouseDown, tab);
            Y.Event.on(tab, "click", handleOnClick);
            tabs.push(tab);
        }

        this.destroy = function() {
            for (var i = 0; i < tabs.length; i++ ) { //alert("kkk "+i);
                Y.Event.removeListener( tabs[i], "mousedown", handleOnMouseDown );
                Y.Event.removeListener( tabs[i], "click", handleOnClick );
            }

        };

        this.disableTab = function( tabIndex ) {
            var selectedTab = tabs[ tabIndex ];
            if ( selectedTab != activeTab ) {
                Y.Dom.addClass(selectedTab, disableClazz);
                Y.Dom.addClass(selectedTab.parentNode, disableClazz);
            }
        };

        this.enableTab = function( tabIndex ) {
            var selectedTab = tabs[ tabIndex ];
            if ( selectedTab != activeTab ) {
                Y.Dom.removeClass(selectedTab, disableClazz);
                Y.Dom.removeClass(selectedTab.parentNode, disableClazz);
            }
        };

        this.switchToTab = function( tabIndex ) {
            var selectedTab = tabs[ tabIndex ];
            handleOnMouseDown(null, selectedTab);
        };

    };

    fitbit.app.Chart = function(id, chartDisplayId, chartType, dataURL, width, height, isVisible) {
        var chartTypeUrl;
        var so;
        var url = dataURL;


        var loadGraph = function(dataURL) {

            so = new SWFObject(chartTypeUrl, id, width, height, "8", "#FFFFFF", "best");

            so.addParam("wmode", "opaque");
            so.addVariable("chartWidth", width);
            so.addVariable("chartHeight", height);
            so.addVariable("dataURL", escape(dataURL));
            so.write(chartDisplayId);
        };

        switch (chartType) {
            case "column2d":
                chartTypeUrl = "/flash/charts/FC_2_3_MSColumn2D.swf.h83cc942ca6d138ecfacda4783ead4225.pack?items=%2Fflash%2Fcharts%2FFC_2_3_MSColumn2D.swf";
                break;
            case "area2d":
                chartTypeUrl = "/flash/charts/FC_2_3_MSArea2D.swf.ha0e53f6630b1e6d7c5f0227f987a9a51.pack?items=%2Fflash%2Fcharts%2FFC_2_3_MSArea2D.swf";
                break;
            case "line":
                chartTypeUrl = "/flash/charts/FC_2_3_MSLine.swf.hde181972901f41152c63867635d95a3e.pack?items=%2Fflash%2Fcharts%2FFC_2_3_MSLine.swf";
                break;
            case "linecolumn2d":
                chartTypeUrl = "/flash/charts/FC_2_3_MSColumnLine_DY_2D.swf.h45aefa24154a408eb57fd512d65adffc.pack?items=%2Fflash%2Fcharts%2FFC_2_3_MSColumnLine_DY_2D.swf";
                break;
            case "stackedarea2d":
                chartTypeUrl = "/flash/charts/FC_2_3_StackedArea_MSLine_DY_2D.swf.hd564554c605bde9bb0fcf891ba00cc87.pack?items=%2Fflash%2Fcharts%2FFC_2_3_StackedArea_MSLine_DY_2D.swf";
                break;
            case "pie":
                chartTypeUrl = "/flash/charts/FC_2_3_Pie2D.swf.hd2af07305c9f4cf8e18b437ba7da2acd.pack?items=%2Fflash%2Fcharts%2FFC_2_3_Pie2D.swf";
                break;
        }

        if (!isVisible) {
            Y.Dom.addClass(chartDisplayId, "invisible");
        } else {
            loadGraph(dataURL);
        }

        this.update = function(graphData) {

            if ( graphData != null ) {
                loadGraph(graphData);
            }
            else {
                loadGraph(url);
            }
        };

        this.hide = function() {
            Y.Dom.addClass(chartDisplayId, "invisible");
            fitbit.util.setContent(Y.Dom.get(chartDisplayId), "");
        };

        this.show = function() {
            Y.Dom.removeClass(chartDisplayId, "invisible");
        };
    };

    fitbit.app.EjsChart = function( id, type, title, dataURL, color ) {
        var firstSeries;
        var additionalSeries = new Array();

        var handler =  new EJSC.XMLDataHandler( dataURL ,
            { onDataReady: function( response , handler , series , chart ) {
                var axisX = chart.axis_bottom;
                var xml = response.responseXML;
                if ( xml == null ) {
                    return true;
                }

                var format = xml.getElementsByTagName('dateFormat')[0].firstChild.nodeValue;
                axisX.formatter.format_string = format;

                while( additionalSeries.length > 0 )  {
                    chart.removeSeries( additionalSeries.pop(), false );
                }

                var additionalDatasets = xml.getElementsByTagName('D');
                for ( var i=0; i<additionalDatasets.length; i++ )  {
                    var xml = additionalDatasets[i].firstChild.nodeValue;
                    var ser = getSeries( new EJSC.XMLStringDataHandler( xml ) );
                    ser.color = "#" + additionalDatasets[i].getAttribute("color");
                    additionalSeries.push( ser );
                    chart.addSeries( ser, false );
                }

                if ( additionalDatasets.length == 0 && type == 'column2d' ) {
                    var max = xml.getElementsByTagName('YMax')[0].firstChild.nodeValue;
                    var min = xml.getElementsByTagName('YMin')[0].firstChild.nodeValue;
                    var step = (max-min)/4;
                    series.addRange( min, min+step, "rgb(0,0,0)", 100, 100, 1, false );
                    series.addRange( min+step, min+2*step, "rgb(0,0,255)", 100, 100, 1, false  );
                    series.addRange( min+2*step, min+3*step, "rgb(0,255,0)", 100, 100, 1, false  );
                    series.addRange( min+3*step, min+4*step, "rgb(255,0,0)", 100, 100, 1, true  );
                }

                chart.redraw();
                return true;
            } }
        );

        var options = { //autosort : false,
            //groupedBars : false,
            color : color,
            useColorArray : false
        };

        var getSeries = function( hndlr ) {
            switch ( type ) {
                case "column2d":
                    return new EJSC.BarSeries( hndlr, options );
                case "area2d":
                    return  new EJSC.AreaSeries( hndlr, options );
                case "line":
                    return new EJSC.LineSeries( hndlr, options );
                case "pie":
                    return new EJSC.PieSeries( hndlr, options );
                default:
                    return null;
            }
        };

        var axisX = {
            formatter: new EJSC.DateFormatter({ format_string: 'MMM D, YYYY' }),
            visible: true,
            caption: ""
        };

        firstSeries = getSeries( handler );

        var ejsChart = new EJSC.Chart( id, {
                title : title,
                show_legend: false,
                axis_bottom: axisX,
                axis_left: { caption: "" }
        });

        ejsChart.addSeries( firstSeries );
        if ( type == "pie" ) {
           ejsChart.setShowLegend( true );
        }


        this.update = function( graphDataURL ) {
            if ( graphDataURL != null ) {
                firstSeries.getDataHandler().setUrl( graphDataURL );
            }
            firstSeries.reload();
        };

        this.hide = function() {
            Y.Dom.addClass( id, "invisible" );
        };

        this.show = function() {
            Y.Dom.removeClass( id, "invisible" );
        };
    };

    //to be continue...
    fitbit.app.AmChartNew = function(chartDisplayId, chartType, dataURL, settingsURL, isVisible) {
        var loadGraph = function() {
            var amFallback = new AmCharts.AmFallback();
            amFallback.settingsFile = settingsURL;
            amFallback.dataFile = dataURL;
            amFallback.pathToImages = "/amcharts/2.2.0/amcharts/javascript/images/";
            amFallback.type = chartType;
            amFallback.loading_settings = "Loading settings...";
            amFallback.loading_data = "Loading data...";
            amFallback.write(chartDisplayId);
        };

        if ( !isVisible ) {
            Y.Dom.addClass( chartDisplayId, "invisible" );
        } else {
            loadGraph();
        }

        this.update = function( ) {
            fitbit.util.setContent(Y.Dom.get( chartDisplayId ), "");
            loadGraph();
        };

        this.hide = function() {
            Y.Dom.addClass( chartDisplayId, "invisible" );
        };

        this.show = function() {
            Y.Dom.removeClass( chartDisplayId, "invisible" );
        };
    };
    
    fitbit.app.AmChart = function( id, chartDisplayId, chartType, dataURL, width, height, isVisible, usePrintWrapper, chartData ) {
        var chartTypeUrl;
        var so;
        var url = dataURL;
        

        var loadGraph = function( dataURL ) {
            var enablePrintableContainer = usePrintWrapper != undefined && usePrintWrapper != null && usePrintWrapper;
            var swfUrl = enablePrintableContainer
                ? "/flash/amcharts/swfPrintableContainer.swf.hbf1f74420bc3af2c2abb110d8b12a186.pack?items=%2Fflash%2Famcharts%2FswfPrintableContainer.swf"
                : chartTypeUrl;

            so = new SWFObject( swfUrl, id, width, height, "8", "#FFFFFF", "best" );
            so.addParam( "wmode", "opaque" );
            so.addParam( "hasPriority", "true" );
            so.addParam( "allowScriptAccess", "always" );
            so.addVariable( "path", "/flash/amcharts/" );
            so.addVariable( "settings_file", escape(dataURL) );
            so.addVariable( "data_file", escape("") );

            if ( enablePrintableContainer ) {
                so.addParam( "title",  chartDisplayId );
                so.addVariable( "amChartUrl", chartTypeUrl );
            }

            if ( chartData != undefined && chartData != null ) {
                so.addVariable( "chart_data", chartData );
            }

            //so.addVariable( "chart_settings", "" );
            if (chartType == "line") {
                so.addVariable("additional_chart_settings", escape("<settings><graphs><graph gid='0'><type>line</type></graph><graph gid='1'><type>line</type></graph><graph gid='2'><type>line</type></graph><graph gid='3'><type>line</type></graph><graph gid='4'><type>line</type></graph></graphs></settings>"));
            }

            if (chartType == "linecolumn2d") {
                so.addVariable("additional_chart_settings", escape("<settings><graphs><graph gid='0'></graph><graph gid='1'><type>line</type></graph><graph gid='2'><type>line</type></graph><graph gid='3'><type>line</type></graph><graph gid='4'><type>line</type></graph></graphs></settings>"));
            }
            //so.addVariable( "loading_settings", "LOADING SETTINGS"); // you can set custom "loading settings" text here
            //so.addVariable( "loading_data", "LOADING DATA" ); // you can set custom "loading data" text here
            so.addVariable( "preloader_color", "#999999" );
            so.addVariable( "chart_id", id );
            
            //--------------------------------------------------------------------------------------//
            //  Firefox print workaround                                                            //
            if ( enablePrintableContainer ) {
                // Pack swf into div & place into 1px visible div
                var container = document.createElement("div");
                container.id = "cont_" + fitbit.app.objectsCounter.toString();
                container.style.position = "absolute";
                container.style.left = fitbit.app.objectsCounter.toString() + "px";
                fitbit.app.objectsCounter++;
                
                document.getElementById("amChartsFixContainer").appendChild(container);
                so.write( container.id );
            }
            //                                                                                      //
            //--------------------------------------------------------------------------------------//
            else{
                so.write( chartDisplayId );
            }
            
            var sourceLinkElem = Y.Dom.get(chartDisplayId + "Source");
            if (sourceLinkElem != undefined) {
               sourceLinkElem.innerHTML = "<a target=\"_blank\" href=\"" + dataURL + "\">Source</a>";
            }
        };

        dataURL = dataURL + "&chart_type=" + chartType;
        switch ( chartType ) {
            case "pie":
                chartTypeUrl = "/flash/amcharts/ampie.swf.h87b02d99877ca264a5f2682201ab822d.pack?items=%2Fflash%2Famcharts%2Fampie.swf";
                break;
            case "trueline":
                chartTypeUrl = "/flash/amcharts/amline.swf.h3b6c48bead080bc8e17ada224cbf131b.pack?items=%2Fflash%2Famcharts%2Famline.swf";
                break;
            default:
                chartTypeUrl = "/flash/amcharts/amcolumn.swf.h051b2fc44abcc6e8b27e935f392397b2.pack?items=%2Fflash%2Famcharts%2Famcolumn.swf";
                break;
        }

        if ( !isVisible ) {
            Y.Dom.addClass( chartDisplayId, "invisible" );
        } else {
            loadGraph( dataURL );
        }

        this.update = function( graphData ) {
            Y.Dom.get( chartDisplayId ).innerHTML = "";
            if ( graphData != null ) {
                loadGraph( graphData );
            }
            else {
                loadGraph( url );
            }
        };

        this.hide = function() {
            Y.Dom.addClass( chartDisplayId, "invisible" );
            //fitbit.util.setContent( Y.Dom.get(chartDisplayId), "");
        };

        this.show = function() {
            Y.Dom.removeClass( chartDisplayId, "invisible" );
        };
    };

    fitbit.app.convertErrorsToList = function(errorsArray, listId, escapeHtml) {
        var errorString = "<div class='errorMessage'>"+fitbit.i18n.getResource('com.fitbit.app.error.errors_title')+"</div><div style='height: 100px; overflow: auto;'><ul class='errorList clearfix' style='margin-bottom: 15px;' id='" + listId + "'>";

        for (var i = 0; i < errorsArray.length; i++) {
            var errorMessage;
            if(errorsArray[i].errorType == "system"){
                // if 500 error happens we are getting errorType="system" and
                // message contains exception stack trace. We do not want to
                // exception stack trace to the user so instead we are displaying
                // generic message.
                errorMessage = fitbit.i18n.getResource('com.fitbit.app.error.general_fatal_error');
            }else{
                if (escapeHtml) {
                    errorMessage = fitbit.app.escapeHtml(errorsArray[i].message);
                } else {
                    errorMessage = errorsArray[i].message;
                }
            }

            errorString += "<li class='errorBullet'>" + errorMessage + "</li>";
        }

        return errorString + "</ul></div>";
    };

    fitbit.app.escapeHtml = function(originalString) {
        return originalString.split("&").join("&amp;").split( "<").join("&lt;").split(">").join("&gt;");
    };

    fitbit.app.unEscapeHtml = function(originalString) {
        return originalString.split("&amp;").join("&").split("&lt;").join("<").split("&gt;").join(">");
    };

    fitbit.app.UIState = function() {

        this.cookieName = "uis";
        this.state = null;

        this.set = function( index ) {
            this.state.add( index );
            this.saveState();
        };


        this.clearAndSet = function( indicesToClear, indicesToSet ) {
            if ( indicesToClear ) {
                if ( !org.antlr.lang.isArray( indicesToClear ) ) {
                    indicesToClear = [indicesToClear];
                }
                for ( var i = 0; i < indicesToClear.length; i++ ) {
                    this.state.clear( indicesToClear[ i ] );
                }
            }
            if ( indicesToSet ) {
                if ( !org.antlr.lang.isArray( indicesToSet ) ) {
                    indicesToSet = [indicesToSet];
                }
                for ( var i = 0; i < indicesToSet.length; i++ ) {
                    this.state.add( indicesToSet[ i ] );
                }
            }
            this.saveState();
        };

        this.clear = function( index ) {
            this.state.clear( index );
            this.saveState();
        };

        this.get = function( index ) {
            this.state.member( index );
        };

        this.getCookie = function( name ) {
            var results = document.cookie.match( '(^|;) ?' + name + '=([^;]*)(;|$)' );
            if ( results ) {
                return ( unescape ( results[2] ) );
            } else {
                return "";
            }
        };

        this.setCookie = function( name, value, exp_ms, path, domain, secure ) {
            var cookieString = name + "=" + escape ( value );
            if ( exp_ms ) {
                var expires = new Date ();
                expires.setTime( expires.getTime() + exp_ms );
                cookieString += "; expires=" + expires.toUTCString();
            }
            if ( path ) {
                cookieString += "; path=" + escape ( path );
            }
            if ( domain ) {
                cookieString += "; domain=" + escape ( domain );
            }
            if ( secure ) {
                cookieString += "; secure";
            }
            document.cookie = cookieString;
        };

        this.loadState = function() {
            var stateStr = this.getCookie( this.cookieName );

            if ( this.state == null ) {
                this.state = this.loadStateFromByteArray( this.base64Decode( stateStr ) );
            }
        };

        this.saveState = function() {
            var stateStr = this.base64Encode( this.saveStateToByteArray() );
            this.setCookie( this.cookieName, stateStr, 3600 * 24 * 365 * 1000, "/" );
        };

        this.loadStateFromByteArray = function( bytes ) {
            var bitSet = null;

            if ( bytes != null ) {
                var bytesLength = bytes.length;
                bitSet = new org.antlr.runtime.BitSet();
                for ( var i = 0; i < bytesLength * 8; i++ ) {
                    if ( ( bytes[bytesLength-Math.floor(i/8)-1]&(1<<(i%8)) ) > 0 ) {
                        bitSet.add( i );
                    }
                }
            }
            return bitSet;
        };

        this.saveStateToByteArray = function() {
            var bytes = null;
            if ( this.state != null ) {
                var size = 0;
                for ( var i = 0; i < this.state.numBits(); i++ ) {
                    if ( this.state.member( i ) ) {
                        size = i+1;
                    }
                }
                var bytesLength = Math.floor( size / 8 ) + 1;
                bytes = new Array();
                for ( var i = 0; i < bytesLength; i++ ) {
                    bytes[i] = 0;
                }
                for ( var i = 0; i < size; i++ ) {
                    if ( this.state.member( i ) ) {
                        bytes[bytesLength-Math.floor(i/8)-1] |= 1<<(i%8);
                    }
                }
            }
            return bytes;
        };


        this.base64Encode = function( data ) {
            var b64_map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
            var byte1, byte2, byte3;
            var ch1, ch2, ch3, ch4;
            var result = new Array(); //array is used instead of string because in most of browsers working with large arrays is faster than working with large strings
            var j=0;
            for ( var i = 0; i < data.length; i += 3 ) {
                byte1 = data[i];
                byte2 = data[i+1];
                byte3 = data[i+2];
                ch1 = byte1 >> 2;
                ch2 = ( ( byte1 & 3 ) << 4 ) | ( byte2 >> 4 );
                ch3 = ( ( byte2 & 15 ) << 2 ) | ( byte3 >> 6 );
                ch4 = byte3 & 63;

                if ( isNaN( byte2 ) ) {
                    ch3 = ch4 = 64;
                } else if ( isNaN( byte3 ) ) {
                    ch4 = 64;
                }

                result[ j++ ] = b64_map.charAt(ch1)+b64_map.charAt(ch2)+b64_map.charAt(ch3)+b64_map.charAt(ch4);
            }

            return result.join('');
        };

        this.base64Decode = function( data ) {
            data = data.replace(/[^a-z0-9\+\/=]/ig, ''); // strip none base64 characters
            var b64_map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
            var byte1, byte2, byte3;
            var ch1, ch2, ch3, ch4;
            var result = new Array(); //array is used instead of string because in most of browsers working with large arrays is faster than working with large strings
            var j=0;
            while ( ( data.length % 4 ) != 0 ) {
                data += '=';
            }

            for ( var i = 0; i < data.length; i += 4 ) {
                ch1 = b64_map.indexOf( data.charAt(i) );
                ch2 = b64_map.indexOf( data.charAt( i + 1 ) );
                ch3 = b64_map.indexOf( data.charAt( i + 2 ) );
                ch4 = b64_map.indexOf( data.charAt( i + 3 ) );

                byte1 = (ch1 << 2) | (ch2 >> 4);
                byte2 = ((ch2 & 15) << 4) | (ch3 >> 2);
                byte3 = ((ch3 & 3) << 6) | ch4;

                result[ j++ ] = byte1;
                if ( ch3 != 64 ) result[ j++ ] = byte2;
                if ( ch4 != 64 ) result[ j++ ] = byte3;
            }
            return result;
        };

        this.loadState();
    };

    fitbit.app.toggleScale = function( scaleName, on, uisIndex ) {
        if ( on ) {
            Y.Dom.addClass( scaleName + "ShowLink", "invisible" );
            Y.Dom.removeClass( scaleName + "Scale", "invisible" );
            new fitbit.app.UIState().clear( uisIndex );
        }
        else {
            Y.Dom.addClass( scaleName + "Scale", "invisible" );
            Y.Dom.removeClass( scaleName + "ShowLink", "invisible" );
            new fitbit.app.UIState().set( uisIndex );
        }
    };

    fitbit.app.highlightRow = function(elementId, on) {
        var highlightElement = Y.Dom.get(elementId);
        if (on) {
            Y.Dom.setStyle(highlightElement, "background-color", "#fffdcc");
        } else {
            Y.Dom.setStyle(highlightElement, "background-color", "");
        }

        return highlightElement;
   };

   fitbit.app.highlightRecord = function( recordType, recordId, on ) {
       //fitbit.app.highlightRow( recordType + "." + recordId, on );

       var actions = Y.Dom.get( recordType + "Actions." + recordId );

       if ( on ) {
           Y.Dom.removeClass( actions, "invisible" );
       } else {
           Y.Dom.addClass( actions, "invisible" );
       }
   };

   fitbit.app.highlightDelete = function(deleteImgId, on, isBackgroundOn) {
        var deleteImg = Y.Dom.get("deleteImg." + deleteImgId);
        if (on) {
            if (isBackgroundOn) {
                deleteImg.src = "/images/common/delete_red_yellow.gif";
            } else {
                deleteImg.src = "/images/common/delete_red_white.gif";
            }
        } else {
            if (isBackgroundOn) {
                deleteImg.src = "/images/common/delete_grey_yellow.gif";
            } else {
                deleteImg.src = "/images/common/delete_grey_white.gif";
            }
        }

        return deleteImg;
   };

    /*
     * Every element with an associated tooltip must have the "tooltip" class.
     *
     * For simple tooltips, a title attribute is enough.
     *   Example: <span class="tooltip" title="This is a tooltip">...</span>
     *
     * For tooltips containing HTML markup:
     *   1. Create a container with a unique id and the class "tooltip-content" (so that it's hidden by default)
     *   2. Give the element that triggers the tooltip a class with the format "ttid-<id_of_tooltip_content_container>"
     *
     *   Example:
     *      <span class="tooltip ttid-foo-bar">...</span>
     *      <div id="foo-bar" class="tooltip-content">
     *          <p>All HTML in here will be hidden by default.</p>
     *          <p>But it will be copied into the tooltip and displayed when the user mouses over</p>
     *      </div>
     */
    fitbit.app.loadTooltips = function() {
        var zIndex = 20000;
        var ttClass = 'tooltip';
        var ttPrefix = 'tooltip-';
        var ctxPrefix = 'ttid-';
        var ctxPrefixLen = ctxPrefix.length;
        var infiniteDelay = 100000000;

        for (var nodes = Y.Dom.getElementsByClassName(ttClass), i = nodes.length, args, id; i--;) {
            args = {context: nodes[i], zIndex: zIndex, autodismissdelay: infiniteDelay};
            if (args.context.title) {
                id = ttPrefix + i;
            } else {
                id = '';
                for (var classes = nodes[i].className.split(/\s+/), j = classes.length; j--;) {
                    if (classes[j].indexOf(ctxPrefix) == 0) {
                        var content = document.getElementById(classes[j].slice(ctxPrefixLen));
                        if (content) {
                            id = ttPrefix + content.id;
                            args.text = content.innerHTML;
                            break;
                        }
                    }
                }
            }

            function handleHover(e, tooltip) {
                for (var el = Y.Event.getRelatedTarget(e); el && el != this; el = el.parentNode);
                if (!el) {
                    if (e.type == 'mouseout') {
                        tooltip.hideProcId = setTimeout(function() { tooltip.hide() }
                            , tooltip.cfg.getProperty('hidedelay'));
                    } else {
                        clearTimeout(tooltip.hideProcId);
                    }
                }
            }

            if (id) {
                args.context.tooltip = new YAHOO.widget.Tooltip(id, args);
                args.context.tooltip.contextTriggerEvent.subscribe(
                    function(type, args) {
                        var tooltip = args[0].tooltip;
                        tooltip.contextTriggerEvent.unsubscribe(arguments.callee);
                        Y.Event.on(tooltip.id, 'mouseover', handleHover, tooltip);
                        Y.Event.on(tooltip.id, 'mouseout', handleHover, tooltip);
                    }
                );
            }
        }
    };

    fitbit.app.init = function() {
        fitbit.app.loadTooltips();
    };

    Y.Event.onDOMReady(fitbit.app.init);
})();

(function() {
    fitbit.namespace("fitbit.app.search.solr");

    fitbit.app.search.solr.food = {
        solrURL: "/solr/food/select",

        getQueryStringBaseInternal: function(queryParameter, qtParameter, fqParameter) {
            var q  = "?q=" + encodeURIComponent(queryParameter);
            var wt = "&wt=foodjson";
            var qt = qtParameter == null || qtParameter == "" ? "" : "&qt=" + qtParameter;
            var fq = fqParameter == null || fqParameter == "" ? "" : "&fq=" + encodeURIComponent(fqParameter);

            var queryString = q + wt + qt + fq;
            return queryString;
        },

        getQueryString: function(queryParameter, userIdParameter, qtParameter, fqParameter) {
            var fq = "(accessLevel:1" + (userIdParameter == "" || userIdParameter == null ? "" : " OR creatorId:" + userIdParameter + " OR userId:" + userIdParameter) + ")";
                fq = fq + (fqParameter == null || fqParameter == "" ? "" : " AND (" + fqParameter + ")");
            return this.getQueryStringBaseInternal( queryParameter, qtParameter, fq);
        },

        getQueryStringMyFoodsOnly: function(queryParameter, userIdParameter, qtParameter ) {
            var fq = "(creatorId:" + userIdParameter + " OR userId:" + userIdParameter + ")";
            return this.getQueryStringBaseInternal( queryParameter, qtParameter, fq);
        }

    };

    fitbit.app.search.solr.brand = {
        solrURL: "/solr/brand/select",

        getQueryStringBaseInternal: function(queryParameter, wtParameter, qtParameter, fqParameter, chunkSizeParameter, startParameter, rowsParameter) {
            var q  = "?q=" + encodeURIComponent(queryParameter);
            var wt = wtParameter == null || wtParameter == "" ? "&wt=brandjson" : "&wt=" + encodeURIComponent(wtParameter);
            var qt = qtParameter == null || qtParameter == "" ? "" : "&qt=" + encodeURIComponent(qtParameter);
            var fq = fqParameter == null || fqParameter == "" ? "" : "&fq=" + encodeURIComponent(fqParameter);

            var chunkSize = chunkSizeParameter == null || chunkSizeParameter == "" ? "" : "&chunkSize=" + encodeURIComponent(chunkSizeParameter);
            var start     = startParameter     == null || startParameter     == "" ? "" : "&start=" + encodeURIComponent(startParameter);
            var rows      = rowsParameter      == null || rowsParameter      == "" ? "" : "&rows=" + encodeURIComponent(rowsParameter);

            var queryString = q + wt + qt + fq + chunkSize + start + rows;
            return queryString;
        },

        getQueryString: function(queryParameter, userIdParameter, qtParameter, fqParameter, startParameter, rowsParameter) {
            var fq = this.getFilter(fqParameter, userIdParameter);
            return this.getQueryStringBaseInternal(queryParameter, null, qtParameter, fq, null, startParameter, rowsParameter);
        },

        getQueryStringForMenu: function(queryParameter, userIdParameter, qtParameter, fqParameter, chunkSizeParameter) {
            var fq = this.getFilter(fqParameter, userIdParameter);
            return this.getQueryStringBaseInternal(queryParameter, "brandindexjson", qtParameter, fq, chunkSizeParameter, null, null);
        },

        getFilter: function(fqParameter, userIdParameter) {
            var fq = "(brandIsPublic:true";
            if ( userIdParameter != '' ) {
                fq += " OR owner:" + userIdParameter;
            }
            fq += ")" + (fqParameter == null || fqParameter == "" ? "" : " AND (" + fqParameter + ")");

            return fq;
        }
    };

    fitbit.app.search.solr.activity = {
        solrURL: "/solr/activity/select",

        getQueryString: function(queryParameter, userIdParameter, qtParameter) {
            var q  = "?q=" + encodeURIComponent(queryParameter);
            var wt = "&wt=activityjson";
            var qt = qtParameter == null || qtParameter == "" ? "" : "&qt=" + qtParameter;
            var fq = "(accessLevel:1" + (userIdParameter == "" || userIdParameter == null ? "" : " OR creatorId:" + userIdParameter) + ")";
            fq = "&fq=" + encodeURIComponent(fq);

            var queryString = q + wt + qt + fq;

            return queryString;
        }
    };

    fitbit.app.search.solr.forum = {
        solrURL: "/solr/forum/select",

        getQueryStringBaseInternal: function(queryParameter, qtParameter, fqParameter) {
            var q  = "?q=" + encodeURIComponent(queryParameter);
            var wt = "&wt=forumjson";
            var qt = qtParameter == null || qtParameter == "" ? "" : "&qt=" + qtParameter;
            var fq = fqParameter == null || fqParameter == "" ? "" : "&fq=" + encodeURIComponent( fqParameter );

            var queryString = q + wt + qt + fq;
            return queryString;
        },

        getQueryStringAdmin: function(queryParameter) {
            var fq = "";
            var qt = "forum";
            return this.getQueryStringBaseInternal(queryParameter, qt, fq);
        },

        getQueryString: function(queryParameter, userIdParameter) {
            var fq = "((postStatus:0 AND topicStatus:0) OR (postOwnerId:" + userIdParameter + " OR topicOwnerId:" + userIdParameter + "))";
            var qt = "forum";
            return this.getQueryStringBaseInternal(queryParameter, qt, fq);
        },

        getQueryStringForHightlightedPost: function(postId, queryParameter) {
            var fq = "id:" + postId;
            var qt = "post_hl";
            var q  = "id:" + postId + " " + queryParameter;
            return this.getQueryStringBaseInternal(q, qt, fq);
        }
    };

    fitbit.app.search.solr.friend = {
        solrURL: "/solr/friend/select",

        getQueryStringBaseInternal: function( queryParameter, qtParameter, fqParameter ) {
            var q  = "?q=" + encodeURIComponent(queryParameter);
            var wt = "&wt=friendjson";
            var qt = qtParameter == null || qtParameter == "" ? "" : "&qt=" + qtParameter;
            var fq = fqParameter == null || fqParameter == "" ? "" : "&fq=" + encodeURIComponent(fqParameter);

            var queryString = q + wt + qt + fq;
            return queryString;
        },

        getQueryString: function( queryParameter, userEncodedIdParameter, qtParameter, fqParameter ) {
            var fq = "(userEncodedId:" + userEncodedIdParameter + " AND friendshipDiscontinued:false)";
                fq = fq + (fqParameter == null || fqParameter == "" ? "" : " AND (" + fqParameter + ")");
            return this.getQueryStringBaseInternal( queryParameter, qtParameter, fq);
        }
    };

})();

