Ext.namespace('twowayfitness');

twowayfitness.debug_break = function()
{
    var bla = 42;
};

twowayfitness.onDocReady = function(fun)
{
    Ext.onReady(fun);
    // alert("twowayfitness.onDocReady");
    // Ext.EventManager.onDocumentReady(
    //    fun,
    //    window,
    //    {
    //      delay: 5000
    //    }
    // );
};


// function log(message) {
//     if (!log.window_ || log.window_.closed) {
//         var win = window.open("", null, "width=400,height=200," +
//                               "scrollbars=yes,resizable=yes,status=no," +
//                               "location=no,menubar=no,toolbar=no");
//         alert("LOG");
//         if (!win) return;
//         alert("LOG 2");
//         
//         var doc = win.document;
//         doc.write("<html><head><title>Debug Log</title></head>" +
//                   "<body></body></html>");
//         doc.close();
//         log.window_ = win;
//     }
//     var logLine = log.window_.document.createElement("div");
//     logLine.appendChild(log.window_.document.createTextNode(message));
//     log.window_.document.body.appendChild(logLine);
//     alert("LOG leaving");
// }

// This function returns the name of a given function. It does this by
// converting the function to a string, then using a regular expression
// to extract the function name from the resulting code.
function funcname(f) {
    var s = f.toString().match(/function (\w*)/)[1];
    if ((s == null) || (s.length == 0)) return "anonymous";
    return s;
}

// This function returns a string that contains a "stack trace."
function stacktrace(depth) {
    var s = "STACK: ";  // This is the string we'll return.
    // Loop through the stack of functions, using the caller property of
    // one arguments object to refer to the next arguments object on the
    // stack.
    // s += arguments.callee;
    // s += "==========="
    // s += arguments.callee.caller;
    // s += "==========="
    // s += arguments.callee.caller.caller;
    // s += "==========="
    
    var count = 3;
    for(var f = arguments.callee.caller; f != null && count != 0; f = f.caller) {
        s += f;
        s += "===========\n";
        count--;
        
    //     s += " . ";
    //     // Add the name of the current function to the return value.
    //     s += funcname(a.callee) + "\n";
    // 
    //     // Because of a bug in Navigator 4.0, we need this line to break.
    //     // a.caller will equal a rather than null when we reach the end 
    //     // of the stack. The following line works around this.
    //     if (a.caller == a) break;
    }
    return s;
}


// _StackTrace = function() {
//     _StackTrace.initializeBase(this);
// };
// _StackTrace.prototype = {
//     _getFunctionName: function(theFunction) {
//         if (theFunction.name) {
//             return theFunction.name;
//         }
//         var definition = theFunction.toString();
//         var name = definition.substring(definition.indexOf(‘
//         function’) + 8, definition.indexOf(‘ (’));
//         if (name) {
//             return name;
//         }
//         return“anonymous”;
//     },
//     _getSignature: function(theFunction) {
//         var signature = newSys.StringBuilder(this._getFunctionName(theFunction));
//         signature.append(“ (”);
//         for (var x = 0; x < theFunction.arguments.length; x++) {
//             var nextArgument = theFunction.arguments[x];
//             if (nextArgument.length > 30) {
//                 nextArgument = nextArgument.substring(0, 30) + “…”;
//             }
//             signature.append(String.format(“‘ {
//                 0
//             }’”, nextArgument));
//             // comma separator
//             if (x < theFunction.arguments.length - 1) {
//                 signature.append(“, “);
//             }
//         }
//         signature.append(“)”);
//         return signature.toString();
//     },
//     createStackTrace: function(startingPoint) {
//         var stackTraceMessage = newSys.StringBuilder(“Stack trace: n”);
//         var nextCaller = startingPoint;
//         while (nextCaller) {
//             stackTraceMessage.appendLine(this._getSignature(nextCaller));
//             nextCaller = nextCaller.caller;
//         }
//         stackTraceMessage.appendLine();
//         stackTraceMessage.appendLine();
//         return stackTraceMessage;
//     }
// };
// _StackTrace.registerClass(“_StackTrace”);
// Sys.Application.add_init(
// function() {
//     StackTrace = new_StackTrace();
// }
// );
// Sys.Application.notifyScriptLoaded();



// A window that automatically sizes and positions itself with respect
// to another component defined by the constrain_to config setting.
// If constrain_to is not specified, then the size and position of the window
// will not be altered.
//
// In order for the automatic sizing and position to work, auto_height should not
// be set to true.
twowayfitness.PopupWindow = Ext.extend(Ext.Window, {
    constructor: function(config) {
        // jstracer.write('PopupWindow constructor keys = ' + Object.keys(this));
        
        // Your preprocessing here
        twowayfitness.PopupWindow.superclass.constructor.apply(this, [ config ]);
        // Your postprocessing here
    },
    constrainedSize : function(container_size, this_size, use_max) {
        var max = container_size - 20; // leave a little room on each side
        var ret = use_max ? max : (this_size > max ? max : this_size);
        // alert('this_size = ' + this_size);
        return ret;
    },
    constrainedPosition : function(container_size, container_position, this_size) {
        var leftover = container_size - this_size;
        return container_position + leftover/2;
    },
    setSizeAndPosition: function() {
        Ext.log('setSizeAndPosition');
        // this.layout();
        var container = this.constrain_to;
        if(!container) {
            container = twowayfitness.main_panel;
        }
        if(container) {
            this.setWidth(this.constrainedSize(container.getSize().width, this.getSize().width));
            var new_height = this.constrainedSize(container.getSize().height, this.getSize().height, this.use_max_possible_height);
            
            if(this.twoWaybeingResized) {
                this.twoWaybeingResized(new_height);
            }
            
            Ext.log('setSizeAndPosition setting height = ' + new_height);
            this.setHeight(new_height);

            var container_position = container.getPosition();
            
            var new_x = this.constrainedPosition(container.getSize().width, container_position[0], this.getSize().width);
            var new_y = this.constrainedPosition(container.getSize().height, container_position[1], this.getSize().height);
            
            this.setPosition(new_x, new_y);
            
            // this.doLayout();
        }
    },
    // override 
    initComponent : function() {
        Ext.applyIf(this, {
            cls: 'popup',
            title: 'Notice',
            // constrain_to: twowayfitness.viewport,            
            showCloseButtons: true
        });
        
        Ext.applyIf(this, {
            autoScroll: true,
            bodyStyle: 'position:relative;' // I need this for IE. Don't really know why :-(. See http://extjs.com/forum/showthread.php?t=17348
        });

        // this doesn't work if it's an applyIf. Not sure why. This means that users of this class cannot override the 'constrain' setting.
        Ext.apply(this, {
            constrain: true
        });

        if(this.showCloseButtons) {
            Ext.applyIf(this, {
                tbar: [
                    {
                        text: "Close",
                        tooltip: "Close this window",
                        handler: function() {
                            this.hide();
                        },
                        scope: this
                    }
                ]
            });
        }
        
        if(!this.deferSizing) {
            this.addListener(
                {
                    'show' : {
                        fn: function() {
                            this.setSizeAndPosition();
                        },
                        scope: this
                    }
                }
            );
        }
        
        twowayfitness.PopupWindow.superclass.initComponent.call(this);
    }
});

twowayfitness.HtmlPopupWindow = Ext.extend(twowayfitness.PopupWindow, {
    constructor: function(config) {
        this.config = config;
        twowayfitness.HtmlPopupWindow.superclass.constructor.apply(this, [ config ]);
    },
    // override 
    initComponent : function() {
        var self = this;
        
        var panel_config = null;
        if(this.url) {
            Ext.applyIf(this, {
                autoLoad: {
                    url: this.url,
                    text: 'Fetching ...',
                    scripts: true,
                    callback: function(el, success, response) {
                        if(success) {
                            self.setSizeAndPosition();
                        } else {
                            this.hide();
                            Ext.Msg.show({
                               title:'Alert',
                               msg: 'Unfortunately we failed to fetch that document. Perhaps it has been deleted recently.',
                               buttons: Ext.Msg.OK,
                               icon: Ext.MessageBox.ERROR
                            });                            
                        }
                    },
                    scope: this
                }
            });
        }
        
        Ext.applyIf(this, {
            width: 700,
            maximizable: true
        });
        
        // Ext.applyIf(this,
        //     {
        //         width: 700,
        //         maximizable: true,
        //         items: [
        //             new Ext.Panel(panel_config)
        //         ]
        //     }
        // );
        
        // finally call the superclasses implementation
        twowayfitness.HtmlPopupWindow.superclass.initComponent.call(this);
        
        // alert('id = ' + this.id);
        Ext.ComponentMgr.register(this);
    }
});

twowayfitness.HelpWindow = Ext.extend(twowayfitness.HtmlPopupWindow, {
    constructor: function(help_key, config) {
        this.help_key = help_key;
        Ext.applyIf(config, {
            deferSizing: true,
            url: "/help/" + help_key
        });
        twowayfitness.HelpWindow.superclass.constructor.apply(this, [ config ]);
    }
});

twowayfitness.displayHtmlFromUrlPopup = function(url, config)
{
    config = config ? config : {};
    Ext.applyIf(config, {
        url: url,
        deferSizing: true
    });
    
    var window = new twowayfitness.HtmlPopupWindow(
        config
    );
    window.show();
};

twowayfitness.displayHtmlPopup = function(html, config)
{
    config = config ? config : {};
    Ext.applyIf(config, {
        showCloseButtons: false,
        constrain_to: twowayfitness.main_panel,
        html: html 
    });
    // config.html = html;
    var window = new twowayfitness.HtmlPopupWindow(
        config
    );
    window.show();
};

twowayfitness.displayHelp = function(help_key)
{
    var window = new twowayfitness.HelpWindow(
        help_key,
        {
            title: 'Help'
        }
    );
    window.show();
};

twowayfitness.showMessage = function(html, config) {
    config = config ? config : {};
    Ext.applyIf(config, {
        title: 'Notice',
        showCloseButtons: false,
        width: 550,
        buttons: [
            {
                text: 'OK',
                handler: function(button) {
                    button.findParentByType(twowayfitness.HtmlPopupWindow).hide();
                }

            }
        ]
    });

    twowayfitness.displayHtmlPopup(html, config);
};

twowayfitness.showPlainMessage = function(string, options) {
    var html = "<p class='instructions'>" + string + "</p";
    twowayfitness.showMessage(html, options);
};


twowayfitness.micksPlugin = {
    init: function(component) {
        Ext.apply(component, {
            log: function(message) {
                if(this.should_log) {
                    Ext.log(message);
                }
            },
            adjust_size: function()
            {
//                this.log('micksPlugin adjust_size');
                var p = this;
                var size = p.getSize();
                var orig_width = size.width;
                var orig_height = size.height;
                this.log('micksPlugin adjust_size getSize() width = ' + orig_width + ' height = ' + orig_height);
//                this.log('   min_width = ' + p.min_width);
//                this.log('   min_height = ' + p.min_height);

                var determine_width = function(height, aspect_ratio) {
                    return height * aspect_ratio;
                };

                var determine_height = function(width, aspect_ratio) {
                    Ext.log('determine_height width = ' + width + ' aspect_ratio = ' + aspect_ratio);
                    return width / aspect_ratio;
                };

                var new_height = orig_height;
                var new_width = orig_width;

                if(p.size_determined_by) {
                    if(p.size_determined_by == 'width') {
                        // set height impossibly large. It will be fixed up shortly.
                        new_height = 999999;
                    } else {
                        new_width = 999999;
                    }
                }

                if(p.min_width) {
                    if(orig_width < p.min_width) {
                        new_width = p.min_width;
                         //console.log('   width too small, setting to ' + new_width);
                    }
                }
                if(p.min_height) {
                    if(orig_height < p.min_height) {
                        new_height = p.min_height;
                        this.log('   height too small, setting to ' + new_height);
                    }
                }

                if(p.min_aspect_ratio || p.aspect_ratio) {
                    var aspect_ratio = p.aspect_ratio;
                    this.log('aspect_ratio = ' + p.aspect_ratio + ' min_aspect_ratio = ' + p.min_aspect_ratio + ' max_aspect_ratio = ' + p.max_aspect_ratio);
                    if(p.min_aspect_ratio) {
                        // console.log('    checking aspect_ratio h = ' + new_height + ' w = ' + new_width);
                        aspect_ratio = (new_width * 1.0) / new_height; // this is the aspect ratio that would give the maximum chart area

                        Ext.log('maximal aspect ratio = ' + aspect_ratio);

                        // ensure aspect ratio does not exceed limits
                        if(aspect_ratio < p.min_aspect_ratio) {
                            aspect_ratio = p.min_aspect_ratio;
                        }
                        else if(aspect_ratio > p.max_aspect_ratio) {
                            aspect_ratio = p.max_aspect_ratio;
                        }
                    }

                    // now work out whether the height or the width should determine the overall size
                    height1 = determine_height(new_width, aspect_ratio);
                    width1 = determine_width(new_height, aspect_ratio);
                    if(height1 > new_height) {
                        new_width = width1;
                    } else {
                        new_height = height1;
                    }
                }

//                    if(p.size_determined_by) {
//                        var average_aspect_ratio = ((p.min_aspect_ratio + p.max_aspect_ratio) / 2);
//                        if(p.size_determined_by == 'width')
//                        {
//                            var aspect_ratio = (new_width * 1.0) / new_height; // this is the aspect ratio that would give the maximum chart area
//
//                            Ext.log('maximal aspect ratio = ' + aspect_ratio);
//
//                            // ensure aspect ratio does not exceed limits
//                            if(aspect_ratio < p.min_aspect_ratio) {
//                                aspect_ratio = p.min_aspect_ratio;
//                            }
//                            else if(aspect_ratio > p.max_aspect_ratio) {
//                                aspect_ratio = p.max_aspect_ratio;
//                            }
//
//                            new_height = determine_height(new_width, aspect_ratio);
//                        } else {
//                            new_width = determine_width(new_height, average_aspect_ratio);
//                        }
//                    } else {
//                        var current_ratio = (new_width * 1.0)/new_height;
//                        if(current_ratio < p.min_aspect_ratio) {
//                            new_height = determine_height(new_width, p.min_aspect_ratio);
//                            if(new_height < p.min_height) {
//                                new_height = p.min_height;
//                                new_width = determine_width(new_height, p.min_aspect_ratio);
//                            }
//                        } else if(current_ratio > p.max_aspect_ratio) {
//                            new_width = determine_width(new_height, p.max_aspect_ratio);
//                            if(new_width < p.min_width) {
//                                new_width = p.min_width;
//                                new_height = determine_height(new_width, p.max_aspect_ratio);
//                            }
//                        }
//
//
//                    }
//                else if(p.aspect_ratio) {
//                    // console.log('    checking aspect_ratio h = ' + new_height + ' w = ' + new_width);
//                    if(p.size_determined_by) {
//                        if(p.size_determined_by == 'width')
//                        {
//                            new_height = determine_height(new_width, p.aspect_ratio);
//                        } else {
//                            new_width = determine_width(new_height, p.aspect_ratio);
//                        }
//                    } else {
//                        var current_ratio2 = (new_width * 1.0)/new_height;
//
//                        var ratio = current_ratio2 / p.aspect_ratio;
//                        // only adjust aspect ratio if it is significantly out of whack
//                        if(ratio > 1.01) {
//                            new_width = determine_width(new_height, p.aspect_ratio);
//                            if(new_width < p.min_width) {
//                                new_width = p.min_width;
//                                new_height = determine_height(new_width, p.aspect_ratio);
//                            }
//                            // console.log('    changing width = ' + new_width);
//                        }
//                        if(ratio < 0.99) {
//                            new_height = determine_height(new_width, p.aspect_ratio);
//                            if(new_height < p.min_height) {
//                                new_height = p.min_height;
//                                new_width = determine_width(new_height, p.aspect_ratio);
//                            }
//                            // console.log('    changing_height = ' + new_height);
//                        }
//                    }
//                }

                // only call setSize if we are actually changing the size
                if(new_width != orig_width || new_height != orig_height) {
                    p.inside_resize = true;
                    this.log('    setting size to = ' + new_width + ' by ' + new_height);
                    p.setSize(new_width, new_height);

                    // is this needed?
//                    p.ownerCt.syncSize();
//                    p.ownerCt.doLayout();



                    // var parent = component.findParentBy(function() { return true; });
                    // console.log('   parent = ' + parent);
                    // parent.doLayout();

                    p.inside_resize = false;
                }
            }
        });

        component.on('bodyresize',
            function(p, width, height) {
                this.log('bodyresize width = ' + width + ' height = ' + height);
                if(p.inside_resize) {
                    this.log('bodyresize detected RECURSIVE call. exiting early.');
                    return;
                }
                component.adjust_size();
            }
        ); 
    }
};

twowayfitness.makePanel = function(config)
{
    Ext.apply(config, {
        plugins: twowayfitness.micksPlugin
    });
    var ret = new Ext.Panel(config);
    return ret;
};

// twowayfitness.FieldCreator = Ext.extend(Object, {


//twowayfitness.Panel = Ext.extend(Ext.Panel, {
//    initComponent: function() {
//        var self = this;
//
//        self.on('bodyresize',
//            function(p, width, height) {
//                if(p.inside_resize) {
//                    console.log('bodyresize detected recursive call. exiting early.');
//                    return;
//                }
//
//                var size = p.getSize();
//                var orig_width = size.width;
//                var orig_height = size.height;
//                console.log('bodyresize getSize() width = ' + orig_width + ' height = ' + orig_height);
//                // console.log('   min_width = ' + p.min_width);
//
//                var new_height = orig_height;
//                var new_width = orig_width;
//
//                if(p.min_width != undefined) {
//                    if(orig_width < p.min_width) {
//                        new_width = p.min_width;
//                        // console.log('   width too small, setting to ' + new_width);
//                    }
//                }
//                if(p.min_height != undefined) {
//                    if(orig_height < p.min_height) {
//                        new_height = p.min_height;
//                        // console.log('   height too small, setting to ' + new_height);
//                    }
//                }
//
//                if(p.min_aspect_ratio != undefined) {
//                    // console.log('    checking aspect_ratio h = ' + new_height + ' w = ' + new_width);
//                    var current_ratio = (new_width * 1.0)/new_height;
//
//                    if(current_ratio < p.min_aspect_ratio) {
//                        new_height = new_width / p.min_aspect_ratio;
//                        if(new_height < p.min_height) {
//                            new_height = p.min_height;
//                            new_width = new_height * p.min_aspect_ratio;
//                        }
//                    } else if(current_ratio > p.max_aspect_ratio) {
//                        new_width = new_height * p.max_aspect_ratio;
//                        if(new_width < p.min_width) {
//                            new_width = p.min_width;
//                            new_height = new_width / p.max_aspect_ratio;
//                        }
//                    }
//                }
//                else if(p.aspect_ratio != undefined) {
//                    // console.log('    checking aspect_ratio h = ' + new_height + ' w = ' + new_width);
//                    var current_ratio = (new_width * 1.0)/new_height;
//
//                    var ratio = current_ratio / p.aspect_ratio;
//                    // only adjust aspect ratio if it is significantly out of whack
//                    if(ratio > 1.01) {
//                        new_width = new_height * p.aspect_ratio;
//                        if(new_width < p.min_width) {
//                            new_width = p.min_width;
//                            new_height = new_width / p.aspect_ratio;
//                        }
//                        // console.log('    changing width = ' + new_width);
//                    }
//                    if(ratio < 0.99) {
//                        new_height = new_width / p.aspect_ratio;
//                        if(new_height < p.min_height) {
//                            new_height = p.min_height;
//                            new_width = new_height * p.aspect_ratio;
//                        }
//                        // console.log('    changing_height = ' + new_height);
//                    }
//                }
//
//                if(new_width != orig_width || new_height != orig_height) {
//                    p.inside_resize = true;
//                    p.setSize(new_width, new_height);
//                    console.log('    setting size to = ' + new_width + ' by ' + new_height);
//
//                    p.inside_resize = false;
//                }
//            }
//        );
//
//        twowayfitness.Panel.superclass.initComponent.call(this);
//    }
//});


// A PopupWindow with some standard buttons and a form for a body.
twowayfitness.Dialog = Ext.extend(twowayfitness.PopupWindow, {
    initComponent: function() {
        var self = this;
        
        var formConfig = {
            // autoScroll: true,
            style:'padding: 5px 5px 0',
            bodyStyle:'padding: 5px 5px 0',
            labelWidth: 125,
            labelAlign: 'right'
        };

        Ext.applyIf(this.form_panel, formConfig);
         
        Ext.applyIf(this, {
           save_button_text: 'Ok' 
        });

        var buttons = [
                    {
                        text: this.save_button_text,
                        handler: function() {
                            self.got_ok();
                        }
                    },
                    {
                        text: 'Cancel',
                        handler: function() {
                            self.hide();
                        }
                    },
                    {
                        text: 'Help',
                        handler: function() {
                            twowayfitness.displayHelp(self.help_key);
                        }
                    }
                ];
        
        
        Ext.applyIf(this, {
             // width: 500,
             keys: [
                {
                    key: Ext.EventObject.ENTER,
                    handler: function() {
                        if(self.submitOnEnter)
                        {
                            self.got_ok();
                        }
                    },
                    scope: self
                }
             ],
            submitOnEnter: true,
             autoScroll: true,
             monitorResize: true,
             stateful: false,
             // layout: 'fit',
             showCloseButtons: false,
             autoHeight: true,
             closeAction:'hide',
             // modal: false,
             closable: true,
             items: this.formPanel,
             buttons: buttons
         });
         
         twowayfitness.Dialog.superclass.initComponent.call(this);
    }
});

twowayfitness.null_progress_dialog = {
    hideProgress: function() {
        // do nothing
    },
    startProgress: function() {
        // do nothing
    }
};

twowayfitness.RestDialog = Ext.extend(twowayfitness.Dialog, {
    got_ok: function() {
        this.formPanel.dosubmit();
    },
    submission_uri: function() {
        var self = this;
        if(self.REST_uri) {
            return self.REST_uri;
        } else {
            if(self.data) {
                // it's an update
                return self.container_uri() + '/' + self.data[self.object_name + '[id]'] + '?format=ext_json';
            } else {
                // it's a create request
                return self.container_uri() + '/'; // do I need this trailing slash?
            }
        }
    },
    container_uri: function() {
        if(this.REST_container_uri) {
            return this.REST_container_uri;
        } else {
            return '/' + this.REST_key;
        }
    },
    hideProgress: function() {
        this.progressCount -= 1;
        if(this.progressCount == 0) {
            this.hide();
            this.progressBox.hide();
        }
    },
    startProgress: function() {
        this.progressCount += 1;
    },
    initComponent: function() {
        this.addEvents('submitted', 'cancelled');
        
        var self = this;

        var baseParams = {
            'authenticity_token': this.form_authenticity_token
        };
        
        var formConfig = {
            bodyStyle:'padding: 5px 5px 0',
            labelWidth: 125,
            labelAlign: 'right',
            baseParams: baseParams,
            
            defaults:
                {
                    width: 300
                },
            items: self.form_items,
            dosubmit: function() {
                if(self.beforeSubmit) {
                    self.beforeSubmit();
                }
            
                var url = self.submission_uri();
                
                if(self.data) {
                    // it's an update request
                    baseParams['_method'] = 'put';
                } else {
                    // it's a create request
                }
                
                if(self.standardSubmit) {
                    // copied the following from the Ext doco. Don't know why they don't just do this for you.
                    var O = self.formPanel;
                    if (O.getForm().isValid()) {
                        O.getForm().standardSubmit = true;
                        O.getForm().getEl().dom.action = url;
                        if (O.baseParams) {
                            for (var i in O.baseParams) {
                                O.add({
                                    xtype: 'hidden',
                                    name: i,
                                    value: O.baseParams[i]
                                });
                            }
                            O.doLayout();
                        }
                        O.getForm().submit();
                    }
                } else {
                    self.progressBox = Ext.Msg.wait(self.submit_progress_message);
                    
                    self.formPanel.getForm().submit(
                        {
                            url: url,
                            success: function(form, action) {
                                var result = action.result;
                                self.progressCount = 1;
                            
                                self.fireEvent('submitted', this, result);
                            
                                // following is old fashioned way to fire the event. TODO: deprecate it
                                if(self.dataSaved) {
                                    self.dataSaved(result);
                                }
                            
                                if(!self.manualProgressDismiss) {
                                    self.hide();
                                    self.progressBox.hide();
                                }
                            },
                            failure: function(form, action) {
                                self.progressBox.hide();
                                twowayfitness.handle_form_submission_failure(form, action);
                            }
                        }
                    );
                }
            }
        };

        Ext.apply(formConfig, this.form_panel_config);
        
        Ext.applyIf(this, {
             save_button_text: 'Save Changes'
         });
        
         
        // alert('self.form_items = ' + self.form_items.size());

        // alert('formPanel.items = ' + formPanel.items.size());
        var buttons = [
                    {
                        text: this.save_button_text,
                        // el: 
                        handler: function() {
                            self.formPanel.dosubmit();
                        }
                    },
                    {
                        text: 'Cancel',
                        handler: function() {
                            self.hide();
                            self.fireEvent('cancelled', this);
                        }
                    }
                ];

        if(self.help_key) {
            buttons.push(
                {
                    text: 'Help',
                    handler: function() {
                        twowayfitness.displayHelp(self.help_key);
                    }
                }
            );
        }

        Ext.applyIf(this, {
             autoScroll: true,
             monitorResize: true,
             save_button_text: 'Save Changes',
             submit_progress_message: 'Saving Changes',
             stateful: false,
             showCloseButtons: false,
             formPanel: new Ext.FormPanel(formConfig),
             autoHeight: true,
             closeAction:'hide',
             closable: true,
             buttons: buttons
         });
         
         twowayfitness.RestDialog.superclass.initComponent.call(this);
    }
});

twowayfitness.AnyChartPanelSuper = Ext.extend(Ext.Panel, {
    createChart: function() {
        if(this.rendered) {
            if(!this.chart) {
               this.chart = new AnyChart('/anychart_5_1_2/swf/' + this.swf);
               this.chart.wMode = 'transparent';
               this.chart.width = "100%";
               this.chart.height = "100%";
               // this.chart.waitingForDataText = "Please select desired chart";
               if(this.waitingForDataText) {
                   this.chart.waitingForDataText = this.waitingForDataText;
               }
               this.chart.xmlLoadingText = "Loading chart data";
               if(this.data_xml) {
                   this.chart.setData(this.data_xml);
               }

               if(this.url) {
                   this.chart.setXMLFile(this.url);
               }
               // jstracer.write('calling this.chart.write this.body.id = ' + this.body.id);
               this.chart.write(this.body.id);
            }
            //  else {
            //     jstracer.write('re-calling this.chart.write this.body.id = ' + this.body.id);
            //     this.chart.write(this.body.id);
            // }
            return true;
        }
        return false;
    },
    redisplay: function() {
        this.createChart();
    },
    setData: function(data_xml) {
//        Ext.log('AnyChartPanelSuper::setData()');
        this.data_xml = data_xml;
        if(this.createChart()) {
            this.chart.setData(data_xml);
            if(this.avoid_IE_memory_leaks) {
                // jstracer.write('avoiding leaks');
                this.chart.interactive = false;
                var chart_html = this.chart.getMixedHTML();
                this.chart_panel.body.update(chart_html);
                this.chart_panel.body.on('click', function() {
                    alert('got click');
                });
            }
        }   
    },
    setUrl: function(url) {
        this.url = url;
        
        if(this.createChart()) {
            // jstracer.write('calling setXMLFile(' + url + ')');
            this.chart.setXMLFile(url);
        }
    },
    // override initComponent
    initComponent: function() {
        var self = this;
        
        Ext.applyIf(this, {
            avoid_IE_memory_leaks: false,
            monitorResize: true,
            html: "<div class='instructions'><p>To view 2Way Fitness Analytics charts you will need to install the free Adobe flash plugin.</p><p><a href='http://get.adobe.com/flashplayer/'><img src='/images/flashplayer_100x100.jpg'/></a></p><p>Please click <a href='http://get.adobe.com/flashplayer/'>here<a> to get the Flash player.</p></div>",
            
            
            plugins: twowayfitness.micksPlugin,
//            should_log: true,
            border: false
        });
        
        this.addListener({
            'afterrender': {
                fn: function() {
//                    Ext.log('Got AnyChartPanel::afterrender event. rendered = ' + self.rendered);
                    self.createChart();
                }
            }
        });

        this.on('expand', function() {
           alert('expand'); 
        });
        
        this.on('show', function() {
           alert('show'); 
        });
        twowayfitness.AnyChartPanelSuper.superclass.initComponent.call(this);
    }
});

twowayfitness.AnyChartPanel = Ext.extend(twowayfitness.AnyChartPanelSuper, {
    // override initComponent
    initComponent: function() {
        Ext.applyIf(this, {
            swf: 'AnyChart.swf',
            aspect_ratio: 1.8,
            min_height: 300
        });
        
        twowayfitness.AnyChartPanel.superclass.initComponent.call(this);
    }
});

twowayfitness.AnyGaugePanel = Ext.extend(twowayfitness.AnyChartPanelSuper, {
    // override initComponent
    initComponent: function() {
        Ext.applyIf(this, {
            // border: true,
            avoid_IE_memory_leaks: false,
            // min_height: 1,
            // min_width: 1,
            swf: 'Gauge.swf'
        });
        // call the superclass's initComponent implementation
        twowayfitness.AnyGaugePanel.superclass.initComponent.call(this);
    }
});

// twowayfitness.AnyChartPanel = Ext.extend(Ext.Panel, {
//     createChart: function() {
//         if(this.rendered && this.chart_panel.rendered) {
//             if(!this.chart || this.avoid_IE_memory_leaks) {
//                jstracer.write('creating new chart');
//                this.chart = new AnyChart('/anychart_5_1_2/swf/' + this.swf);
//                this.chart.wMode = 'transparent';
//                this.chart.width = "100%";
//                this.chart.height = "100%";
//                
//                if(this.avoid_IE_memory_leaks) {
//                    this.chart.interactive = false;
//                } else {
//                    jstracer.write('calling this.chart.write');
//                    this.chart.write(this.chart_panel.body.id); 
//                }
//             }
//             return true;
//         }
//         return false;
//     },
//     redraw: function() {
//         // This function recreates the chart from scratch.
//         if(this.chart) {
//             this.chart = null;
//             this.setData(this.data_xml);
//         }
//     },
//     gotResize: function() {
//         if(this.chart) {
//             this.doLayout();
//         }
//     },
//     setData: function(data_xml) {
//         this.data_xml = data_xml;
//         if(this.createChart()) {
//             this.chart.setData(data_xml);
//             if(this.avoid_IE_memory_leaks) {
//                 jstracer.write('avoiding leaks');
//                 this.chart.interactive = false;
//                 var chart_html = this.chart.getMixedHTML();
//                 this.chart_panel.body.update(chart_html);
//                 this.chart_panel.body.on('click', function(e) {
//                     alert('got click');
//                 });
//             }
//         }   
//     },
//     setUrl: function(url) {
//         this.url = url;
//         
//         if(this.createChart()) {
//             jstracer.write('calling setXMLFile(' + url + ')');
//             this.chart.setXMLFile(url);
//             if(this.avoid_IE_memory_leaks) {
//                 jstracer.write('setUrl inside avoid_IE_memory_leaks');
//                 this.chart.interactive = false;
//                 var chart_html = this.chart.getMixedHTML();
//                 this.chart_panel.body.update(chart_html);
//             }
//         }
//     },
//     // override initComponent
//     initComponent: function() {
//         var self = this;
//         
//         self.chart_panel = new Ext.Panel({
//              border: false,
//              autoWidth: true,
//              floating:  false
//         });
//         
//         // jstracer.write('after creation chart_panel height = ' + self.chart_panel.getSize().height);
// 
//         self.chart_panel.addListener({
//             'render': {
//                 fn: function(panel, width, height) {
//                     jstracer.write('chart_panel::render')
//                     if(self.init_data) {
//                         self.setData(self.init_data);
//                         self.init_data = null;
//                     }
//                     else if(self.init_url) {
//                         self.setUrl(self.init_url);
//                         self.init_url = null;
//                     } else {
//                         if(self.chart) {
//                             self.chart.updateSize(width, height);
//                         }
//                     }
//                 },
//                 scope: self
//             }
//         });
//         
//         
//         self.chart_panel_holder = new Ext.Panel({
//             layout: 'fit',
//             border: false,
//             items: self.chart_panel
//         });
//         
//         Ext.applyIf(this, {
//             avoid_IE_memory_leaks: false,
//             swf: 'AnyChart.swf',
//             monitorResize: true,
//             layout: 'fit',
//             items: [
//                 self.chart_panel_holder
//             ],
//             border: false
//         });
//         
//         
//         // call the superclass's initComponent implementation       
//         twowayfitness.AnyChartPanel.superclass.initComponent.call(this);
//     }
// });


// 
// var next_chart_panel_id = 1;
// 
// twowayfitness.anycharts_pool = {
// };
// 
// twowayfitness.allocateChartPanel = function(swf_name) {
//     jstracer.write('allocateChartPanel(' + swf_name + ')');
//     var array = twowayfitness.anycharts_pool[swf_name];
//     if(!array) {
//         array = twowayfitness.anycharts_pool[swf_name] = [];
//     }
//     if(array.size() == 0) {
//         var id = "chart-panel-" + next_chart_panel_id++;
//         jstracer.write('returning new chart panel id = '+ id);
//         return new Ext.Panel({
//           // ('/anychart/swf/' + swf_name);  
//           border: false,
//           title: 'a: chart panel: ' + id,
//           id: id,
//           floating:  false
//         });
//     } else {
//         jstracer.write('reusing chart panel');
//         var ret = array.pop();
//         
//         // twowayfitness.viewport.remove(ret);
//         
//         return ret;
//     }
// };
// 
// twowayfitness.deallocateChartPanel = function(panel, swf_name)
// {
//     jstracer.write('deallocateChartPanel(' + swf_name + ')');
//     panel.purgeListeners();
//     // twowayfitness.viewport.add(panel);
//     var array = twowayfitness.anycharts_pool[swf_name];
//     if(!array) {
//         twowayfitness.anycharts_pool[swf_name] = [];
//         array = twowayfitness.anycharts_pool[swf_name];
//     }
//     array.push(panel);
// };
// 
// twowayfitness.AnyChartPanel = Ext.extend(Ext.Panel, {
//     setData: function(data_xml) {
//         this.data_xml = data_xml;
//         if(this.rendered && this.chart_panel.rendered) {
//             var chart_width = this.chart_panel.getSize().width;
//             var chart_height = this.chart_panel.getSize().height;
//             // jstracer.write('setData() width = ' + chart_width + ' height = ' + chart_height);
// 
//             // aaaaa
//             // if(!this.chart) {
//             //    this.chart = new AnyChart('/anychart/swf/' + this.swf);
//             //    this.chart.wMode = 'transparent';
//             //    this.chart.width = chart_width;
//             //    this.chart.height = chart_height;
//             //    this.chart.write(this.chart_panel.body.id); 
//             // }
//             // 
//             // this.chart.setData(data_xml);
//         }
//     },
//     // override initComponent
//     initComponent: function() {
//         var self = this;
//         Ext.applyIf(this, {
//             swf: 'AnyChart.swf'
//         });
//         
//         self.chart_panel = twowayfitness.allocateChartPanel(this.swf);
//         // self.chart_panel = new Ext.Panel({
//         //      // region: 'center',
//         //      border: false,
//         //      floating:  false
//         //      // ,
//         //      // height: 300
//         //      // ,
//         //      // listeners: {
//         //      //     'resize' : {
//         //      //         fn: function(component, adjWidth, adjHeight, rawWidth, rawHeight) {
//         //      //             if(self.chart) {
//         //      //                 jstracer.write('AnyChartPanel resizing height = ' + adjHeight);
//         //      //                 self.chart.updateSize(adjWidth, adjHeight);
//         //      //             }
//         //      //         },
//         //      //         scope: this,
//         //      //         buffer: 50
//         //      //     }
//         //      // }
//         //      
//         //      // dataURL  : '/client/first_chart',
//         //      // width     : 400,
//         //      // height: 300
//         // });
//         
//         // jstracer.write('after creation chart_panel height = ' + self.chart_panel.getSize().height);
// 
//         self.chart_panel.addListener({
//             'bodyresize': {
//                 fn: function(panel, width, height) {
//                     if(self.init_data) {
//                         self.setData(self.init_data);
//                         self.init_data = null;
//                     } else {
//                         if(self.chart) {
//                             self.chart.updateSize(width, height);
//                         }
//                     }
//                 },
//                 scope: self,
//                 buffer: 50
//             },
//             beforedestroy: {
//                 fn: function(component) {
//                     jstracer.write('chart_panel beforedestroy id = ' + self.chart_panel.id);
//                     // jstracer.write('trying to deallocate chart panel');
//                     // twowayfitness.deallocateChartPanel(self.chart_panel, self.swf);
//                     return false; // stop the destroy
//                 },
//                 scope: self
//             }
//         });
// 
//         // self.addListener({
//         //     remove: {
//         //         fn: function(container, component) {
//         //             if(component == self.chart_panel) {
//         //                 jstracer.write('trying to deallocate chart panel');
//         //                 twowayfitness.deallocateChartPanel(self.chart_panel, self.swf);
//         //             }
//         //         }
//         //     }
//         // });
//         
//         self.chart_panel_holder = new Ext.Panel({
//             layout: 'fit',
//             // region: 'center',
//             border: false,
//             // height: 300,
//             items: self.chart_panel
//         });
//         
//         self.chart_panel_holder.addListener({
//             beforedestroy: {
//                 fn: function(component) {
//                     jstracer.write('holder beforedestroy id = ' + self.chart_panel.id);
//                     self.chart_panel_holder.remove(self.chart_panel, false);
//                     twowayfitness.deallocateChartPanel(self.chart_panel, self.swf);
//                     // twowayfitness.deallocateChartPanel(self.chart_panel, self.swf);
//                     return true; // allow the destroy
//                 },
//                 scope: self
//             }
//         });
//         
//         
//         // self.chart_panel_holder.addListener({
//         //     'render': {
//         //         fn: function() {
//         //             jstracer.write('AnyChartPanel chart_panel_holder render');
//         //             if(this.init_data) {
//         //                 jstracer.write('AnyChartPanel chart_panel_holder calling setData()');
//         //                 this.setData(this.init_data);
//         //             }
//         //         },
//         //         scope: self
//         //     }
//         // });
//         
//         
//         Ext.applyIf(this, {
//             layout: 'fit',
//             // height: 300,
//             items: [
//                 self.chart_panel_holder
//             ],
//             border: false
//         });
//         
//         // call the superclass's initComponent implementation       
//         twowayfitness.AnyChartPanel.superclass.initComponent.call(this);
//     }
// });
// 
// twowayfitness.AnyGaugePanel = Ext.extend(twowayfitness.AnyChartPanel, {
//     // override initComponent
//     initComponent: function() {
//         Ext.applyIf(this, {
//             swf: 'Gauge3.swf'
//         });
//         // call the superclass's initComponent implementation
//         twowayfitness.AnyGaugePanel.superclass.initComponent.call(this);
//     }
// });
// 
// 









//    object_name: rails object name
//  display_show_panel
// 
// 
twowayfitness.GridWithShowPanel = Ext.extend(Ext.Panel, {
    constructor: function(config) {
        // Your preprocessing here
        twowayfitness.GridWithShowPanel.superclass.constructor.apply(this, [ config ]);
        // Your postprocessing here
    },
    setDatastore: function(datastore) {
        this.datastore = datastore;
        this.store = datastore; // do i need this?
        
        this.disable_selected_item_buttons();
        
        if(this.grid.rendered) {
            this.grid.reconfigure(datastore, this.column_model);
        } else {
        }
    },
    disable_selected_item_buttons: function() {
        Ext.each(this.selected_item_buttons, function(button) {
            button.disable();
        });
    },
    enable_selected_item_buttons: function() {
        Ext.each(this.selected_item_buttons, function(button) {
            button.enable();
        });
    },
    hideProgress: function() {
        this.progressCount -= 1;
        if(this.progressCount == 0) {
            this.progressBox.hide();
        }
    },
    startProgress: function() {
        this.progressCount += 1;
    },
    reloadList: function(current_id) {
        this.datastore.load({
            callback: function(records, options, success) {
                if(current_id) {
                    var index = 0;
                    // find record with id = current_id
                    Ext.each(
                        records,
                        function(record) {
                            if(record.data.id == current_id) {
                                this.grid.getSelectionModel().selectRecords([record]);
                                this.grid.getView().focusRow(index);
                                this.showItem(record.data);
                                
                                return false;
                            }
                            index += 1;
                            return true;
                        },
                        this
                    );
                }
            },
            scope : this
        });
    },
    reconfigure: function() {
        if(this.grid.rendered) {
            this.grid.reconfigure(this.datastore, this.column_model);
        } else {
            alert("Wasn't rendered???");
        }
    },
    editable_and_deletable: function(data) {
       return true;
    },
    // change the component displayed in the center
    setCenterPanel: function(component) {
        this.show_panel_wrapper.removeAll(true);
        this.show_panel_wrapper.add(component);
        this.show_panel_wrapper.doLayout();
    },
    showItem: function(data) {
        var url = '/' + this.collection_path + '/' + data.id;
        this.show_panel.load({
            url: url,
            params: {
                fragment: "true"
            },
            method: 'GET',
            timeout: 30,
            scripts: true
        });
        if(this.editable_and_deletable(data.data)) {
            this.enable_selected_item_buttons();
        } else {
            this.disable_selected_item_buttons();
        }
    },
    // override initComponent
    initComponent: function() {
        var self = this;
        
        var show_panel_config = {
            layout: 'fit',
            itemId: 'mainPanel'
        };
        
        if(this.showPanelConfig) {
            Ext.apply(show_panel_config, this.showPanelConfig);
        }

        this.show_panel = new Ext.Panel(show_panel_config);
        
        this.new_button = new Ext.Toolbar.Button({
            text:'New...',
            tooltip:'Create new  ' + this.object_name,
            handler: function() {
                if(self.on_new != undefined) {
                    self.on_new();
                } else {
                    alert("new selected ... what now?");
                }
                // #{on_new_str}
            },
            iconCls:'add'
        });

        this.edit_button = new Ext.Toolbar.Button({
            text:'Edit...',
            tooltip:'Edit selected  ' + this.object_name,
            handler: function() {
                var selected = this.grid.getSelectionModel().getSelected();
                if(selected) {
                    self.on_edit(selected);
                } else { 
                    alert('Please select a row first.');
                }
            },
            iconCls:'edit',
            scope: self
        });
        
        this.delete_button = new Ext.Toolbar.Button({
            text:'Delete...',
            tooltip:'Delete selected ' + this.object_name,
            handler: function() {
                var selected = this.grid.getSelectionModel().getSelected();
                if (selected) {
                    Ext.Msg.confirm('Delete', 'Are you sure you wish to delete this entry?', function(btn, text) {
                        if(btn == 'yes') {
                            var conn = new Ext.data.Connection();
                            var url = selected.data.uri ? selected.data.uri : ('/' + self.collection_path + '/' + selected.data.id);
                            self.progressBox = Ext.Msg.wait("Deleting ...");
                            self.progressCount = 1;
                            
                            conn.request({
                                url: url,
                                method: 'POST',
                                params: {
                                    _method: 'DELETE',
                                    authenticity_token: self.form_authenticity_token
                                },
                                success: function(response, options) {
                                    var reload = true;
                                    self.disable_selected_item_buttons();

                                    if(self.after_delete != undefined) {
                                        reload = self.after_delete();
                                    } else {
                                        self.show_panel.body.update('');
                                    }
                                
                                    if(reload) {
                                        self.datastore.load();
                                    }
                                    
                                    if(!self.manualProgressDismiss) {
                                        self.progressBox.hide();
                                    }
                                },
                                failure: function(response, options) {
//                                    Ext.Msg.alert('Delete failed', 'Your request to delete the item failed. Perhaps it has already been deleted.');
                                    twowayfitness.showPlainMessage("Failed to remove the item. Perhaps it has already been deleted.", { title: 'Delete failed' }); 
                                    self.progressBox.hide();
                                }
                            });
                        }
                    });
                } else {
                    alert('Please select a row first.');
                }
            },
            iconCls:'remove',
            scope: self
        });
        
        // alert("initcomponent title = " + this.title + "this.datastore = " + self.datastore);
        
        // buttons that apply to the selected item (grid row)
        this.selected_item_buttons = [
            this.edit_button,
            this.delete_button
        ];
        var tbar_buttons = null;
        if(this.display_toolbar) {
            tbar_buttons = [
                this.new_button, '-',
                this.edit_button,'-',
                this.delete_button
            ];
            if(this.additional_tbar_buttons) {
                this.selected_item_buttons = this.selected_item_buttons.concat(this.additional_tbar_buttons);
                tbar_buttons.push('-');
                tbar_buttons = tbar_buttons.concat(this.additional_tbar_buttons);
            }
        }
        
        this.disable_selected_item_buttons();
        
        var grid_config = {
            store: self.datastore,
            cm: this.column_model,
            sm: new Ext.grid.RowSelectionModel({singleSelect:true}),
            tbar: tbar_buttons
        };
        
        if(this.grid_config) {
            Ext.apply(grid_config, this.grid_config);
        }
        
        // create the grid
        this.grid = new Ext.grid.GridPanel(grid_config);
        
        this.grid.edit_button = this.edit_button;
        this.grid.delete_button = this.delete_button;

        this.grid.addListener(
            'render',
            function() {
                this.reconfigure();
            },
            this
        );

        this.grid.on("rowclick",
            function(grid, row, e) {
                var data = grid.getStore().getAt(row);
                if(this.editable_and_deletable(data.data)) {
                    this.enable_selected_item_buttons();
                } else {
                    this.disable_selected_item_buttons();
                }
            },
            this
        );

        if(this.display_show_panel) {
            this.grid.on("rowclick",
              function(grid, row, e) {
                  Ext.log('calling grid.getStore().getAt(row);');
                var data = grid.getStore().getAt(row);
                if(this.on_rowclick) {
                    this.on_rowclick(data.data);
                } else {
                    this.showItem(data);
                }
              }, this
            );
        }
        
        var items;
        
        var list_panel_config = {
            border: false,
            layout: 'fit',
            height: 200,
            minSize: 50,
            split: true,
            region: 'north',
            items: this.grid
        };
        
        if(this.listPanelConfig) {
            Ext.apply(list_panel_config, this.listPanelConfig);
        }
        
        var list_panel = new Ext.Panel(list_panel_config);
        
        if(this.display_show_panel) {
            var show_panel_wrapper_config = {
                region: 'center',
                border: false,
                autoScroll: false,
                layout: 'fit',
                split: true,
                items: [
                    this.show_panel
                ]
            };
            if(this.showPanelWrapperConfig) {
                Ext.apply(show_panel_wrapper_config, this.showPanelWrapperConfig);
            }
            
            this.show_panel_wrapper = new Ext.Panel(show_panel_wrapper_config);
            
            // list_panel.rowHeight = .25;
            // this.show_panel.rowHeight = .75;
            items = [list_panel, this.show_panel_wrapper];
        } else {
            list_panel.region = 'center';
            list_panel.rowHeight = 1.0;
            items = [list_panel];
        }
        

        // used applyIf rather than apply so user could
        // override the defaults
        Ext.applyIf(this, {
            border: false,
            autoScroll: false,
            width: 500,
            layout: 'border',
            items: items
        });

        // call the superclass's initComponent implementation
        twowayfitness.GridWithShowPanel.superclass.initComponent.call(this);
    }
});





var seconds_test = /^[0-5][0-9](\.[0-9]+)?$/;
Ext.apply(Ext.form.VTypes, {
    //  vtype validation function
    seconds: function(val, field) {
        return seconds_test.test(val);
    },
    // vtype Text property: The error text to display when the validation function returns false
    secondsText: "Must be whole number such as '07' or '14' or fractional number such as '07.42' or '14.67'. Must be less than 60.",
    // vtype Mask property: The keystroke filter mask
    secondsMask: /[\d\.]/
});


// custom Vtype for vtype:'minutes'
var minutes_test = /^[0-5]?[0-9]$/;
Ext.apply(Ext.form.VTypes, {
    //  vtype validation function
    minutes: function(val, field) {
        return minutes_test.test(val);
    },
    // vtype Text property: The error text to display when the validation function returns false
    minutesText: 'Must be between 00 and 59.',
    // vtype Mask property: The keystroke filter mask
    minutesMask: /[\d]/
});

function makeDuration2Field(field_prefix, options) {
    var hrs_field = new Ext.form.NumberField({
        //xtype: 'textfield',
        emptyText: 'hrs',
        name: field_prefix + 'hrs]]',
        decimalPrecision: 0,
        minValue: 0,
        width: 25
    });
    var min_field = new Ext.form.TextField({
        //xtype: 'textfield',
        emptyText: 'min',
        name: field_prefix + 'min]]',
        minValue: 0,
        maxValue: 59,
        decimalPrecision: 0,
        width: 28,
        vtype: 'minutes'
    });
    var sec_field = new Ext.form.TextField({
        //xtype: 'numberfield',
        emptyText: 'sec',
        name: field_prefix + 'sec]]',
        minValue: 0,
        maxValue: 59.99,
        decimalPrecision: 2,
        width: 45,
        vtype: 'seconds'
    });

    var config =  {
        copyValues: function(src) {
            Ext.log('hrs_field = ' + src.hrs_field.getValue());
            this.hrs_field.setValue(src.hrs_field.getValue());
            this.min_field.setValue(src.min_field.getValue());
            this.sec_field.setValue(src.sec_field.getValue());
        },
        setValues: function(data) {
            Ext.log('newDurationField setValues() data.duration_hrs = ' + data.duration_hrs);
            this.hrs_field.setValue(data.duration_hrs);
            this.min_field.setValue(data.duration_min);
            this.sec_field.setValue(data.duration_sec);
        },
        setAsNew: function() {
            this.hrs_field.setValue('');
            this.min_field.setValue('');
            this.sec_field.setValue('');
        },
        fieldLabel: 'Duration',
        border: false,
        name: 'exercise_diary_entry[duration]',
        hrs_field: hrs_field,
        min_field: min_field,
        sec_field: sec_field,
//        xtype: 'panel',
        layout: 'hbox',
        items: [
            hrs_field,
            {
                xtype: 'panel',
                border: false,
                margins: {top: 0, right: 2, bottom:0, left:2},
                html: ':'
            },
            min_field,
            {
                xtype: 'panel',
                border: false,
                margins: {top: 0, right: 2, bottom:0, left:2},
                html: ':'
            },
            sec_field
//            ,
//            dummy_field
        ]
    };

    Ext.apply(config, options);

    return new Ext.Panel(config);
}


twowayfitness.BoxesPanel = Ext.extend(Ext.Panel, {
    setData: function (data) {
        this.data = data;
        if(this.rendered) {
            this.relayout();
        }
    },
    relayout: function() {
        var width = this.getSize().width;
        var self = this;
        twowayfitness.remove_all_components(this);
        
        var num_items = this.numItems();
        
        var num_columns = Math.floor(width / this.box_width);
        var column_width = 0.99 / num_columns;
        
        // jstracer.write('num_items = ' + num_items + ' width = ' + width + ' num_columns = ' + num_columns + ' column_width = ' + column_width);

        var p2 = null;
        var row_index = 0;
        var item_index = 0;
        for(row_index = 0; item_index < num_items; row_index++) {
            var panel = new Ext.Panel({
                border: self.borders,
                layout: 'column'
            });
            for (var column_index = 0; column_index < num_columns && item_index < num_items; column_index++, item_index++) {
                var box_panel = this.createBox(item_index);
                box_panel.columnWidth = column_width;                
                p2 = box_panel;
                panel.add(box_panel);
            }
            
            // panel.doLayout();
            
            this.add(panel);
            
        }
        
        // jstracer.write('boxes relayout just before doLayout()');
        
        this.doLayout();
        // jstracer.write('boxes relayout just after doLayout() p2.height = ' + p2.getSize().height);
    },
    initComponent: function() {
        Ext.applyIf(this, {
            monitorResize: true,
            border: false,
            borders: false,
            box_width: 200
        });
        
        twowayfitness.BoxesPanel.superclass.initComponent.call(this);
        
        this.addListener({
            bodyresize: {
                // fn: function(component, adjWidth, adjHeight, rawWidth, rawHeight) {
                fn: function(component, width, height) {
                    // jstracer.write('boxes resize');
                    if(this.data) {
                        this.relayout();
                    }
                },
                scope: this,
                buffer: 50
            },
            'render': {
                fn: function() {
                    this.fetchData();
                },
                scope: this
            }
        });
    }
});


// TODO: factor out common bits
twowayfitness.ProfileDialog = Ext.extend(twowayfitness.PopupWindow, {
    initComponent: function() {
        var self = this;
        
        var file_upload_field = new Ext.form.FileUploadField({
            emptyText: 'Select an image. Max size 1MB.',
            fieldLabel: 'Photo',
            height: 30,
            name: 'profile[uploaded_photo_data]',
            buttonCfg: {
                text: '',
                iconCls: 'upload-icon'
            }
        });
        
        var timezones = [["International Date Line West", "(GMT-11:00) International Date Line West"], ["Midway Island", "(GMT-11:00) Midway Island"], ["Samoa", "(GMT-11:00) Samoa"], ["Hawaii", "(GMT-10:00) Hawaii"], ["Alaska", "(GMT-09:00) Alaska"], ["Pacific Time (US \u0026 Canada)", "(GMT-08:00) Pacific Time (US \u0026 Canada)"], ["Tijuana", "(GMT-08:00) Tijuana"], ["Arizona", "(GMT-07:00) Arizona"], ["Chihuahua", "(GMT-07:00) Chihuahua"], ["Mazatlan", "(GMT-07:00) Mazatlan"], ["Mountain Time (US \u0026 Canada)", "(GMT-07:00) Mountain Time (US \u0026 Canada)"], ["Central America", "(GMT-06:00) Central America"], ["Central Time (US \u0026 Canada)", "(GMT-06:00) Central Time (US \u0026 Canada)"], ["Guadalajara", "(GMT-06:00) Guadalajara"], ["Mexico City", "(GMT-06:00) Mexico City"], ["Monterrey", "(GMT-06:00) Monterrey"], ["Saskatchewan", "(GMT-06:00) Saskatchewan"], ["Bogota", "(GMT-05:00) Bogota"], ["Eastern Time (US \u0026 Canada)", "(GMT-05:00) Eastern Time (US \u0026 Canada)"], ["Indiana (East)", "(GMT-05:00) Indiana (East)"], ["Lima", "(GMT-05:00) Lima"], ["Quito", "(GMT-05:00) Quito"], ["Atlantic Time (Canada)", "(GMT-04:00) Atlantic Time (Canada)"], ["Caracas", "(GMT-04:00) Caracas"], ["La Paz", "(GMT-04:00) La Paz"], ["Santiago", "(GMT-04:00) Santiago"], ["Newfoundland", "(GMT-03:30) Newfoundland"], ["Brasilia", "(GMT-03:00) Brasilia"], ["Buenos Aires", "(GMT-03:00) Buenos Aires"], ["Georgetown", "(GMT-03:00) Georgetown"], ["Greenland", "(GMT-03:00) Greenland"], ["Mid-Atlantic", "(GMT-02:00) Mid-Atlantic"], ["Azores", "(GMT-01:00) Azores"], ["Cape Verde Is.", "(GMT-01:00) Cape Verde Is."], ["Casablanca", "(GMT) Casablanca"], ["Dublin", "(GMT) Dublin"], ["Edinburgh", "(GMT) Edinburgh"], ["Lisbon", "(GMT) Lisbon"], ["London", "(GMT) London"], ["Monrovia", "(GMT) Monrovia"], ["Amsterdam", "(GMT+01:00) Amsterdam"], ["Belgrade", "(GMT+01:00) Belgrade"], ["Berlin", "(GMT+01:00) Berlin"], ["Bern", "(GMT+01:00) Bern"], ["Bratislava", "(GMT+01:00) Bratislava"], ["Brussels", "(GMT+01:00) Brussels"], ["Budapest", "(GMT+01:00) Budapest"], ["Copenhagen", "(GMT+01:00) Copenhagen"], ["Ljubljana", "(GMT+01:00) Ljubljana"], ["Madrid", "(GMT+01:00) Madrid"], ["Paris", "(GMT+01:00) Paris"], ["Prague", "(GMT+01:00) Prague"], ["Rome", "(GMT+01:00) Rome"], ["Sarajevo", "(GMT+01:00) Sarajevo"], ["Skopje", "(GMT+01:00) Skopje"], ["Stockholm", "(GMT+01:00) Stockholm"], ["Vienna", "(GMT+01:00) Vienna"], ["Warsaw", "(GMT+01:00) Warsaw"], ["West Central Africa", "(GMT+01:00) West Central Africa"], ["Zagreb", "(GMT+01:00) Zagreb"], ["Athens", "(GMT+02:00) Athens"], ["Bucharest", "(GMT+02:00) Bucharest"], ["Cairo", "(GMT+02:00) Cairo"], ["Harare", "(GMT+02:00) Harare"], ["Helsinki", "(GMT+02:00) Helsinki"], ["Istanbul", "(GMT+02:00) Istanbul"], ["Jerusalem", "(GMT+02:00) Jerusalem"], ["Kyev", "(GMT+02:00) Kyev"], ["Minsk", "(GMT+02:00) Minsk"], ["Pretoria", "(GMT+02:00) Pretoria"], ["Riga", "(GMT+02:00) Riga"], ["Sofia", "(GMT+02:00) Sofia"], ["Tallinn", "(GMT+02:00) Tallinn"], ["Vilnius", "(GMT+02:00) Vilnius"], ["Baghdad", "(GMT+03:00) Baghdad"], ["Kuwait", "(GMT+03:00) Kuwait"], ["Moscow", "(GMT+03:00) Moscow"], ["Nairobi", "(GMT+03:00) Nairobi"], ["Riyadh", "(GMT+03:00) Riyadh"], ["St. Petersburg", "(GMT+03:00) St. Petersburg"], ["Volgograd", "(GMT+03:00) Volgograd"], ["Tehran", "(GMT+03:30) Tehran"], ["Abu Dhabi", "(GMT+04:00) Abu Dhabi"], ["Baku", "(GMT+04:00) Baku"], ["Muscat", "(GMT+04:00) Muscat"], ["Tbilisi", "(GMT+04:00) Tbilisi"], ["Yerevan", "(GMT+04:00) Yerevan"], ["Kabul", "(GMT+04:30) Kabul"], ["Ekaterinburg", "(GMT+05:00) Ekaterinburg"], ["Islamabad", "(GMT+05:00) Islamabad"], ["Karachi", "(GMT+05:00) Karachi"], ["Tashkent", "(GMT+05:00) Tashkent"], ["Chennai", "(GMT+05:30) Chennai"], ["Kolkata", "(GMT+05:30) Kolkata"], ["Mumbai", "(GMT+05:30) Mumbai"], ["New Delhi", "(GMT+05:30) New Delhi"], ["Kathmandu", "(GMT+05:45) Kathmandu"], ["Almaty", "(GMT+06:00) Almaty"], ["Astana", "(GMT+06:00) Astana"], ["Dhaka", "(GMT+06:00) Dhaka"], ["Novosibirsk", "(GMT+06:00) Novosibirsk"], ["Sri Jayawardenepura", "(GMT+06:00) Sri Jayawardenepura"], ["Rangoon", "(GMT+06:30) Rangoon"], ["Bangkok", "(GMT+07:00) Bangkok"], ["Hanoi", "(GMT+07:00) Hanoi"], ["Jakarta", "(GMT+07:00) Jakarta"], ["Krasnoyarsk", "(GMT+07:00) Krasnoyarsk"], ["Beijing", "(GMT+08:00) Beijing"], ["Chongqing", "(GMT+08:00) Chongqing"], ["Hong Kong", "(GMT+08:00) Hong Kong"], ["Irkutsk", "(GMT+08:00) Irkutsk"], ["Kuala Lumpur", "(GMT+08:00) Kuala Lumpur"], ["Perth", "(GMT+08:00) Perth"], ["Singapore", "(GMT+08:00) Singapore"], ["Taipei", "(GMT+08:00) Taipei"], ["Ulaan Bataar", "(GMT+08:00) Ulaan Bataar"], ["Urumqi", "(GMT+08:00) Urumqi"], ["Osaka", "(GMT+09:00) Osaka"], ["Sapporo", "(GMT+09:00) Sapporo"], ["Seoul", "(GMT+09:00) Seoul"], ["Tokyo", "(GMT+09:00) Tokyo"], ["Yakutsk", "(GMT+09:00) Yakutsk"], ["Adelaide", "(GMT+09:30) Adelaide"], ["Darwin", "(GMT+09:30) Darwin"], ["Brisbane", "(GMT+10:00) Brisbane"], ["Canberra", "(GMT+10:00) Canberra"], ["Guam", "(GMT+10:00) Guam"], ["Hobart", "(GMT+10:00) Hobart"], ["Melbourne", "(GMT+10:00) Melbourne"], ["Port Moresby", "(GMT+10:00) Port Moresby"], ["Sydney", "(GMT+10:00) Sydney"], ["Vladivostok", "(GMT+10:00) Vladivostok"], ["Magadan", "(GMT+11:00) Magadan"], ["New Caledonia", "(GMT+11:00) New Caledonia"], ["Solomon Is.", "(GMT+11:00) Solomon Is."], ["Auckland", "(GMT+12:00) Auckland"], ["Fiji", "(GMT+12:00) Fiji"], ["Kamchatka", "(GMT+12:00) Kamchatka"], ["Marshall Is.", "(GMT+12:00) Marshall Is."], ["Wellington", "(GMT+12:00) Wellington"], ["Nuku'alofa", "(GMT+13:00) Nuku'alofa"]];
        var timezone_name = 'profile[time_zone_name]';
        var timezone_field = new Ext.form.ComboBox({
            fieldLabel: 'Time Zone',
            editable: false,
            store: timezones,
            value: this.data ? this.data[timezone_name] : '',
            valueNotFoundText: 'not specified',
            name: 'timezone',
            typeAhead: true,
            forceSelection: true,
            triggerAction: 'all',
            emptyText: 'Select a timezone...',
            hiddenName: timezone_name,
            selectOnFocus:true
        });

        var baseParams = {
            'authenticity_token': this.form_authenticity_token
        };
        if(this.client_id) {
            baseParams['client_id'] = this.client_id;
        }
        
        if(this.data) {
            // it's an update request
            baseParams['_method'] = 'put';
            // this.url = '/profiles/' + this.data['profile[id]'] + '?format=xml';
            this.url = '/profiles/' + this.data['profile[id]'];
            // this.url = '/profiles/' + this.data['profile[id]'] + '?format=ext_json';
            // this.url = '/metrics/';
        } else {
            // it's a create request
            this.url = '/profiles/';
        }
        
        var fc = new twowayfitness.FieldCreator({
            data: this.data,
            object_name: 'profile'
        });
        
        var formPanel = new Ext.FormPanel(
             {
                 autoScroll: true,
                 fileUpload: true,
                 bodyStyle:'padding:5px 5px 0',
                 labelWidth: 125,
                 labelAlign: 'right',

                 baseParams: baseParams,
                 
                 defaults:
                     {
                         width: 250
                     },
                 items:
                     [
                         {
                             autoWidth: true,
                             border: false,
                             html: '<p class="instructions">All fields are optional. You can enter as much or as little information about yourself as you like.<p>'
                         },
                        file_upload_field,
                        fc.text_field('first_name', 'First Name'),
                        fc.text_field('last_name', 'Last Name'),
                         timezone_field,
                        {
                            autoWidth: true,
                            border: false,
                            html: '<p class="instructions">Below you can specify a nickname for yourself that will be used to represent you if you choose to take part in online forum discussions. You can leave the Nickname field blank if you are happy for your first and last name to appear in online discussions.<p>'
                        },
                        fc.text_field('nickname', 'Nickname'),
                        fc.simple_date_field('dob', 'Date of Birth'),
//                        fc.text_field('height', 'Height (cm)'),
                        fc.text_area('aims', 'Aims'),
                        fc.text_area('likes', 'Likes'),
                        fc.text_area('dislikes', 'Dislikes'),
                        fc.text_area('highlight', 'Highlight since joining 2 Way Fitness')
                     ],
                dosubmit: function() {
                     formPanel.getForm().submit(
                         {
                             url: self.url,
                             waitMsg:'Saving Data...',
                             success: function(form, action) {
//                                 var html = action.result.html;
//                                 var usr_info = Ext.get('user-info');
//                                 if(usr_info) {
//                                     usr_info.update(html);
//                                 }
                                 if(twowayfitness.current_panel.panel_name == 'Home') {
                                    twowayfitness.main_panel.display_home_panel();
                                 }
                                 self.hide();
                             },
                             failure: function(form, action) {
                                 twowayfitness.handle_form_submission_failure(form, action);
//                                  alert('Failed to submit data. Please try again later.');
                             }
                         }
                     );
                 }
             }
         );
        
        var buttons = [
                    {
                        text: "Save Changes",
                        handler: function() {
                            formPanel.dosubmit();
                        }
                    },
                    {
                        text: 'Cancel',
                        handler: function(cmp) {
                            self.hide();
                        }
                        
                    },
                    {
                        text: 'Help',
                        handler: function() {
                            twowayfitness.displayHelp('create_or_edit_profile');
                        }
                    }
                ];
        
        
        Ext.applyIf(this, {
             showCloseButtons: false,
             title: 'Profile',
             width: 580,
             // autoHeight: true,
             closeAction:'hide',
             modal: true,
             closable: true,
             items: formPanel,
             buttons: buttons
         });

        this.on('show', function(comp) {
            // Fix for IE: for some reason (an ext bug I think), the date of birth field does not show unless I do the following.
           comp.doLayout();
        });

        twowayfitness.ProfileDialog.superclass.initComponent.call(this);
    }
});

twowayfitness.editProfile = function(profile_id, form_authenticity_token) {
    var progressBox = Ext.Msg.wait("Fetching data");
    
    Ext.Ajax.request({
       url: '/profiles/' + profile_id,
       method: 'GET',
       params: { 'format':'ext_json' },
       success : function (response, options) {
           progressBox.hide();
           var data = Ext.util.JSON.decode(response.responseText);
           var winxxx = new twowayfitness.ProfileDialog({
               data: data.data,
               form_authenticity_token: form_authenticity_token
           });
           winxxx.show();
       },
       failure : function (response, options) {
           progressBox.hide();
           twowayfitness.showPlainMessage('We failed to fetch information about your profile from the server. Please try again later.');
       }
    });

};


twowayfitness.MeasurementDialog = Ext.extend(twowayfitness.RestDialog, {
    initComponent: function() {
        var fc = new twowayfitness.FieldCreator({
            data: this.data,
            submission_object_name: 'measurement'
        });

        this.dateField = fc.date_field('date', 'Date', {
            format: 'jS F, Y',
            allowBlank: false
        });

        var value_field;
        if(this.isDuration) {
            value_field = makeDuration2Field(
                'measurement[duration2[',
                {
                    fieldLabel: 'Value',
                    name: 'measurement[duration]'
                }
            );
//            alert('this.data.duration_min = ' + this.data.duration_min);
            if(this.data) {
                value_field.setValues(this.data);
            }
        } else {
            value_field = fc.text_field('value', 'Value', {
            });
        }

        Ext.applyIf(this, {
             width: 440,
             title: 'Add Goal',
//             help_key: 'measurement',
             object_name: 'measurement',
             modal: true,
             form_panel_config: {
                 labelWidth: 60
             },
             form_items: [
                this.dateField,
                value_field
             ]
         });

        twowayfitness.MeasurementDialog.superclass.initComponent.call(this);
    }
});



/**
 * twowayfitness.MessageStore
 * @extends Ext.data.Store
 * @cfg {String} url This will be a url of a location to load the MessageStore
 * This is a specialized Store which maintains messages.
 */
twowayfitness.MessageStore = function(config) {
    var config = config || {};
    Ext.applyIf(config, {
        remoteSort: true,
        reader: new Ext.data.JsonReader
            (
                {
                    root: 'messages',
                    id: 'id',
                    totalProperty: 'results'
                },
                [
                    {name: 'id', mapping: 'id'},
                    {name: 'sender_id', mapping: 'sender_id'},
                    {name: 'subject', mapping: 'subject'},
                    {name: 'when_sent', mapping: 'when_sent_as_string'},
                    {name: 'sender_name', mapping: 'sender_name'},
                    {name: 'recipient_names', mapping: 'recipient_names'},
                    {name: 'recipient_id', mapping: 'recipient_id'},
                    {name: 'has_been_read', mapping: 'has_been_read'},
                    {name: 'content', mapping: 'content'}
                ]
            )
    });
    // call the superclass's constructor 
    twowayfitness.MessageStore.superclass.constructor.call(this, config);
};
Ext.extend(twowayfitness.MessageStore, Ext.data.Store);

 
 
    // Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
    // Ext.QuickTips.init();
    // 
    // alert("Here I am");  
    // var ds = message_datastore;
    // 
    // var cm = message_column_model;
    // cm.defaultSortable = true;
    // 
    // var edit_button = new Ext.Toolbar.Button({
    //     text: 'Edit...',
    //     tooltip: 'Edit selected Message',
    //     handler: function() {
    //         var selected = grid.getSelectionModel().getSelected();
    //         if (selected) {
    //             window.location.href = '/messages/' + selected.data.id + '/edit';
    //         } else {
    //             alert('Please select a row first.');
    //         }
    //     },
    //     iconCls: 'edit'
    // });
    // 
    // var delete_button = new Ext.Toolbar.Button({
    //     text: 'Delete...',
    //     tooltip: 'Delete selected Message',
    //     handler: function() {
    //         var selected = grid.getSelectionModel().getSelected();
    //         if (selected) {
    //             if (confirm('Really delete?')) {
    //                 var conn = new Ext.data.Connection();
    //                 conn.request({
    //                     url: '/messages/' + selected.data.id,
    //                     method: 'POST',
    //                     params: {
    //                         _method: 'DELETE',
    //                         authenticity_token: '69b9501efe945eacde62d42a818a4c6b4fbea9d3'
    //                     },
    //                     success: function(response, options) {
    //                         ds.load();
    //                     },
    //                     failure: function(response, options) {
    //                         alert('Delete operation failed.');
    //                     }
    //                 });
    //             }
    //         } else {
    //             alert('Please select a row first.');
    //         }
    //     },
    //     iconCls: 'remove'
    // });
    // 
    // 
    // // create the grid
    // var grid = new Ext.grid.GridPanel({
    //     ds: ds,
    //     cm: cm,
    //     sm: new Ext.grid.RowSelectionModel({
    //         singleSelect: true
    //     }),
    //     renderTo: 'messages-received-grid',
    //     title: 'Listing Messages',
    //     width: 540,
    //     height: 450,
    //     stripeRows: true,
    //     viewConfig: {
    //         forceFit: true
    //     },
    // 
    //     // inline toolbars
    //     tbar: [{
    //         text: 'New...',
    //         tooltip: 'Create new Message',
    //         handler: function() {
    //             window.location.href = '/messages/new';
    //         },
    //         iconCls: 'add'
    //     },
    //     '-', edit_button
    //     , '-', delete_button
    //     , '->'],
    // 
    //     bbar: new Ext.PagingToolbar({
    //         pageSize: 15,
    //         store: ds,
    //         displayInfo: true,
    //         displayMsg: 'Record {0} - {1} of {2}',
    //         emptyMsg: "No records found"
    //     })
    //     ,
    //     plugins: [
    //     new Ext.ux.grid.Search(
    //     {
    //         position: 'top'
    //     }
    //     )
    // 
    //     ]
    // 
    // });
    // 
    // grid.edit_button = edit_button;
    // grid.delete_button = delete_button;
    // 
    // // show record on double-click
    // grid.on("rowdblclick",
    // function(grid, row, e) {
    //     window.location.href = '/messages/' + grid.getStore().getAt(row).id;
    // });
    // 
    // 
    // 
    // ds.load({
    //     params: {
    //         start: 0,
    //         limit: 15
    //     }
    // });
    // });
 
 



twowayfitness.MessageGridView = Ext.extend(Ext.grid.GridView, {
    getRowClass: function(record, index, rowParams, store ) {
        var ret = record.data.has_been_read ? "" : "unread";
        // alert("getRowClass returning" + ret);
        return ret;
    },
    // override 
    initComponent : function() {
        Ext.apply(this,
            {
                // forceFit: true,
                // autoFill : true
            }
        );
    }
});
 
 
/**
 * twowayfitness.MessageGrid
 * @extends Ext.grid.GridPanel
 * This is a custom grid which will display message information. It is tied to 
 * a specific record definition by the dataIndex properties. 
 * 
 * It follows a very custom pattern used only when extending Ext.Components
 * in which you can omit the constructor.
 * 
 * It also registers the class with the Component Manager with an xtype of
 * messagegrid. This allows the application to take care of the lazy-instatiation
 * facilities provided in Ext 2.0's Component Model.
 */
twowayfitness.MessageGrid = Ext.extend(Ext.grid.GridPanel, {
    constructor: function(correspondent_config, config) {
        // alert("MessageGrid() correspondent_id = " + correspondent_id);
        this.correspondent_config = correspondent_config;
        // Your preprocessing here
    	twowayfitness.MessageGrid.superclass.constructor.apply(this, [ config ]);
        // Your postprocessing here
    },
    
    url: function(mailbox_name) {
        var ret = '/messages.ext_json?mailbox=' + mailbox_name;
        if(this.correspondent_config.correspondent_id)
        {
            ret = ret + '&correspondent=' + this.correspondent_config.correspondent_id;
        };
        return ret;
    },
    switchMailboxes: function(mailbox_name) {
        var store = new twowayfitness.MessageStore({
             storeId: 'gridMessageStore',
             proxy: new Ext.data.HttpProxy(
                 new Ext.data.Connection(
                   {
                       url: this.url(mailbox_name),
                       method: 'GET'
                   }
                 )
             )
        });
        store.load();
        this.replyButton.disable();
        this.mailbox_name = mailbox_name;
        // this.getTopToolbar().disable();
        this.reconfigure(
            store,
            this.getColumnModel()
        );
    },
    
    // override 
    initComponent : function() {
        this.mailbox_name = 'inbox';
        var grid = this;
        var buttons = [];
        
        if(this.correspondent_config.correspondent_id) {
            this.writeMessageButton =  new Ext.Toolbar.Button(
                {
                    text: 'Write Message to ' + this.correspondent_config.generic_description,
                    icon: '/images/icon_mail2.jpg',
                    cls: 'x-btn-text-icon',
                    handler: function(button,event) {
                        var dialog = new twowayfitness.CreateMessageDialog("", "", this.correspondent_config.name, this.correspondent_config.correspondent_id, grid.form_authenticity_token);
                        dialog.show();
                    },
                    scope: this
                }
            );
            // replyButton.messageGrid = this;
            buttons.push(this.writeMessageButton);
        }
        
        this.replyButton =  new Ext.Toolbar.Button(
            {
                text: 'Reply',
                icon: '/images/email_reply_icon5.jpg',
                cls: 'x-btn-text-icon',
                handler: function(button,event) {
                    var message_data = this.messageGrid.getSelectionModel().getSelected().data;



                    var store = new twowayfitness.MessageStore({
                         // storeId: 'gridMessageStore',
                         proxy: new Ext.data.HttpProxy(
                             new Ext.data.Connection(
                               {
                                   url: '/messages/message_as_reply/' + message_data.id,
                                   // url: this.url(mailbox_name),
                                   method: 'GET'
                               }
                             )
                         )
                    });

                    // var store = new twowayfitness.MessageStore({
                    //      proxy: new Ext.data.HttpProxy(
                    //          {
                    //              url: '/messages/message_as_reply/' + message_data.id,
                    //              method: 'get'
                    //          }
                    //      )
                    // });
                    store.load(
                        {
                            callback: function(records, options, success) {
                                // var message = eval(response.responseText);
                                // alert("success = " + success);
                                var message = records[0].data;
                                var dialog = new twowayfitness.CreateMessageDialog(message.subject, message.content, message.recipient_names, message.recipient_id, grid.form_authenticity_token);
                                dialog.show();
                            }
                        }
                    );
                }
            }
        );
        this.replyButton.messageGrid = this;
        buttons.push(this.replyButton);

        Ext.apply(this, {
            view: new twowayfitness.MessageGridView({
                forceFit: true
            }),
            forceFit: true,
            enableColumnHide: false,
            enableHdMenu: false,
            // autoExpandColumn: 'subject-column',
            // stripeRows: true,
            // autoWidth: true,
            // tools:[{
            //     id:'searchss',
            //     qtip: 'Refresh form Data',
            //     // hidden:true,
            //     handler: function(event, toolEl, panel){
            //         // refresh logic
            //     }
            // }],
            columns: [
                //{id: 'id', header: "#", width: 20, dataIndex: 'id'},
                {header: 'From', width: 120, fixed: true, dataIndex: 'sender_name', sortable: true },
                {header: 'To', width: 120, fixed: true, dataIndex: 'recipient_names', sortable: true },
                {header: 'Sent', width: 160, fixed: true, dataIndex: 'when_sent', sortable: true },
                {header: 'Subject', dataIndex: 'subject', id: 'subject-column', sortable: true }
            ],
            tbar: new Ext.Toolbar(
                buttons
            ),
            sm: new Ext.grid.RowSelectionModel({singleSelect: true}),
            // Note the use of a storeId, this will register thisStore
            // with the StoreMgr and allow us to retrieve it very easily.

            store: new twowayfitness.MessageStore({
                 storeId: 'gridMessageStore',
                 proxy: new Ext.data.HttpProxy(
                     new Ext.data.Connection(
                       {
                           url: this.url('inbox'),
                           method: 'GET'
                       }
                     )
                 )
            }),

            // store: new twowayfitness.MessageStore({
            //     storeId: 'gridMessageStore',
            //     url: this.url('inbox')
            //     // ,
            //     // baseParams: storeBaseParams
            // }),
            enableColumnResize: true
        });
        // finally call the superclasses implementation
        twowayfitness.MessageGrid.superclass.initComponent.call(this);

        this.store.load();
        
        // Ext.StoreMgr.get('gridMessageStore').load(
        //     {
        //         method: 'GET'
        //     }
        // );
        
    }
});
// This will associate an string representation of a class
// (called an xtype) with the Component Manager
// It allows you to support lazy instantiation of your components
Ext.reg('messagegrid', twowayfitness.MessageGrid);

twowayfitness.MessageBoxNode = function(title, mailbox_name, message_boxes_panel) {
    var node = new Ext.tree.TreeNode(
        {
            text: title,
            leaf: true,
            listeners: {
                'click' : function() {
                    // alert("got click");
                    message_boxes_panel.got_click(this.mailbox_name);
                },
                scope: node
            }
        }
    );
    node.message_boxes_panel = message_boxes_panel;
    node.mailbox_name = mailbox_name;
    return node;
};

twowayfitness.MessageBoxesPanel = Ext.extend(Ext.tree.TreePanel, {
    got_click: function(mailbox_name) {
      // alert("got_click(" + mailbox_name + ") this.topPanel = " + this.topPanel);
      this.mainPanel.got_message_box_selection(mailbox_name);
    },
    
    initComponent: function() {
        var root = new Ext.tree.TreeNode(
            {
                text: "Mail Boxes",
                expanded: true
            }
        );
        Ext.apply(this,
            {
                useArrows:true,
                autoScroll:true,
                animate:true,
                enableDD:true,
                containerScroll: true, 
                title: "Menu",
                root: root
                // ,
                // listeners: {
                //     'show': {
                //             fn: function() { alert("on show"); },
                //             scope: this
                //         },
                //     'beforeclick':     {
                //                 fn: function() {
                //                     alert("beforeclick");
                //                     return true;
                //                 },
                //                 scope: this
                //             }
                //         
                // }
                
            }
        );
            
        // call the superclass's initComponent implementation
        twowayfitness.MessageBoxesPanel.superclass.initComponent.call(this);
        
        // var node = new Ext.tree.TreeNode(
        //     {
        //         // text: "inbox",
        //         listeners: {
        //             'click' : function() { alert("got a click"); },
        //             scope: this
        //         }
        //     }
        // );
        this.inboxNode = twowayfitness.MessageBoxNode("Inbox", 'inbox', this);
        root.appendChild(this.inboxNode);
        root.appendChild(twowayfitness.MessageBoxNode("Sent", 'sent', this));

        this.addListener(
            {
                'render': {
                        fn: function() {
                            // alert("on show this.inboxNode = " + this.inboxNode);
                            // this.getSelectionModel().select(this.inboxNode);
                            // this.inboxNode.ui.highlight();
                            // this.inboxNode.select();
                            return true;
                        },
                        scope: this
                    }
            }
        );
    }
});
// This will associate an string representation of a class
// (called an xtype) with the Component Manager
// It allows you to support lazy instantiation of your components
Ext.reg('messageboxespanel', twowayfitness.MessageBoxesPanel);


/**
 * twowayfitness.MessageDetail
 * @extends Ext.Panel
 * This is a specialized Panel which is used to show information about
 * a message. 
 * 
 * This demonstrates adding 2 custom properties (tplMarkup and 
 * startingMarkup) to the class. It also overrides the initComponent
 * method and adds a new method called updateDetail.
 * 
 * The class will be registered with an xtype of 'messagedetail'
 */
twowayfitness.MessageDetail = Ext.extend(Ext.Panel, {
    
    // startingMarkup as a new property
    startingMarkup: 'Please select a message to see the message body', // TODO: make this string DRY
    // override initComponent to create and compile the template
    // apply styles to the body of the panel and initialize
    // html to startingMarkup
    initComponent: function() {
        // this.tpl = new Ext.Template(this.tplMarkup);
        Ext.apply(this, {
            bodyStyle: {
                background: '#ffffff',
                padding: '7px'
            },
            autoScroll: true,
            html: this.startingMarkup
        });
        // call the superclass's initComponent implementation
        twowayfitness.MessageDetail.superclass.initComponent.call(this);
    },
    // add a method which updates the details
    updateDetail: function(data) {
        this.load({
            url: "/messages/" + data.id,
            params: {fragment: "true"},
            method: 'GET',
            // callback: yourFunction,
            // scope: yourObject, // optional scope for the callback
            // discardUrl: false,
            // nocache: false,
            // text: "",
            timeout: 30,
            scripts: true
        });
        // this.tpl.overwrite(this.body, data);     
    }
});
// register the twowayfitness.MessageDetail class with an xtype of messagedetail
Ext.reg('messagedetail', twowayfitness.MessageDetail);

/**
 * twowayfitness.MessageMasterDetail
 * @extends Ext.Panel
 * 
 * This is a specialized panel which is composed of both a messagegrid
 * and a messagedetail panel. It provides the glue between the two 
 * components to allow them to communicate. You could consider this
 * the actual application.
 * 
 */
twowayfitness.MessageMasterDetail = Ext.extend(Ext.Panel, {
    constructor: function(form_authenticity_token, correspondent_config, config) {
        this.form_authenticity_token = form_authenticity_token;
        this.correspondent_config = correspondent_config;
        // Your preprocessing here
    	twowayfitness.MessageDetail.superclass.constructor.apply(this, [ config ]);
        // Your postprocessing here
    },
    
    // override initComponent
    initComponent: function() {
        // used applyIf rather than apply so user could
        // override the defaults
        Ext.applyIf(this, {
            border: false,
            frame: false,
            title: 'Messages',
            // width: 540,
            monitorResize : true,
            // height: 700,
            // autoHeight: true,
            layout: 'border',
            tools: [
                {
                    id: 'help',
                    handler: function(event, toolEl, panel) {
                            twowayfitness.displayHelp('messages');
                        }
                }
            ],
            items: [
                {
                    xtype: 'panel',
                    // title: 'TOP PANEL',
                    itemId: 'topPanel',
                    region: 'north',
                    layout: 'border',
                    height: 200,
                    split: true,
                    items: [
                        {
                            xtype: 'messageboxespanel',
                            itemId: 'messageBoxesPanel',
                            border: false,
                            collapsible: true,
                            region: 'west',
                            // height: 150,
                            width: 150,
                            minSize: 100,
                            // maxSize: 300,
                            split: true
                        },
                        new twowayfitness.MessageGrid(
                            this.correspondent_config,
                            {
                                // xtype: 'messagegrid',
                                // title: "Items",
                                border: false,
                                region: 'center',
                                itemId: 'gridPanel',
                                minSize: 100,
                                maxSize: 300
                            }
                        )
                    ]
                }
               ,
                {
                 xtype: 'messagedetail',
                 itemId: 'detailPanel',
                 // split: true,
                 region: 'center'
                }
            ]           
        });
        // call the superclass's initComponent implementation       
        twowayfitness.MessageMasterDetail.superclass.initComponent.call(this);

        var topPanel = this.getComponent('topPanel');
        topPanel.getComponent('messageBoxesPanel').mainPanel = this;
        var gridPanel = topPanel.getComponent('gridPanel');
        gridPanel.form_authenticity_token = this.form_authenticity_token;
        gridPanel.replyButton.disable();
    },
    // override initEvents
    initEvents: function() {
        // call the superclass's initEvents implementation
        twowayfitness.MessageMasterDetail.superclass.initEvents.call(this);
        
        // now add application specific events
        // notice we use the selectionmodel's rowselect event rather
        // than a click event from the grid to provide key navigation
        // as well as mouse navigation
        
        var messageGridSm = this.getComponent('topPanel').getComponent('gridPanel').getSelectionModel();     
        messageGridSm.on('rowselect', this.onRowSelect, this);
    },
    // add a method called onRowSelect
    // This matches the method signature as defined by the 'rowselect'
    // event defined in Ext.grid.RowSelectionModel
    onRowSelect: function(sm, rowIdx, r) {
        // getComponent will retrieve itemId's or id's. Note that itemId's 
        // are scoped locally to this instance of a component to avoid
        // conflicts with the ComponentMgr
        var detailPanel = this.getComponent('detailPanel');
        detailPanel.updateDetail(r.data);
        r.set('has_been_read', true);
        var gridPanel = this.getComponent('topPanel').getComponent("gridPanel");
        if(gridPanel.mailbox_name == "inbox") {
            gridPanel.replyButton.enable();
        }
    },
    got_message_box_selection: function(mailbox_name) {
        this.getComponent('detailPanel').body.update("Please select a message to see the message body");
        var gridPanel = this.getComponent('topPanel').getComponent('gridPanel');
        gridPanel.switchMailboxes(mailbox_name);
    }
    
});
// register an xtype with this class
Ext.reg('messagemasterdetail', twowayfitness.MessageMasterDetail);

twowayfitness.flashMessage = function(message) {
    alert(message);
};

twowayfitness.CreateMessageDialog = function(subject, content, recipient_name, recipient_id, form_authenticity_token) {
    // alert("form_authenticity_token = " + form_authenticity_token);
    
    var dialog = this;
    
    var full_subject = subject;
    this.subjectField = new Ext.form.TextField(
            {
                name: 'message[subject]',
                fieldLabel: 'Subject',
                value: full_subject
            }
        );

    this.bodyField = new Ext.form.TextArea(
            {
                name: 'message[content]',
                fieldLabel: 'Message',
                height: 300,
                value: content
            }
        );

    this.recipientNameField = new Ext.form.TextField(
        {
            name: 'to',
            fieldLabel: 'To',
            disabled : true,
            value: recipient_name
        }
    );
        
    this.recipientField = new Ext.form.Hidden(
        {
            name: 'recipients',
            value: recipient_id
        }
    );

    this.formPanel = new Ext.FormPanel(
        {
            url: "/messages",
            method: 'POST',
            baseParams: {
                authenticity_token: form_authenticity_token
            },
            
            title: ('Create Message'),
            bodyStyle:'padding:5px 5px 0',
            labelWidth: 125,
            labelAlign: 'right',
            
            defaults:
                {
                    width: 450
                },
            items:
                [
                    this.recipientNameField,
                    this.subjectField,
                    this.bodyField,
                    this.recipientField
                ]
        }
    );
    
    var buttons = [
                {
                    text: 'Send',
                    handler: function() {
                        var progessBox = Ext.Msg.wait("Sending Message");
                        dialog.formPanel.form.submit(
                            {
                                success: function() {
                                    // alert("success");
                                    // twowayfitness.flashMessage("Message has been sent.");
                                    progessBox.hide();
                                    dialog.hide();
                                },
                                failure: function() {
                                    progessBox.hide();
                                    alert("Sorry, we failed to deliver that message. Please try again later.");
                                }
                            }
                        );
                    }
                },
                {
                    text: 'Cancel',
                    handler: function() {
                        dialog.hide();
                    }
                }
            ];
    
    this.window = new Ext.Window(
        {
             width: 630,
             autoHeight: true,
             closeAction:'hide',
             modal: false,
             closable: true,
             items: this.formPanel,
             buttons: buttons
         });
};

twowayfitness.CreateMessageDialog.prototype.show = function() {
    this.window.show();
};

twowayfitness.CreateMessageDialog.prototype.hide = function() {
    this.window.hide();
};

// twowayfitness.CreateMessageDialog.prototype.submit = function() {
//     // alert("about to submiturl = " + this.url);
//     this.formPanel.getForm().submit(
//         {
//             url: this.url,
//             waitMsg:'Saving Data...'
//         }
//     );
// }


twowayfitness.show_blank_message_dialog = function(recipient_name, recipient_id, form_authenticity_token)
{
    var dialog = new twowayfitness.CreateMessageDialog("", "", recipient_name, recipient_id, form_authenticity_token);
    dialog.show();
};

twowayfitness.display_messages = function(form_authenticity_token, correspondent_config)
{
    // alert("correspondent_id = " + correspondent_id);
    // Finally now that we've defined all of our classes we can instantiate
    // an instance of the app and renderTo an existing div called 'binding-example'
    // Note now that classes have encapsulated this behavior we can easily create
    // an instance of this app to be used in many different contexts, you could 
    // easily place this application in an Ext.Window for example
    Ext.onReady(
        function() {
            // create an instance of the app
            var messageApp = new twowayfitness.MessageMasterDetail(
                form_authenticity_token,
                correspondent_config,
                {
                    renderTo: 'binding-example'
                }
            );
            // We can retrieve a reference to the data store
            // via the StoreMgr by its storeId
            Ext.StoreMgr.get('gridMessageStore').load(
                {
                    method: 'GET'
                }
            );
        }
    );
};

show_activity_dialog = function(entry_id, rails_authenticity_token, options) {
    var box = Ext.MessageBox.wait('Fetching Information');
    
    if(!options) {
        options = {};
    }
    
    Ext.applyIf(options, {
        allow_edit: true
    });
    
    var url = "/exercise_diary_entries/" + entry_id;
    
    var activity_data = new Ext.data.Store(
        {
            proxy: new Ext.data.HttpProxy(
                 {
                     url: url
                 }
             ),
             reader: new Ext.data.JsonReader(
                 {},

                 [
                     'success',
                     'id',
                     'diary_id',
                     //'duration',
                     'duration_hrs',
                     'duration_min',
                     'duration_sec',
                     'distance',
                     'tag_id',
                     'activities',
                     'comments',
                     'injuries',
                     'ple',
                     'time_as_string',
                     'time_of_day_as_string'
                 ]
             ),
             remoteSort: false
         }
     );
     activity_data.on('load', function() {
         box.hide();
         var data = activity_data.reader.jsonData;
         if(data.failed) {
             alert('Failed to retrieve entry. Perhaps it has been deleted.');
         } else {
             if(options.duplicate) {
                 showDuplicateExerciseActivityDialog(rails_authenticity_token, data, options);
             } else {
                 showExerciseActivityDialog(rails_authenticity_token, options.allow_edit, data, options);
             }
         }
     });
     activity_data.load();
};

twowayfitness.makeExertionField = function(name, hidden_name, options) {
    var levels =
            [
                ['0', "0 - resting"],
                ['0.5', "0.5"],
                ['1', "1 - easy"],
                ['1.5', "1.5"],
                ['2', "2 - mild"],
                ['2.5', "2.5"],
                ['3', "3 - average"],
                ['3.5', "3.5"],
                ['4', "4 - hard"],
                ['4.5', "4.5"],
                ['5', "5 - intense"]
            ];
    
    // var tooltip = '1: Very easy. Talking is no difficulty - strolling walk with stops - "I could do this is in my sleep".<br>2:Moderately easy. Talking takes some effort. Working up a bit of a sweat - brisk walk - "This will make me tired after a while".<br>3:Moderately difficult. Talking is not easy and requires effort. Muscles getting tired. Sweating - hard bushwalk, slow jog - "This is tiring but I can continue".<br>4: Difficult. Talking very hard to do. Getting puffed. Sweating a lot. Muscles tired - medium-hard jog, hard game of sport - "I need a rest break".<br>5: Peak Effort. You are working as hard as you can. You have just enough breath to finish the exercise - sprinting, lifting heavy weights - "I have to stop, I am spent".';
    
    var tooltip = '1: EASY. Talking is no difficulty - strolling walk with stops - "I could do this in my sleep". Most people could maintain this level for a few hours. Heart rate 60-100bpm (beats per minute).<br>2: LIGHT. Talking takes some effort. Working up a bit of a sweat - brisk walk - "This will make me tired after a while". Most people could maintain this level for an hour or more. Heart rate 100-130bpm.<br>3: MODERATE. Talking is not easy and requires effort. Muscles getting tired. Sweating - hard mountain walk, slow to medium jog - "This is tiring but I can continue". Most people could maintain this level for between 20 and 60 minutes. Heart rate 130-150bpm.<br>4: HARD. Talking very hard to do. Getting puffed. Sweating a lot. Muscles tired - medium-hard jog, hard game of sport - "I need a rest break". Most people could maintain this level for up to 20mins. Heart rate 150-170bpm.<br>5: MAXIMUM. You are working as hard as you can. You have just enough breath to finish the exercise - sprinting, lifting heavy weights - "I have to stop, I\'m spent". This level is a peak effort and can only be sustained for up to 1 minute at a time. Heart rate 170bpm+.';
    
    var ret = new Ext.form.ComboBox({
        name: name,
        value: options.value,
        hiddenName: hidden_name,
        fieldLabel: options.is_template ? "Expected Exertion" : "Perceived Exertion",
        store: levels,
        triggerAction: 'all',
        emptyText:'Select a level...',
        selectOnFocus:true,
        listeners: {
                    render: function() {
                        // not as DRY as it could be ...
                        Ext.QuickTips.register({
                                                target: Ext.get(this.id),
                                                title: 'Exertion Levels',
                                                text: tooltip,
                                                hideDelay: 0,
                                                dismissDelay: 60000
                                            });
                        Ext.QuickTips.register({
                                                target:Ext.get(this.id).next('img'),
                                                title: 'Exertion Levels',
                                                text: tooltip,
                                                hideDelay: 0,
                                                dismissDelay: 60000
                                            });

                    }
        },                
        width: 150
    });
    
    return ret;
};

var makeTagCombo = function(name, hidden_name, value) {
    var items = [
        {
            "name": "none",
            "id": null
        }
    ];

    items = items.concat(twowayfitness.app_config.tags);

    var tag_store = new Ext.data.JsonStore({
        autoDestroy: true,
        data: items,
        storeId: 'tagStore',
        fields: [ 'id', 'name' ]
    });

    return new Ext.form.ComboBox({
        name: name,
        value: value,
        hiddenValue: value,
        hiddenName: hidden_name,
        allowBlank: true,
        editable: false,
        hiddenId: 'tag-combo-box',
        mode: 'local',
        fieldLabel: "Tag",
        displayField: 'name',
        valueField: 'id',
        store: tag_store,
        triggerAction: 'all',
        emptyText:'Tag this item...',
        selectOnFocus: true
        //listeners: {
        //            render: function() {
        //                // not as DRY as it could be ...
        //                Ext.QuickTips.register({
        //                                        target: Ext.get(this.id),
        //                                        title: 'Exertion Levels',
        //                                        text: tooltip,
        //                                        hideDelay: 0,
        //                                        dismissDelay: 60000
        //                                    });
        //                Ext.QuickTips.register({
        //                                        target:Ext.get(this.id).next('img'),
        //                                        title: 'Exertion Levels',
        //                                        text: tooltip,
        //                                        hideDelay: 0,
        //                                        dismissDelay: 60000
        //                                    });
        //
        //            }
        //},
        //width: 150
    });
};

function exerciseDurationField(field_prefix) {
    return makeDuration2Field(field_prefix, { name: 'exercise_diary_entry[duration]' });
}

// =========================================
// SectionPanel
// =========================================
twowayfitness.SectionPanel = Ext.extend(Ext.Panel, {
    constructor: function(config) {
        Ext.log('twowayfitness.SectionPanel() duration_hrs= ' + config.duration_hrs);
        Ext.apply(this, config);
        
        // Your preprocessing here
        twowayfitness.SectionPanel.superclass.constructor.apply(this, [ config ]);
        // Your postprocessing here
    },
    sectionsPanel: function() {
        return this.findParentByType(twowayfitness.SectionsPanel);
    },
    setMyTitle: function(title) {
        if(title == '') {
            title = ' ';
        }
        this.setTitle(title);
    },
    initComponent: function() {
        var self = this;

        this.field_name_prefix = 'exercise_diary_entry[sections][' + this.id + ']';
        
        this.nameField = new Ext.form.TextField(
                {
                    name: this.field_name_prefix + '[name]',
                    value: this.title,
                    fieldLabel: 'Section Title',
                    enableKeyEvents: true,
                    listeners: {
                        'keyup': {
                            fn: function() {
                                var title = self.nameField.getValue();
                                self.setMyTitle(title);
                                self.ownerCt.doLayout();
                            },
                            scope: self
                        }
                    }
                    // ,
                    // width: 200
                }
            );

        this.exertionField = twowayfitness.makeExertionField(this.field_name_prefix + '[ple]', this.field_name_prefix + '[ple]', {
            value: this.ple,
            is_template: this.is_template
        });

        this.newDurationField = exerciseDurationField(this.field_name_prefix + '[duration2[');
        this.newDurationField.hrs_field.setValue(this.duration_hrs);
        this.newDurationField.min_field.setValue(this.duration_min);
        this.newDurationField.sec_field.setValue(this.duration_sec);

        //this.durationField = new Ext.form.TextField(
        //        {
        //            name: this.field_name_prefix + '[duration]',
        //            fieldLabel: 'Duration (minutes)',
        //            value: this.duration
        //        }
        //    );

        this.distanceField = new Ext.form.TextField(
                {
                    name: this.field_name_prefix + '[distance]',
                    fieldLabel: 'Distance (' + twowayfitness.app_config.distance_unit + ')',
                    value: this.distance ? this.distance : '0.0'
                }
            );

        this.detailsField = new Ext.form.TextArea(
                {
                    name: this.field_name_prefix + '[details]',
                    fieldLabel: 'Details (optional)',
                    value: this.details,
                    width: 220
                }
            );

        this.tagField = makeTagCombo(this.field_name_prefix + '[tag_id]', this.field_name_prefix + '[tag_id]', this.tag_id ? this.tag_id : '');

        this.positionField = new Ext.form.Hidden({
            name: this.field_name_prefix + '[position]',
            value: ''
        });
        
        
          Ext.applyIf(this, {
              autoHeight: true,
              draggable: {
                  onDrag : function(e){
                      var pel = this.proxy.getEl();
                      this.xx = pel.getLeft(true);
                      this.yy = pel.getTop(true);
                  },

          //      Called on the mouseup event.
                  endDrag : function(e) {
                      self.sectionsPanel().reorderSection(self, this.xx, this.yy);
                  }
              },
              
              tools: [
                {
                    id: 'close',
                    handler: function() {
                        var parent = self.findParentByType(twowayfitness.SectionsPanel);
                        parent.removeSection(self, true);
                    }
                }
              ],
              layoutOnTabChange: true,
              deferredRender: false,
              bodyStyle: 'padding: 5px 2px',
              items: [
                {
                    layout: 'column',
                    border: false,
                    items: [
                        this.positionField,
                        {
                            xtype: 'fieldset', 
                            columnWidth: 0.45,
                            labelWidth: 130,
                            border: false,
                            autoHeight: true,
                            items: [
                                this.nameField,
                                this.newDurationField,
                                //this.durationField,
                                this.exertionField,
                                this.distanceField,
                                this.tagField
                            ]
                        },
                        {
                            xtype: 'fieldset', 
                            columnWidth: 0.55,
                            labelWidth: 130,
                            border: false,
                            autoHeight: true,
                            items: [
                                this.detailsField
                            ]
                        }
                    ]
                }
              ]
          });

          this.setMyTitle(this.title);
          twowayfitness.SectionPanel.superclass.initComponent.call(this);
    }
});

// ========================================
// SectionsPanel
// ======================================== 
twowayfitness.SectionsPanel = Ext.extend(Ext.form.FieldSet, {
    setPositionFields: function() {
        var all_sections = this.sections();
        all_sections.each(function(section, index) {
            section.positionField.setValue(index);
        });
    },
    removeSection: function(section, destroy) {
        var all_sections = this.sections();
        if(all_sections.getCount() <= 1) {
            twowayfitness.showPlainMessage("Cannot remove this section. An exercise activity must have at least one section.");
//            Ext.Msg.alert('Notice', "Cannot remove this section. An exercise activity must have at least one section.");
        } else {
            this.innerPanel.remove(section, destroy);
            this.doLayout();
        }
    },
    copySectionDetails: function(dest, src) {
        Ext.log('copySectionDetails');
        dest.setTitle(src.title);
        dest.nameField.setValue(src.nameField.getValue());
        dest.newDurationField.copyValues(src.newDurationField);
        //dest.durationField.setValue(src.durationField.getValue());
        dest.exertionField.setValue(src.exertionField.getValue());
        dest.distanceField.setValue(src.distanceField.getValue());
        dest.tagField.setValue(src.tagField.getValue());
    },
    moveSection: function(from_index, to_index, sections) {
        if(from_index == to_index) {
            // nothing to do
            return;
        }
        
        var section = sections.get(from_index);
        var title = section.title;
        var name = section.nameField.getValue();
        //var duration = section.durationField.getValue();
        var duration_hrs = section.newDurationField.hrs_field.getValue();
        var duration_min = section.newDurationField.min_field.getValue();
        var duration_sec = section.newDurationField.sec_field.getValue();
        var ple = section.exertionField.getValue();
        var distance = section.distanceField.getValue();
        var tag = section.tagField.getValue();
        var details = section.detailsField.getValue();
        
        var to_section;
        if(from_index < to_index) {
            // we need to shift elements up
            to_section = sections.get(to_index-1);
            for(var j = from_index; j < to_index-1 ; ++j) {
                var src = sections.get(j+1);
                var dest = sections.get(j);
//                jstracer.write('moveSection() src = ' + (j+1) + ' dest = ' + j + ' current title = ' + dest.title + ' setting title to ' + src.title);
                this.copySectionDetails(dest, src);
            }
        } else {
            // we need to shift elements down
            to_section = sections.get(to_index);
            for(var j = from_index - 1; j >= to_index ; --j) {
                var src = sections.get(j);
                var dest = sections.get(j+1);
//                jstracer.write('moveSection() j = ' + j + ' current title = ' + dest.title + ' setting title to ' + src.title);
                this.copySectionDetails(dest, src);
            }
        }
        to_section.setTitle(title);
        to_section.nameField.setValue(name);
        //to_section.durationField.setValue(duration);
        to_section.newDurationField.hrs_field.setValue(duration_hrs);
        to_section.newDurationField.min_field.setValue(duration_min);
        to_section.newDurationField.sec_field.setValue(duration_sec);
        to_section.exertionField.setValue(ple);
        to_section.distanceField.setValue(distance);
        to_section.tagField.setValue(tag);
        to_section.detailsField.setValue(details);
    },
    // given that the supplied section has been dragged to position (x,y), reorder the section
    // amongst the other sections in the sections panel such that the drag request has been satisfied.
    reorderSection: function(section, x, y) {
        var all_sections = this.sections();
        
        // first determine position of the section being dragged
        var section_index;
        all_sections.each(function(other_section, index, length) {
            // jstracer.write("  '" + item.title + "' y = " + item.getPosition()[1]);
            if(other_section === section) {
                section_index = index;
            }
        });
        
        // for(var i = 0; i < all_sections.length; i++) {
        //     var other_section = all_sections[i];
        //     if(other_section === section) {
        //         section_index = i;
        //     }
        // }
        
        var found_place = false;
        for(var i = 0; !found_place && i < all_sections.length; i++) {
           var other_section = all_sections.get(i);
           var other_y = other_section.getPosition()[1];
           if(other_y > y) {
               // We have determined that we need to position section before other_section.
               // I tried implementing this by removing the section from its container
               // and inserting it back in, but never quite got it working. From reading
               // the Ext forum it seems that support for moving things around in forms is
               // not great.
               // 
               // So, instead of that I leave the sections where they are, but move the data
               // around instead.
               this.moveSection(section_index, i, all_sections);
               
               found_place = true;
           }
        }
        if(!found_place) {
            this.moveSection(section_index, all_sections.length, all_sections);
        }
    },
    numSections: function() {
        return this.items.length;
    },
    sections: function() {
        var all_sections = this.items;

//        all_sections.each(function(item, index, length) {
//            jstracer.write("  '" + item.title + "' y = " + item.getPosition()[1]);
//        });
        
        return all_sections;
    },
    initComponent: function() {
      var self = this;
        

      Ext.applyIf(this, {
          autoHeight: true,
          title: 'Sections',
          border: true,
          items: [
              new twowayfitness.SectionPanel({ title: 'Section 1', formPanel: self.formPanel, is_template: this.is_template })
          ],
          bbar: new Ext.Toolbar(
              [
                  {
                      text: 'add section',
                      iconCls:'add',
                      handler: function() {
                          var newPanel = new twowayfitness.SectionPanel({
                              title: '',
                              formPanel: self.formPanel,
                              is_template: self.is_template
                          });
                          self.innerPanel.add(
                              newPanel
                          );
                          self.doLayout();
                      }
                  }
              ]
          )
      });
      this.innerPanel = this;
      twowayfitness.SectionsPanel.superclass.initComponent.call(this);
    }
});


function ExerciseActivityDialog(allow_edit, is_new, options) {
    var self = this;
    
    Ext.applyIf(self, options);
    
    this.numSections = function() {
        return this.sectionsPanel.numSections();
    };
    
    this.showSections = function(user_is_switching) {
        this.instructions_panel.body.update("<div class='instructions'><h3>Use a Single Section</h3><p>To revert to a single section for this activity, uncheck the 'Split activity into sections' checkbox.</p></div>");
        this.durationAndExertionComponent.hide();
        this.sectionsPanel.show();
        this.previousHeight = this.window.getSize().height;
//        jstracer.write('expanding this.previousHeight = ' + this.previousHeight + 'this.window.getSize().height = ' + this.window.getSize().height)
        this.formPanel.setWidth(this.widthWhenComplex);
        this.window.use_max_possible_height = true;
        this.window.setSizeAndPosition();

        // showSections is called both when the dialog is being displayed for the first time, and
        // when the user is switching from not displaying sections.
        // In the latter case we want to copy values from the main part of the dialog to the section part.
        if(user_is_switching) {
            var section = this.sectionsPanel.sections().get(0);
            section.newDurationField.copyValues(this.newDurationField);
            //section.durationField.setValue(this.durationField.getValue());
            section.exertionField.setValue(this.exertionField.getValue());
            section.distanceField.setValue(this.distanceField.getValue());
            section.tagField.setValue(this.tagField.getValue());
        }

        this.window.doLayout();
        if(user_is_switching) {
            this.instructions_panel.getEl().frame();
        }
    };
    
    this.hideSections = function(user_is_switching) {
        this.instructions_panel.body.update("<div class='instructions'><h3>Split into Sections</h3><p>To split this activity into individual sections select the 'Split activity into sections' checkbox.</p></div>");
        this.durationAndExertionComponent.show();
        this.sectionsPanel.hide();
        this.window.setHeight(this.previousHeight);
        this.previousHeight = this.window.getSize().height;
        this.formPanel.setWidth(this.widthWhenSimple);
        this.window.use_max_possible_height = false;
//        jstracer.write('this.previousHeight = ' + this.previousHeight + 'this.window.getSize().height = ' + this.window.getSize().height);
        this.window.setSizeAndPosition();
        this.window.doLayout();
        
        var section = this.sectionsPanel.sections().get(0);
        this.newDurationField.copyValues(section.newDurationField);
        //this.durationField.setValue(section.durationField.getValue());
        this.exertionField.setValue(section.exertionField.getValue());
        this.distanceField.setValue(section.distanceField.getValue());
        this.tagField.setValue(section.tagField.getValue());

        if(user_is_switching) {
            this.instructions_panel.getEl().frame();
        }
    };
    
    this.displayHelp = function() {
        twowayfitness.displayHelp(this.is_template ? 'activity_template' : 'exercise');
    };

    this.widthWhenSimple = 800;
    this.widthWhenComplex = 800;
    
    if(this.is_template) {
        this.templateNameField = new Ext.form.TextField({
            width: 400,
            name: 'activity_template[name]',
            fieldLabel: "Name of Regular Activity"
        });
    } else {
        this.dateField = new Ext.form.DateField(
            {
                name: 'date',
                fieldLabel: 'When - date',
                format: 'Y-m-d',
                allowBlank: false,
                value: this.date,
                readOnly: true,
                width: 130
            }
        );
    }
        
    this.timeField = new Ext.form.TimeField(
            {
                name: 'exercise_diary_entry[time_of_day]',
                fieldLabel: 'Time of Day',
                increment: 30,
                width: 130
            }
        );
        
    var defaultFieldWidth = 270;
    
    this.activitiesField = new Ext.form.TextField(
            {
                width: defaultFieldWidth,
                name: 'exercise_diary_entry[activities]',
                fieldLabel: "Summary"
            }
        );

    this.dummyField = new Ext.form.TextArea(
            {
                width: defaultFieldWidth,
                name: 'exercise_diary_entry[dummy]',
                fieldLabel: "Dummy"
            }
        );
        
    this.injuriesField = new Ext.form.TextArea(
            {
                width: defaultFieldWidth,
                name: 'exercise_diary_entry[injuries]',
                fieldLabel: "Injuries"
            }
        );

    this.commentsField = new Ext.form.TextArea(
            {
                width: defaultFieldWidth,
                name: 'exercise_diary_entry[comments]',
                fieldLabel: "Comments"
            }
        );

    //this.durationField = new Ext.form.TextField(
    //        {
    //            name: 'exercise_diary_entry[duration]',
    //            fieldLabel: 'Duration (minutes)',
    //            value: this.duration
    //        }
    //    );

    this.distanceField = new Ext.form.TextField(
            {
                name: 'exercise_diary_entry[distance]',
                fieldLabel: 'Distance (' + twowayfitness.app_config.distance_unit + ')',
                value: this.distance ? this.distance : '0.0'
            }
        );

    this.sectionsPanel = new twowayfitness.SectionsPanel({
        is_template: this.is_template
    });

    this.exertionField = twowayfitness.makeExertionField('exercise_diary_entry[ple]', 'exercise_diary_entry[ple]', {
        is_template: this.is_template
    });

    this.tagField = makeTagCombo('exercise_diary_entry[tag_id]', 'exercise_diary_entry[tag_id]', this.tag_id ? this.tag_id : '');
    //this.tagField = makeTagCombo('exercise_diary_entry[tag_id]', 'exercise_diary_entry[tag_id]', 2);

    this.instructions_panel = new Ext.Panel({
        width: 350,
        style:'margin: 3px',
        border: false
    });

    this.newDurationField = exerciseDurationField('exercise_diary_entry[duration2[');

    this.durationAndExertionComponent = new Ext.form.FieldSet({
        autoHeight: true,
        border: false,
        labelWidth: 120,
        style: 'padding: 0px; margin: 0px',
        bodyStyle: 'padding: 0px; margin: 0px',
        items: [
            //this.durationField,
            this.newDurationField,
            this.exertionField,
            this.distanceField,
            this.tagField
        ]
    });
        
    this.useSectionsCheckBox = new Ext.form.Checkbox(
            {
                name: 'exercise_diary_entry[use_sections]',
                fieldLabel: "Split activity into sections",
                listeners: {
                    'check': {
                        fn: function(checkbox, checked) {
                            if(self.settingCheckBoxRecursively) {
                                // Don't handle event if we're being called recursively.
                                // Does Ext provide a way to do this more elegantly?
                                return;
                            }
                            if(checkbox.rendered) {
                                if(checked) {
                                    this.showSections(true);
                                } else {
                                    if(this.numSections() == 1) {
                                        this.hideSections(true);
                                    } else {
                                        twowayfitness.showPlainMessage("Cannot switch to single section view while there is more than one section. Please remove all but one section and try again.");
                                        self.settingCheckBoxRecursively = true;
                                        checkbox.setValue(true);
                                        self.settingCheckBoxRecursively = false;
                                    }
                                }
                            }
                        },
                        scope: self
                    }
                    
                }
            }
        );

    var top_section_form_items = [];
    if(this.is_template) {
    } else {
        top_section_form_items.push(this.dateField);
    }
    top_section_form_items = top_section_form_items.concat(
        [
            this.timeField,
            this.activitiesField,
            this.durationAndExertionComponent,
            this.commentsField,
            this.injuriesField
        ]
    );
    
    var top_section = new Ext.Panel({
        width: this.widthWhenSimple,
        layout: 'column',
        border: false,
        items: [
            {
                width: 450,
                xtype: 'fieldset',
                labelWidth: 120,
                columnWidth: 1.0,
                defaultType: 'textfield',
                autoHeight: true,
                bodyStyle: Ext.isIE ? 'padding:0 0 5px 15px;' : 'padding:10px 15px;',
                border: false,                        
                items: top_section_form_items
            },
            {
                border: false,
                items: [
                    this.instructions_panel,
                    {
                        xtype: 'fieldset',
                        labelWidth: 170,
                        autoHeight: true,
                        bodyStyle: Ext.isIE ? 'padding:0 0 5px 15px;' : 'padding:10px 15px;',
                        border: false,                        
                        items: [
                            this.useSectionsCheckBox
                        ]
                    }
                ]
            }
        ]
    });
    
    var formPanelItems = [];
    if(this.templateNameField) {
        formPanelItems.push(
            {
                border: false,
                xtype: 'fieldset',
                labelWidth: 200,
                defaultType: 'textfield',
                autoHeight: true,
                style: 'background-color: #00ddff',
                // bodyStyle: Ext.isIE ? 'padding:0 0 5px 15px;' : 'padding:10px 15px;',
                bodyStyle: 'padding:10px 15px;',
                items: [
                    this.templateNameField
                ]
            }
        );
    }
    
    formPanelItems.push(top_section);
    formPanelItems.push(
        {
            xtype: 'fieldset',
            labelWidth: 100,
            columnWidth: 1.0,
            defaultType: 'textfield',
            autoHeight: true,
            border: false,                        
            items: [
                this.sectionsPanel
            ]
        }
    );
    
    this.formPanel = new Ext.FormPanel(
        {
            style: 'padding-top: 5px',
            labelWidth: 100,
            width: this.widthWhenSimple - 20,
            border: false,
            labelAlign: 'right',
//            initialConfig: {
//                submitOnEnter: true
//            },
            items:  formPanelItems
        }
    );
    
    // following is a hack to workaround https://extjs.com/forum/showthread.php?t=51414
    this.sectionsPanel.formPanel = this.formPanel;
    
    var buttons = [];
    if(allow_edit) {
        buttons = buttons.concat(
            is_new ?
                {
                    text:'Submit',
                    handler: function() {
                        exerciseActivityDialog.submit();
                    }
                }
            :
                [
                    {
                        text:'Save Changes',
                        handler: function() {
                            exerciseActivityDialog.submit();
                        }
                    }
                ]
        );
        
    }
    
    buttons.push(
        {
            text: 'Cancel',
            handler: function() {
                exerciseActivityDialog.hide();
            }
        }
    );
    buttons.push(
        {
            text: 'Help',
            handler: function() {
                self.displayHelp();
            }
        }
    );
    
    this.window = new twowayfitness.PopupWindow(
        {
            title: this.is_template ? 'Regular Exercise Activity' : 'Exercise Activity',
            // I don't like setting the width here, but I'm struggling to get things right across all the browsers
            width: this.widthWhenSimple + 20,
            closeAction:'hide',
            showCloseButtons: false,
            constrain_to: twowayfitness.main_panel,
//            keys: [
//               {
//                   key: Ext.EventObject.ENTER,
//                   handler: function() {
//                       exerciseActivityDialog.submit();
//                   }
//               }
//            ],
            tools: [
                {
                    id: 'help',
                    handler: function() {
                        self.displayHelp();
                    }
                }
            ],
            listeners: {
                'show': {
                    fn: function() {
                        if(self.useSectionsCheckBox.getValue()) {
                            self.showSections(false);
                        } else {
                            self.hideSections(false);
                        }
                    }
                }
            },
            modal: true,
            closable: true,
            items: this.formPanel,
            buttons: buttons
         });
}

ExerciseActivityDialog.prototype.show = function() {
    this.window.show();
};

ExerciseActivityDialog.prototype.hide = function() {
    this.window.hide();
};

ExerciseActivityDialog.prototype.handle_submission_success = function(form, action) {
    hideExerciseActivityDialog();
    Ext.MessageBox.hide();
    
    var result = action.result;
    this.submission_succeeded(result);
};

// ExerciseActivityDialog.prototype.delete_entry = function() {
//     var self = this;
//     Ext.Msg.confirm('Delete Exercise Entry', 'Are you sure you wish to delete this entry?', function(btn, text) {
//         if (btn == 'yes') {
//             // dialog_window.hide();
//             self.formPanel.getForm().submit(
//                 {
//                     url: self.url,
//                     params: { '_method': 'delete' },
//                     waitMsg:'Deleting Entry ...',
//                     success: function(form, action) {
//                         self.handle_submission_success(form, action);
//                     },
//                     failure: function(form, action) {
//                         twowayfitness.handle_form_submission_failure(form, action);
//                     }
//                 }
//             );
//         }
//     });
// };

ExerciseActivityDialog.prototype.submit = function() {
    var self = this;
    this.sectionsPanel.setPositionFields();
    this.formPanel.getForm().submit(
        {
            url: this.url,
            waitMsg:'Saving Data...',
            success: function(form, action) {
                self.handle_submission_success(form, action);
            },
            failure: function(form, action) {
                twowayfitness.handle_form_submission_failure(form, action);
            }
        }
    );
};

ExerciseActivityDialog.prototype.set_values = function(template_or_activity_data, rails_authenticity_token, is_edit, options) {
    this.is_new = false;
    
    var creating_new = !is_edit;
    
//    jstracer.write('set_values is_edit = ' + is_edit + ' creating_new = ' + creating_new);
//    jstracer.write('template_or_activity_data = ' + template_or_activity_data + ' (options.is_template && !creating_new) = ' + (options.is_template && !creating_new));

    var data = (options.is_template && !creating_new) ? template_or_activity_data.entry : template_or_activity_data;

    if(creating_new) {
        if(options.is_template) {
            this.url = '/activity_templates';
        } else {
            this.url = '/exercise_diary_entries';
        }
    } else {
        if(options.is_template) {
            this.url = '/activity_templates/' + template_or_activity_data.id + '?format=ext_json';
        } else {
            this.url = '/exercise_diary_entries/' + data.id + '?format=ext_json';
        }
    }
    
    this.formPanel.getForm().baseParams = {
        '_method': (is_edit ? 'put' : 'post'),
        'authenticity_token': rails_authenticity_token
    };
    
    this.rails_authenticity_token = rails_authenticity_token;
    
    if(options.is_template) {
        this.templateNameField.setValue(template_or_activity_data.name);
    } else {
        this.dateField.setValue(new Date(data.date_as_string));
    }
    this.timeField.setValue(data.time_of_day_as_string);
    this.activitiesField.setValue(data.activities);

    var section1 = data.sections_as_array[0];
    this.newDurationField.setValues(section1);
    //this.durationField.setValue(section1.duration);
    this.exertionField.setValue(data.average_exertion);
    this.distanceField.setValue(data.distance);
    this.tagField.setValue(data.tag);
    this.injuriesField.setValue(data.injuries);
    this.commentsField.setValue(data.comments);
    this.useSectionsCheckBox.setValue(data.use_sections);
    
    twowayfitness.remove_all_components(this.sectionsPanel);
    for(var index = 0; index < data.sections_as_array.length; ++index)
    {
        var section_info = data.sections_as_array[index];
        Ext.log('section[' + index + '] duration_hrs = ' + section_info.duration_hrs);
        var newPanel = new twowayfitness.SectionPanel({
            formPanel: this.formPanel,
            title: section_info.name,
            is_template: options.is_template,
            duration_hrs: section_info.duration_hrs,
            duration_min: section_info.duration_min,
            duration_sec: section_info.duration_sec,
            //duration: section_info.duration,
            distance: section_info.distance,
            tag_id: section_info.tag_id,
            details: section_info.details,
            ple: section_info.ple
        });
        this.sectionsPanel.add(
            newPanel
        );
    }
    this.sectionsPanel.doLayout();
};

ExerciseActivityDialog.prototype.set_as_new = function(rails_authenticity_token, options)
{
    this.is_new = true;
    this.rails_authenticity_token = rails_authenticity_token;
    
    this.url = options.is_template ? '/activity_templates' : '/exercise_diary_entries';
    
    this.formPanel.getForm().baseParams = {
        'authenticity_token': rails_authenticity_token
    };

    if(options.date) {
        this.dateField.setValue(options.date);
    }
    this.timeField.setValue('');
    this.newDurationField.setAsNew();
    //this.durationField.setValue('');
    this.distanceField.setValue('');
    this.tagField.setValue('');
    this.activitiesField.setValue('');
    this.injuriesField.setValue('');
    this.commentsField.setValue('');
};

function showExerciseActivityDialog(rails_authenticity_token, allow_edit, data, options)
{
    this.exerciseActivityDialog = new ExerciseActivityDialog(allow_edit, false, options);
    this.exerciseActivityDialog.set_values(data, rails_authenticity_token, options.is_edit, options);
    this.exerciseActivityDialog.show();
}

function showDuplicateExerciseActivityDialog(rails_authenticity_token, data, options)
{
    this.exerciseActivityDialog = new ExerciseActivityDialog(true, true, options);
    this.exerciseActivityDialog.set_values(data, rails_authenticity_token, false, options);
    this.exerciseActivityDialog.dateField.setValue(new Date(options.date));
    this.exerciseActivityDialog.show();
}

function newExerciseActivity(rails_authenticity_token, options)
{
    this.exerciseActivityDialog = new ExerciseActivityDialog(true, true, options);
    this.exerciseActivityDialog.set_as_new(rails_authenticity_token, options);
    this.exerciseActivityDialog.show();
}

function ensureExerciseActivityDialogExists()
{
}

function hideExerciseActivityDialog()
{
    this.exerciseActivityDialog.hide();
}



// ~ f.text_area :breakfast, :rows => 2
// ~ f.text_area :morning_tea, :rows => 2
// ~ f.text_area :lunch, :rows => 2
// ~ f.text_area :afternoon_tea, :rows => 2
// ~ f.text_area :dinner, :rows => 2
// ~ f.text_area :supper, :rows => 2
// ~ f.text_area :other_food, :rows => 2, :label => "Other food intake"
// ~ f.text_area :notes, :rows => 2

twowayfitness.edit_dietary_intake = function(url, rails_authenticity_token, diet_panel) {
    var activity_data = new Ext.data.Store(
        {
            proxy: new Ext.data.HttpProxy(
                 {
                     url: url
                 }
             ),
             reader: new Ext.data.JsonReader(
                 {},

                 [
                     'id',
                     "date",
                     "breakfast",
                     "morning_tea",
                     "lunch",
                     "afternoon_tea",
                     "dinner",
                     "supper",
                     "other_food",
                     "notes"
                 ]
             ),
             remoteSort: false
         }
     );
     activity_data.on('load', function() {
         // alert("data loaded");
         var data = activity_data.reader.jsonData;
         // alert("breakfast = " + data.breakfast);
         
         var window = new twowayfitness.DietaryIntakeWindow(data, rails_authenticity_token, diet_panel);
         window.show();
     });
     activity_data.load();
};

twowayfitness.edit_dietary_intake_from_date = function(year, month, day, rails_authenticity_token, diet_panel) {
    var url = "/client/day/" + year + "/" + month + "/" + day + '.ext_json';
    twowayfitness.edit_dietary_intake(url, rails_authenticity_token, diet_panel);
};

twowayfitness.edit_dietary_intake_from_id = function(diary_day_id, rails_authenticity_token, diet_panel) {
    // alert("edit_dietary_intake diet_panel = " + diet_panel);
    var url = "/diary_days/" + diary_day_id + '.ext_json';
    twowayfitness.edit_dietary_intake(url, rails_authenticity_token, diet_panel);
};

twowayfitness.DietaryIntakeWindow = Ext.extend(twowayfitness.PopupWindow, {
    text_area: function(name, label) {
        return new Ext.form.TextArea(
                {
                    name: 'diary_day[' + name + ']',
                    fieldLabel: label,
                    value: this.data[name]
                }
            );
    },
    constructor: function(data, form_authenticity_token, diet_panel, config) {
        this.form_authenticity_token = form_authenticity_token;
        this.data = data;
        this.diet_panel = diet_panel;
        this.url = '/diary_days/' + data.id; // '?format=ext_json';
        
        
        // Your preprocessing here
    	twowayfitness.DietaryIntakeWindow.superclass.constructor.apply(this, [ config ]);
        // Your postprocessing here
    },
    // override 
    initComponent : function() {
        var self = this;
        this.formPanel = new Ext.FormPanel(
            {
                title: 'Dietary Intake for ' + this.data.date,
                bodyStyle:'padding:5px 5px 0',
                // width: 800,
                labelWidth: 125,
                // autoHeight: true,
                // height: 500,
                autoScroll: true,
                labelAlign: 'right',

                defaults:
                    {
                        width: 250
                    },
                items:
                    [
                        // this.dateTimeField
                        // ,
                        // this.dateTimePanel
                        // ,
                        this.text_area('breakfast', 'Breakfast'),
                        this.text_area('morning_tea', 'Morning Tea'),
                        this.text_area('lunch', 'Lunch'),
                        this.text_area('afternoon_tea', 'Afternoon Tea'),
                        this.text_area('dinner', 'Dinner'),
                        this.text_area('supper', 'Supper'),
                        this.text_area('other_food', 'Other'),
                        this.text_area('notes', 'Notes')
                        // dateField
                    ]
            }
        );

        var buttons = [];
        buttons = buttons.concat(
            [
                {
                    text:'Save Changes',
                    handler: function() {
                        self.submit();
                    }
                }
            ]
        );

        buttons.push(
            {
                text: 'Cancel',
                handler: function() {
                    self.hide();
                }
            }
        );
        
        Ext.apply(this,
            {
                constrain_to: twowayfitness.main_panel,
                width: 430,
                showCloseButtons: false,
                closeAction:'hide',
                modal: true,
                closable: true,
                items: this.formPanel,
                buttons: buttons
            }
        );
        twowayfitness.DietaryIntakeWindow.superclass.initComponent.call(this);
    },
    submit: function() {
        // alert("submitting ");
        var self = this;
        this.formPanel.getForm().baseParams = {
            '_method':'put',
            'authenticity_token': this.form_authenticity_token
        };
        
        this.formPanel.getForm().submit(
            {
                url: this.url,
                method: 'PUT',
                waitMsg:'Saving Data...',
                success: function(form, action) {
                    var result = action.result;
                    self.diet_panel.setData(result);
                    self.hide();
                    
                    // alert("success url = " + action.result.url);
                    // twowayfitness.replace_inner('diet-week', action.result.url);
                },
                failure: function(form, action) {
                    twowayfitness.handle_form_submission_failure(form, action);
                }
            }
        );
        
    }
    
});


twowayfitness.ForgotPasswordDialog = Ext.extend(twowayfitness.RestDialog, {
    initComponent: function() {
        var self = this;

        var fc = new twowayfitness.FieldCreator({
            data: this.data,
            object_name: 'password_change_request'
        });
         
        this.addressField = fc.text_field('email_address', 'Email', {
        });
         
        Ext.applyIf(this, {
             width: 500,
             title: 'Forgot Password',
             // help_key: 'change_email_address',
             REST_key: 'password_change_requests',
             object_name: 'password_change_request',
             save_button_text: 'Submit',
             submit_progress_message: 'Submitting',
             // submit_progress_message: 'Logging in',
             modal: true,
             form_items: [
                 {
                     xtype: 'panel',
                     border: false,
                     width: 480,
                     html: '<p class="instructions">Enter your email address below and click on the submit button. We will then send an email to you. Please follow the instructions in that email in order to create a new password for yourself.<p>'
                 },
                this.addressField
             ]
         });
         
         this.addListener({
             'submitted': {
                 fn: function(dialog, result) {
                     twowayfitness.showMessage('<p class = "instructions">An email has been sent to you. Please follow the instructions in the email in order to reset your password.</p>');
                 }
             }
         });
         
         twowayfitness.ForgotPasswordDialog.superclass.initComponent.call(this);
    }
});

twowayfitness.show_forgot_password_dialog = function(form_authenticity_token) {
   var dialog = new twowayfitness.ForgotPasswordDialog({
       form_authenticity_token: form_authenticity_token
   });
   dialog.show();
};



var allowCollapse = function()
{
    return false;
//    return Ext.isIE;
//    return true;
};

var make_period_button = function(period, icon_name, toggle_function, button_group, config) {
    var ret = {};
    //var tooltip = "show data for " + period + " periods";
    Ext.apply(ret, config);
    Ext.applyIf(ret, {
        period_name: period,
        tooltip: period,
        icon: twowayfitness.app_config.icons[icon_name],
        //'/images/icon-' + period + '.png',
        scale: 'large',
        //text: period,
        enableToggle: true,
        toggleGroup: button_group,
        listeners: {
            'toggle': toggle_function
        }
    });
    return ret;
};

var make_historical_snapshots_panel = function(app_config, config) {
    var chart_panel_config = {
        border: false,
        aspect_ratio: 2.0,
        min_height: false
    };

    Ext.apply(chart_panel_config, config.chart_panel_config);

    Ext.log('chart_panel_config.should_log = ' + chart_panel_config.should_log);

    var snapshot_panel = new twowayfitness.AnyChartPanel(chart_panel_config);

    var on_snapshot_toggle = function(button, pressed) {
        if(pressed) {
            snapshot_panel.setUrl('/clients/' + app_config.client_id + '/periods/' + button.period_name + '/historical_snapshot_chart.xml');
        }
    };

    var make_snapshot_period_button = function(period, config) {
        return make_period_button(period, period, on_snapshot_toggle, 'visualisation_period_button_group', config);
    };

    var snapshot_period_buttons = [
        make_snapshot_period_button('weekly', {pressed: true } ),
        make_snapshot_period_button('monthly'),
        make_snapshot_period_button('quarterly'),
        make_snapshot_period_button('yearly')
    ];
    
    if(config) {
        if(config.starting_period) {
            snapshot_panel.setUrl('/clients/' + app_config.client_id + '/periods/' + config.starting_period + '/historical_snapshot_chart.xml');
        }
    }
    
    var base_config = {
        title: 'Historical Snapshot',
        layout: 'anchor',
        tbar: snapshot_period_buttons,
        setData: function(data) {
            snapshot_panel.setData(data);
        },
        items: snapshot_panel
    };
    
    Ext.apply(base_config, config);
    
    return new Ext.Panel(base_config);

};

var make_donuts_panel = function(app_config, config) {
    var chart_panel_config = {
        border: false
    };

    Ext.apply(chart_panel_config, config.chart_panel_config);

    var donuts_panel = new twowayfitness.AnyChartPanel(chart_panel_config);

    var make_url = function(period, orientation, display_labels) {
        return '/clients/' + app_config.client_id + '/periods/' + period + '/donut_dashboard.xml?orientation=' + orientation + '&display_labels=' + (display_labels ? 'yes' : 'no');
    };

    var orientation = 'vertical';
    var display_labels = false;
    if(config) {
        if(config.displayLabels) {
            display_labels = config.displayLabels;
        }
        if(config.orientation) {
            orientation = config.orientation;
        }
        if(config.starting_period) {
            var url
            donuts_panel.setUrl(make_url(config.starting_period, orientation, display_labels));
        }
    }

    var on_donuts_toggle = function(button, pressed) {
        if(pressed) {
            donuts_panel.setUrl(make_url(button.period_name, orientation, display_labels));
        }
    };

    var make_donuts_period_button = function(period, icon_name, config) {
        return make_period_button(period, icon_name, on_donuts_toggle, 'donut_period_button_group', config);
    };

    var donut_period_buttons = [
        make_donuts_period_button('weekly', 'days_7', {pressed: true, tooltip: 'last 7 days' }),
        make_donuts_period_button('monthly', 'days_30', { tooltip: 'last 30 days'}),
        make_donuts_period_button('quarterly', 'days_90', { tooltip: 'last 90 days'}),
        make_donuts_period_button('yearly', 'days_365', { tooltip: 'last 365 days'})
    ];


    var base_config = {
        title: 'Donuts',
        tbar: donut_period_buttons,
        setData: function(data) {
            donuts_panel.setData(data);
        },
        items: donuts_panel
    };

    Ext.apply(base_config, config);

    return new Ext.Panel(base_config);
};

twowayfitness.HomePanel = Ext.extend(Ext.Panel, {
    panel_name: 'Home',
    make_quotes_panel: function() {
        this.quotes_panel = new Ext.Panel({
            collapsible: allowCollapse(),
            frame: true,
            style: 'margin-bottom: 7px',
            title: 'Quote of the Day'
        });

        if(this.data) {
            this.quotes_panel.html = this.data.quote_html;
        }
        
        return this.quotes_panel;
    },
    make_selected_charts_panel: function() {
        this.chart_panel1 = new twowayfitness.AnyChartPanel({
            size_determined_by: 'width',
            anchor: '100%',
            should_log: true
        });

        this.chart_panel1.on('bodyresize', function(p, w, h) {
           Ext.log('chart_panel1 bodyresize ' + w + ' by ' + h);
        });

        this.chart_panel2 = new twowayfitness.AnyChartPanel({
            size_determined_by: 'width',
            anchor: '100%'
        });

        this.chart_panels = [ this.chart_panel1, this.chart_panel2 ];

        this.selected_charts_panel = new Ext.Panel({
            layout: 'anchor',
            title: 'Selected Charts',
            frame: true,
            collapsible: allowCollapse(),
            autoHeight: true,
            border: false,
            anchor: '100%',
            items: [
                this.chart_panel1,
                this.chart_panel2
            ]
        });

        this.selected_charts_panel.on('bodyresize', function(p, w, h) {
           Ext.log('selected_charts_panel bodyresize ' + w + ' by ' + h);
        });

        if(this.data) {
            this.chart_panel1.setData(this.data.chart1_xml);
            this.chart_panel2.setData(this.data.chart2_xml);
        }

        return this.selected_charts_panel;
    },
    switch_to_2_columns: function() {
      if(this.using_3_columns) {
         this.using_3_columns = false;

          this.east_panel.removeAll(true);
          this.center_panel.add(this.make_selected_charts_panel());
          this.west_panel.insert(
                  1,
                  this.make_quotes_panel()
              );
          this.east_panel.hide();
         this.doLayout();
      }
    },
    switch_to_3_columns: function() {
        if(!this.using_3_columns) {
           this.using_3_columns = true;
           this.west_panel.remove(this.quotes_panel, true);
           this.center_panel.remove(this.selected_charts_panel, true);
           this.east_panel.show();
           this.east_panel.add(this.make_quotes_panel());
           this.east_panel.add(this.make_selected_charts_panel());
           this.doLayout();
        }
    },
    initComponent: function() {
        Ext.log('inside HomePanel::initComponent');

        var self = this;
        
        self.chart_panels = [];

        this.visualisation_panel = make_historical_snapshots_panel(self.app_config, {
            chart_panel_config: {
                size_determined_by: 'width',
                anchor: '100%'
            },
            collapsible: allowCollapse(),
            autoHeight: true,
            anchor: '100%',
            style: 'margin-bottom: 7px'
        });

        this.donuts_panel_holder = make_donuts_panel(self.app_config, {
            chart_panel_config: {
                size_determined_by: 'width',
                anchor: '100%',
                aspect_ratio: 0.5,
                min_height: false
            },
            layout: 'anchor',
            anchor: '100%',
            flex: 1.0,
            autoHeight: true,
            collapsible: allowCollapse(),
            margins: {top:0, right:7, bottom:0, left:0}
        });

        this.ep_gauges_panel = new twowayfitness.EpGaugesPanel({
            title: 'Exercise Points',
            collapsible: allowCollapse(),
            size_determined_by: 'width',
            frame: true,
            flex: 1.0,
            style: 'margin-bottom: 7px',
            client_id: this.client_id
        });

        this.make_quotes_panel();
        
        // var gadget_panel = new Ext.Panel({
        //     layout: 'fit',
        //     collapsible: true,
        //     frame: true,
        //     title: 'Weather',
        //     style: 'margin-bottom: 7px',
        //     height: 360,
        //     items: {
        //         autoScroll : true,
        //         autoShow:true,
        //         xtype:'iframepanel',
        //         fitToParent: true,
        //         loadMask:{hideOnReady :false,msg:'Loading ...'},
        //         defaultSrc: '/public/google_gadget'
        //     }
        // });
        // 
        // var simpsons_panel = new Ext.Panel({
        //     layout: 'fit',
        //     // collapsible: true,
        //     // frame: true,
        //     // title: 'Homer Simpson',
        //     border: false,
        //     style: 'margin-bottom: 7px',
        //     height: 270,
        //     items: {
        //         autoScroll : true,
        //         autoShow:true,
        //         xtype:'iframepanel',
        //         fitToParent: true,
        //         loadMask:{hideOnReady :false,msg:'Loading ...'},
        //         defaultSrc: '/public/simpson_gadget'
        //     }
        // });
        // 
        var profile_panel = new Ext.Panel({
//            title: 'News',
            collapsible: allowCollapse(),
            bodyBorder: false,
            frame: true,
            style: 'margin-bottom: 7px',
            html: 'Fetching Details ...'
        });
        
        var todos_panel = new Ext.Panel({
            title: 'To Do',
            collapsible: allowCollapse(),
            frame: true,
            style: 'margin-bottom: 7px',
            html: 'Fetching ...'
        });

        var news_panel = new Ext.Panel({
            title: 'News',
            collapsible: allowCollapse(),
            bodyBorder: false,
            frame: true,
            style: 'margin-bottom: 7px',
            html: 'Fetching News ...'
        });

        var forum_topics_panel = new Ext.Panel({
            title: 'Recent Forum Topics',
            collapsible: allowCollapse(),
            frame: true,
            style: 'margin-bottom: 7px',
            html: 'Fetching Topics ...'
        });
        
//        var html = '';
//        for(var i=0; i<100; i++) {
//            html = html + ("<p>hello " + i + "</p");
//        }


        this.make_selected_charts_panel();

        var donuts_and_eps_panel = new Ext.Panel({
            layout: 'hbox',
            autoHeight: true,
            border: false,
            align : 'stretchmax',
            anchor: '100%',
//            margins: {top:0, right:7, bottom:50, left:0},
            style: {
                marginBottom: '7px'
            },
            items: [
                this.donuts_panel_holder,
                this.ep_gauges_panel
            ]
        });

//        donuts_and_eps_panel.on('bodyresize', function(p, w, h) {
//           Ext.log('donuts_and_eps_panel bodyresize ' + w + ' by ' + h);
//           Ext.log('donuts_and_eps_panel bodyresize height is now ' + p.getHeight());
//        });


        var scrollable_panel_min_width = 700;
        var min_width_for_3_columns = 1050;

        this.west_panel = new Ext.Panel({
            autoHeight: true,
            width: 270,
            flex: 1.0,
            border: false,
            items: [
                profile_panel,
                todos_panel,
                // simpsons_panel,
                // gadget_panel,
                news_panel,
                forum_topics_panel
            ]
        });
        
        this.center_panel = new Ext.Panel({
            layout: 'anchor',
            autoHeight: true,
            flex: 2.0,
            border: false,
            items: [
//                { html: 'HELLO' }
                this.visualisation_panel,
                donuts_and_eps_panel
            ]
        });

//        this.center_panel.addListener(
//            'bodyresize',
//            function(panel, width, height) {
//               Ext.log('center_panel resize width = ' + width + ' height = ' + height);
//               if(panel.rendered) {
//                 Ext.log('calling center_panel.doLayout()');
//                 panel.doLayout();
//               }
//            },
//            this
//        );


        this.east_panel = new Ext.Panel({
             // columnWidth: 170,
             // width: 200,
             border: false,
             layout: 'anchor',
//             anchor: '100%',
             autoHeight: true,
             flex: 2.0,
             items: [
                this.quotes_panel,
                this.selected_charts_panel
             ]
        });
        
        this.scrollable_panel = new Ext.Panel({
            width: scrollable_panel_min_width,
            border: false,
            defaults: {
                style: 'padding: 7px'
            },
            cls: 'slate-panel',
            layout: 'hbox',
            autoHeight: true,
            items: [
                this.west_panel,
                this.center_panel,
                this.east_panel
            ]
        });

        Ext.applyIf(this, {
            using_3_columns: true,
            border: false,
            autoScroll: true,
            items: [
                this.scrollable_panel
            ]
        });

        this.addListener(
            'bodyresize',
            function(panel, width, height) {
               Ext.log('Home Panel resize width = ' + width);

                var scrollable_panel = self.scrollable_panel;
                if(scrollable_panel.rendered) {
                    var scrollable_width = self.scrollable_panel.getSize().width;
                    Ext.log('   home panel resize width = ' + width + " scrollable width = " + scrollable_width);
                    
                    // the 20 below is unfortunate. How to do better?
                    var new_width = width - 20;
                    if(new_width < scrollable_panel_min_width) {
                        new_width = scrollable_panel_min_width;
                    } else {
                        // this handles the case where the outer panel is bigger than scrollable_panel_min_width
                        // in which case we want the scrollable_panel to fill the available space.
                    }
                    scrollable_panel.setWidth(new_width);
                    Ext.log("    new scrollable width = " + new_width);
                } else {
                    var new_width = Math.max(width - 20, scrollable_panel_min_width);
                    Ext.log('    scrollable NOT RENDERED home panel resize width = ' + width + " new scrollable width = " + new_width);
                    scrollable_panel.setWidth(new_width);
                }
                if(width < min_width_for_3_columns) {
                    self.switch_to_2_columns();
                } else {
                    self.switch_to_3_columns();
                }

                Ext.log('calling doLayout()');
                this.doLayout();
            },
            this
        );

        this.addListener(
            'afterlayout',
            function(container, layout) {
                Ext.log('Home Panel after layout');
                if(!this.inside_2nd_do_layout) {
                    this.inside_2nd_do_layout = true;
                    Ext.log('    calling doLayout again');
                    this.doLayout();
                }
                this.inside_2nd_do_layout = false;
            },
            this
        );
        
        twowayfitness.HomePanel.superclass.initComponent.call(this);
        
        Ext.Ajax.request({
            url: '/client/home_page_info',
            method: 'GET',
            params: {
                // 'as_array': 1
            },
            success : function(response, options) {
                var data = Ext.util.JSON.decode(response.responseText);
                self.data = data;
                profile_panel.body.update(data.profile_html);
                self.quotes_panel.body.update(data.quote_html);
                
                todos_panel.body.update(data.todos_html);
                news_panel.body.update(data.news_html);
                forum_topics_panel.body.update(data.forum_topics_html);

                self.visualisation_panel.setData(data.snapshot_chart_xml);
                self.donuts_panel_holder.setData(data.donuts_dashboard_xml);
                
                self.chart_panel1.setData(data.chart1_xml);
                self.chart_panel2.setData(data.chart2_xml);
                self.doLayout();
            },
            failure: function(response, options) {
                alert('failure');
            }
        });
        Ext.log('leaving HomePanel::initComponent');

    }
});


twowayfitness.ChartsTreePanel = Ext.extend(Ext.tree.TreePanel, {
    initComponent: function() {
        var self = this;
        
        // rootVisible seems to be set to true before we get to here, so we can't use applyIf to set it.
        this.rootVisible = false;
        
        Ext.applyIf(this, {
            width: 350,
            region: 'west',
            rootVisible: false,
            autoScroll: true,
            border: true,
            split: true,
            // collapsible: true,
            title: 'Series',
            loader: new Ext.tree.TreeLoader({
                dataUrl: self.dataUrl,
                requestMethod: 'GET'
            }),
            root: {
                nodeType: 'async',
                draggable: false,
                id: 'source'
            }
            // ,
            // listeners: {
            //     'click' : {
            //         fn: function(node, e) {
            //             self.current_node = node;
            //             self.display_chart();
            //         }
            //     }
            // }
        });
        
        twowayfitness.ChartsTreePanel.superclass.initComponent.call(this);
    }
});

make_charts_tree_panel = function(options) {
    var ret = new Ext.tree.TreePanel({
        width: 350,
        rootVisible: false,
        autoScroll: true,
        border: true,
        title: 'Series',
        loader: new Ext.tree.TreeLoader({
            dataUrl: self.dataUrl,
            requestMethod: 'GET'
        }),
        root: {
            nodeType: 'async',
            draggable: false,
            id: 'source'
        }
    });
    
    Ext.apply(ret, options);
    
    return ret;
};

twowayfitness.makeChartsPanel = function(app_config) {
    var self = null;
    
    var chart_settings = app_config.chart_settings;
    
    // : {"period":"monthly","timespan":{"end":"2-weeks-away","beginning":"3-months"},"animated":true,"three_d":false},

    Ext.log('100');

   var settings = {};
   
    settings.chart_panel = new twowayfitness.AnyChartPanel({
        should_log: true,
        waitingForDataText: 'Select a chart for display from the list on the left',
        style: 'padding: 6px',
        min_aspect_ratio: 1.6,
        border: true,
        max_aspect_ratio: 2,
        // autoWidth: true,
        flex: 1,
        min_height: 400,
        anchor: '100%'
    });

    var today = new Date();
    var one_week_ago = new Date();
    one_week_ago.setDate(one_week_ago.getDate()-7);

    var six_months_ago = today.add(Date.MONTH, -6);

    settings.threeDField = new Ext.form.Checkbox({
        name: '3D',
        fieldLabel: '3D',
        listeners: {
            'check': function(field, checked) {
                self.chart_settings.three_d = checked;
                self.display_chart();
            }
        },
        checked: chart_settings.three_d
    });

    settings.animationField = new Ext.form.Checkbox({
        name: 'animated',
        fieldLabel: 'Animated',
        checked: chart_settings.animated,
        listeners: {
            'check': function(field, checked) {
                self.chart_settings.animated = checked;
                self.display_chart();
            }
        }
    });
//    settings.animationField.setValue(true);

    settings.startDateField = new Ext.form.DateField({
        name: 'start-date',
        disabled: !chart_settings.timespan.beginning.date.enabled,
        hideLabel: true,
        format: 'M j, Y',
        allowBlank: false,
        value: chart_settings.timespan.beginning.date.value,
        readOnly: true,
        width: 110,
        listeners: {
            'select': function(field, date) {
                self.display_chart();
            }
        }
    });
    Ext.log('200');

    settings.endDateField = new Ext.form.DateField({
        name: 'end-date',
        hideLabel: true,
        disabled: !chart_settings.timespan.end.date.enabled,
        format: 'M j, Y',
        allowBlank: false,
        value: chart_settings.timespan.end.date.value,
        readOnly: true,
        width: 110,
        listeners: {
            'select': function(field, date) {
                self.display_chart();
            }
        }
    });
    Ext.log('210');

    var begTsValue = chart_settings.timespan.beginning.period.value;
    settings.beginningTimespanPeriodCombo = new Ext.form.ComboBox({
        hideLabel: true,
        //fieldLabel: '',
        typeAhead: true,
        triggerAction: 'all',
        lazyRender:true,
        //autoWidth: true,
        width: 150,
        listWidth: 150,
        mode: 'local',
        store: new Ext.data.ArrayStore({
            id: 0,
            fields: [
                'span',
                'displayText'
            ],
            data: [
                ['week', '1 week before end'],
                ['fortnight', '2 weeks before end'],
                ['month', '1 month before end'],
                ['2-months', '2 months before end'],
                ['3-months', '3 months before end'],
                ['6-months', '6 months before end'],
                ['year', '1 year before end'],
                ['2years', '2 years before end'],
                ['3years', '3 years before end'],
                ['4years', '4 years before end'],
                ['5years', '5 years before end']
            ]
        }),
        value: begTsValue,
        hiddenValue: begTsValue,
        valueField: 'span',
        hiddenName: 'hidden-value',
        displayField: 'displayText',
        listeners: {
            'select': function() {
                self.display_chart();
            }
        }
   });

    Ext.log('220');

    var endTsValue = chart_settings.timespan.end.period.value;
    settings.endCombo = new Ext.form.ComboBox({
        hideLabel: true,
        typeAhead: true,
        triggerAction: 'all',
        lazyRender:true,
        width: 150,
        listWidth: 150,
        mode: 'local',
        store: new Ext.data.ArrayStore({
            id: 0,
            fields: [
                'val',
                'displayText'
            ],
            data: [
                ['year', '1 year ago'],
                ['6-months', '6 months ago'],
                ['3-months', '3 months ago'],
                ['2-months', '2 months ago'],
                ['month', '1 month ago'],
                ['fortnight', '2 weeks ago'],
                ['week', '1 week ago'],
                ['today', 'Today'],
               ['1-week-away', '1 week from today'],
               ['2-weeks-away', '2 weeks from today'],
               ['1-month-away', '1 month from today'],
               ['2-months-away', '2 months from today'],
               ['3-months-away', '3 months from today'],
               ['6-months-away', '6 months from today'],
               ['1-year-away', '1 year from today']
            ]
        }),
        value: endTsValue,
        hiddenValue: endTsValue,
        valueField: 'val',
        hiddenName: 'hidden-value',
        displayField: 'displayText',
        listeners: {
            'select': function() {
                self.display_chart();
            }
        }
   });

    Ext.log('240');
    //this.chooseSpecificStartDateField = new Ext.form.Checkbox({
    //    labelWidth: 200,
    //    fieldLabel: '... or choose specific date',
    //    listeners: {
    //        'check': function(field, checked) {
    //            if(checked) {
    //                self.timespanPeriodCombo.disable();
    //                self.startDateField.enable();
    //            } else {
    //                self.timespanPeriodCombo.enable();
    //                self.startDateField.disable();
    //            }
    //            self.display_chart();
    //        }
    //    }
    //});
    //this.chooseSpecificStartDateField.setValue(false);

    settings.beginningUseComboCheckbox = new Ext.form.Radio({
        hideLabel: true,
        checked: chart_settings.timespan.beginning.period.enabled,
        name: 'beginning-radio',
        style: 'margin-right: 10px',
        listeners: {
            'check': function(field, checked) {
                if(checked) {
                    self.startDateField.disable();
                    self.beginningTimespanPeriodCombo.enable();
                    self.display_chart();
                }
            }
        }
    });
//    settings.beginningUseComboCheckbox.setValue(true);
    Ext.log('250');

    settings.beginningUseSpecificDateCheckbox = new Ext.form.Radio({
        hideLabel: true,
        style: 'margin-right: 10px',
        name: 'beginning-radio',
        checked: chart_settings.timespan.beginning.date.enabled,
        listeners: {
            'check': function(field, checked) {
                if(checked) {
                    self.startDateField.enable();
                    self.beginningTimespanPeriodCombo.disable();
                    self.display_chart();
                }
            }
        }
    });
//    settings.beginningUseSpecificDateCheckbox.setValue(false);
    Ext.log('360');

    settings.startRangeField = new Ext.form.FieldSet({
        labelWidth: 50,
        width: 220,
        autoHeight: true,
        title: 'Beginning',
        bodyStyle: 'padding: 10px',
        checked: chart_settings.timespan.beginning.period.enabled,
        items: [
            {
                xtype: 'panel',
                border: false,
                layout: 'hbox',
                items: [
                    settings.beginningUseComboCheckbox,
                    settings.beginningTimespanPeriodCombo
                ]
            },
            {
                xtype: 'panel',
                border: false,
                style: 'margin-top: 10px',
                layout: 'hbox',
                items: [
                    settings.beginningUseSpecificDateCheckbox,
                    settings.startDateField
                ]
            }
        ]
    });

    Ext.log('380');

    settings.endUseComboCheckbox = new Ext.form.Radio({
        hideLabel: true,
        name: 'end-radio',
        style: 'margin-right: 10px',
        checked: chart_settings.timespan.end.period.enabled,
        listeners: {
            'check': function(field, checked) {
                if(checked) {
                    self.endDateField.disable();
                    self.endCombo.enable();
                    self.display_chart();
                }
            }
        }
    });
//    settings.endUseComboCheckbox.setValue(true);

    Ext.log('400');

    settings.endUseSpecificDateCheckbox = new Ext.form.Radio({
        hideLabel: true,
        style: 'margin-right: 10px',
        name: 'end-radio',
        checked: chart_settings.timespan.end.date.enabled,
        listeners: {
            'check': function(field, checked) {
                if(checked) {
                    self.endDateField.enable();
                    self.endCombo.disable();
                    self.display_chart();
                }
            }
        }
    });
//    settings.endUseSpecificDateCheckbox.setValue(false);
    Ext.log('500');

    settings.endRangeField = new Ext.form.FieldSet({
        labelWidth: 40,
        title: 'End',
        autoHeight: true,
        style: 'margin-left: 10px',
        bodyStyle: 'padding: 10px',
        //autoWidth: true,
        width: 220,
        items: [
            {
                xtype: 'panel',
                border: false,
                layout: 'hbox',
                items: [
                    settings.endUseComboCheckbox,
                    settings.endCombo
                ]
            },
            {
                xtype: 'panel',
                border: false,
                style: 'margin-top: 10px',
                layout: 'hbox',
                items: [
                    settings.endUseSpecificDateCheckbox,
                    settings.endDateField
                ]
            }
        ]
    });
    
    settings.timespanField = new Ext.form.FieldSet({
        title: 'Time Span',
        style: "margin-left: 10px",
        labelWidth: 30,
        width: 490,
        layout: 'column',
        autoHeight: true,
        checkboxToggle: true,
        collapsed: !chart_settings.timespan.enabled,
        // autoWidth: true,
        items: [
            settings.startRangeField,
            settings.endRangeField
        ],
        listeners: {
            'collapse': function() {
                self.display_chart();
            },
            'expand': function() {
                self.display_chart();
            }
        }
    });

    var periodRadioConfig = function(period) {
        return {
            boxLabel: period,
            name: 'rb-auto',
            checked: chart_settings.period == period,
            id: 'period_' + period,
            inputValue: period,
            listeners: {
                'check': {
                    fn: function(radio, checked ) {
                        if(checked) {
                            self.current_period = radio.inputValue;
                            self.display_chart();
                        }
                    }
                }
            }
        };
    };

    settings.settings_panel = new Ext.FormPanel({
        frame: true,
        title: 'Chart Settings',
        region: 'north',
        layout: 'column',
        collapsible: true,
        style: 'padding: 6px',
        labelWidth: 60,
        // width: '100%',
        border: false,
        // autoWidth: true,
        autoHeight: true,
        min_width: 760,
        plugins: twowayfitness.micksPlugin,
        // width: 800,
        //autoScroll: true,
        //height: settings_panel_height,
        defaults: {
            //style: 'padding: 5px',
            bodyStyle: "padding: 10px"
        },
        items: [
            {
                title: 'Appearance',
                xtype:'fieldset',
                autoHeight: true,
                autoWidth: true,
                items: [
//                    settings.threeDField,
                    settings.animationField
                ]
            },
            settings.timespanField,
            {
                title: 'Period',
                id: 'period-field',
                xtype:'fieldset',
                style: "margin-left: 10px",
                autoHeight: true,
                hidden: true,
                width: 120,
                items: [
                    {
                        border: false,
                        xtype: 'radiogroup',
                        id: 'period-radio-group',
                        hideLabel: true,
                        columns: 1,
                        items: [
                            periodRadioConfig('weekly'),
                            periodRadioConfig('monthly'),
                            periodRadioConfig('quarterly'),
                            periodRadioConfig('yearly')
                        ]
                    }
                ]
            }
        ]

    });

    settings.center_panel = new Ext.Panel({
        region: 'center',
        layout: 'anchor',
        frame: true,
        border: true,
        autoScroll: true,
        // layout: 'vbox',
        items: [
            //self.instructions_panel,
            settings.settings_panel,
            settings.chart_panel
        ],
        listeners: {
            'bodyresize' : {
                fn: function(p, width, height) {
                    Ext.log('center_panel::bodyresize');
                    if(self) {
                        self.resizeChart();
                    }
                }
            }
        }
    });

    // console.log('center_panel.autoScroll = ' + this.center_panel.autoScroll);

//    settings.center_panel.on('bodyresize',
//    );

    // this.settings_panel.on('resize',
    //     function(p) {
    //         self.resizeChart();
    //     }
    // );
    settings.settings_panel.on('collapse',
        function(p) {
            self.resizeChart();
        }
    );
    settings.settings_panel.on('expand',
        function(p) {
            self.resizeChart();
        }
    );

    var tree = new twowayfitness.ChartsTreePanel({
        title: 'Select Chart ...',
        collapsible: true,
        dataUrl: '/charts',
        listeners: {
            'click' : {
                fn: function(node, e) {
                    self.current_node = node;
                    self.display_chart();
                }
            }
        }
    });

    Ext.log('micks_init calling apply');

//    settings.center_panel = {
//        region: 'center',
//        html: 'center'
//    };

//    tree = {
//        region: 'west',
//        html: 'tree'
//    };

//        items: [
//            {
//                html: 'THIS IS IT #2'
//            }
//        ]
    // console.log('ChartsPanel autoScroll = ' + this.autoScroll);

    Ext.applyIf(settings, {
        app_config: app_config,
        chart_settings: app_config.chart_settings,
        border: false,
        current_period: app_config.chart_settings.period,
        autoScroll: false,
        layout: 'border',
        title: 'Charts',
        help_key: 'charts',
        tools: [
            {
                id: 'help',
                handler: function(event, toolEl, panel) {
                        twowayfitness.displayHelp(self.help_key);
                    }
            }
        ],
        items: [
            tree,
            settings.center_panel
        ],
        save_chart_settings: function()
        {
            this.chart_settings.animated = this.animationField.getValue();
            this.chart_settings.three_d = this.threeDField.getValue();
            this.chart_settings.period = this.current_period;

            this.chart_settings.timespan = {
                enabled: !this.timespanField.collapsed,
                beginning: {
                    period: {
                        enabled: this.beginningUseComboCheckbox.getValue(),
                        value: this.beginningTimespanPeriodCombo.getValue()
                    },
                    date: {
                        enabled: this.beginningUseSpecificDateCheckbox.getValue(),
                        value: this.startDateField.getValue()
                        // start_date.format('Y-m-d');
                    }
                },
                end: {
                    period: {
                        enabled: this.endUseComboCheckbox.getValue(),
                        value: this.endCombo.getValue()
                    },
                    date: {
                        enabled: this.endUseSpecificDateCheckbox.getValue(),
                        value: this.endDateField.getValue()
                    }
                }
            };
        },
        encode_parameter: function(name, value)
        {
            return '&' + name + '=' + value;
        },
        encode_bool_parameter: function(name, value)
        {
            return this.encode_parameter(name, (value ? 'yes' : 'no'));
        },
        display_chart: function() {
            this.save_chart_settings();
            var chart_settings = this.chart_settings;
            var node = this.current_node;
            if(node) {
                var attributes = node.attributes;
                var period_field = this.findById('period-field');
                var url;
                var enable_period_radios = false;
                var enable_3d = attributes.allow_3d;
                
                if(attributes.chart_url) {
                    url = attributes.chart_url;
                }
                else if(attributes.periodic_series_name) {
                    url = '/time_series/' + attributes.periodic_series_name + '/periods/' + chart_settings.period + '/chart'
                    enable_period_radios = true;
                }

                if(attributes.prefer_square) {
                    Ext.apply(this.chart_panel, {
                        min_aspect_ratio: 0.9,
                        max_aspect_ratio: 1.1,
                        min_height: 350,
                        min_width: undefined
                    });
                } else {
                    Ext.apply(this.chart_panel, {
                        min_aspect_ratio: 1.6,
                        max_aspect_ratio: 2.6,
                        min_height: 350,
                        min_width: undefined
                    });
                }

                if(enable_3d) {
                    this.threeDField.enable();
                } else {
                    this.threeDField.disable();
                }

                if(enable_period_radios) {
                    period_field.show();
                } else {
                    period_field.hide();
                }

                url += '?save_settings=yes';
                url += this.encode_bool_parameter('3d', chart_settings.three_d);
                url += this.encode_bool_parameter('animated', chart_settings.animated);
                url += this.encode_parameter('period', chart_settings.period);
                var start_date = end_date = undefined;

                url += this.encode_bool_parameter('ts_enabled', chart_settings.timespan.enabled);

                url += this.encode_bool_parameter('ts_beg_period_enabled', chart_settings.timespan.beginning.period.enabled);
                url += this.encode_parameter('ts_beg_period_value', chart_settings.timespan.beginning.period.value);
                url += this.encode_bool_parameter('ts_beg_date_enabled', chart_settings.timespan.beginning.date.enabled);
                url += this.encode_parameter('ts_beg_date_value', chart_settings.timespan.beginning.date.value.format('Y-m-d'));

                url += this.encode_bool_parameter('ts_end_period_enabled', chart_settings.timespan.end.period.enabled);
                url += this.encode_parameter('ts_end_period_value', chart_settings.timespan.end.period.value);
                url += this.encode_bool_parameter('ts_end_date_enabled', chart_settings.timespan.end.date.enabled);
                url += this.encode_parameter('ts_end_date_value', chart_settings.timespan.end.date.value.format('Y-m-d'));

//                if(this.beginningUseSpecificDateCheckbox.getValue()) {
//                    start_date = this.startDateField.getValue();
//                    url += '&start_date=' + start_date.format('Y-m-d');
//                } else {
//                    url += '&length=' + this.beginningTimespanPeriodCombo.getValue();
//                }
//                if(this.endUseSpecificDateCheckbox.getValue()) {
//                    end_date = this.endDateField.getValue();
//                    url += '&end_date=' + end_date.format('Y-m-d');
//                } else {
//                    url += '&end=' + this.endCombo.getValue();
//                }

                // if(end_date && start_date && end_date < start_date) {
                //     twowayfitness.showMessage("<p class='instructions'>End date is before start date.</p>");
                // } else {
                //this.center_panel.doLayout();
                this.resizeChart();
                this.chart_panel.setUrl(url);
                // this.settings_panel.doLayout();
                // }
            }
        },
        resizeChart: function() {
            Ext.log('resizeChart rendered = ' + this.rendered);
            if(this.rendered && this.settings_panel.rendered)
            {
    //            Ext.log('resizeChart settings_panel rendered = ' + this.settings_panel.rendered);
                var size = this.center_panel.getSize();
                Ext.log('resizeChart 100');
                var orig_width = size.width;
                var orig_height = size.height;
                var new_width = orig_width - 12;
                Ext.log('resizeChart 150');
                var settings_panel_height = this.settings_panel.getSize().height;
                var new_height = orig_height - settings_panel_height - 30;

                Ext.log('resizeChart 200');
                this.settings_panel.setWidth(orig_width - 30);

                //console.log('resizeChart orig_width = ' + orig_width + ' orig_height = ' + orig_height + ' new_width = ' + new_width + ' new_height = ' + new_height);
                this.chart_panel.setSize(new_width, new_height);

                Ext.log('resizeChart 300');

    //            this.chart_panel.adjust_for_aspect_ratio();
                this.chart_panel.adjust_size();
                Ext.log('resizeChart 350');
                this.center_panel.doLayout();
                Ext.log('resizeChart 400');
            }
        }
    });

    var ret = new Ext.Panel(settings);
    self = ret;
    return ret;
};



twowayfitness.ForumsPanel = Ext.extend(Ext.Panel, {
    initComponent: function() {
        Ext.applyIf(this, {
            border: false,
            // autoScroll: true,
            layout: 'fit',
            items: {
                autoScroll : true,
                autoShow:true,
                xtype:'iframepanel',
                fitToParent: true,
                loadMask:{hideOnReady :false,msg:'Loading ...'},
                defaultSrc: '/forums'
            }
        });
        
        twowayfitness.ForumsPanel.superclass.initComponent.call(this);
    }
});


twowayfitness.MeasurementsPanel = Ext.extend(twowayfitness.GridWithShowPanel, {
    constructor: function(config) {
        // Your preprocessing here
        twowayfitness.MeasurementsPanel.superclass.constructor.apply(this, [ config ]);
        // Your postprocessing here
    },
    editable_and_deletable: function(data) {
       return true;
    },
    displayMetric: function(data) {
        var self = this;
        self.data = data;
        var metric_id = data.id;

        this.metric_id = metric_id;
        this.new_button.enable();
        
        this.measurements_url = '/metrics/' + metric_id + '/measurements';
        
        var datastore = new Ext.data.Store({
            reader: new Ext.data.JsonReader
                    (
                        {
                            root: 'measurements',
                            id: 'uri',
                            totalProperty: 'count'
                        },
                        [
                            // {name: 'id', mapping: 'id'},
                            // {name: 'metric_id', mapping: 'metric_id'},
                            {name: 'uri', mapping: 'uri'},
                            {name: 'date', mapping: 'date', type:'date'},
                            {name: 'duration_hrs', mapping: 'duration_hrs'},
                            {name: 'duration_min', mapping: 'duration_min'},
                            {name: 'duration_sec', mapping: 'duration_sec'},
                            // {name: 'display_value', mapping: 'display_value'},
                            {name: 'value', mapping: 'value'}
                        ]
                    ),
            proxy: new Ext.data.MemoryProxy(),
            data: self.data.measurements,
            autoDestroy: true
        });
        
        datastore.load();
        this.setDatastore(datastore);
        
        self.progress_dialog.hideProgress();
        self.progress_dialog = twowayfitness.null_progress_dialog;
    },
    
    // override initComponent
    initComponent: function() {
        var self = this;
        
        var column_model = new Ext.grid.ColumnModel([
            {
              header:"date",
              dataIndex: 'date',
              sortable: true,
              renderer: Ext.util.Format.dateRenderer("M d, Y")
            },
            {
                header:"value",
                sortable: true,
                dataIndex: 'value'
            }
        ]);

        Ext.applyIf(this, {
            on_new: function() {
                var dialog = new twowayfitness.MeasurementDialog({
                    isDuration: self.data.units == 'time',
                    manualProgressDismiss: true,
                    title: 'Add measurement',
                    REST_uri: self.measurements_url,
                    dataSaved: function() {
                        self.benchmark_display_panel.updateMetric(dialog);
                    },
                    form_authenticity_token: self.form_authenticity_token
                });
                this.progress_dialog = dialog;
                dialog.on('show', function(comp) {
                    // Fix for IE: for some reason (an ext bug I think), the duration field does not show unless I do the following.
                   comp.doLayout();
                });
                dialog.show();
            },
            after_delete: function() {
                this.progress_dialog = self;
                self.benchmark_display_panel.updateMetric(self);
            },
            on_edit: function(selected) {
                var dialog = new twowayfitness.MeasurementDialog({
                    isDuration: self.data.units == 'time',
                    manualProgressDismiss: true,
                    title: 'Edit measurement',
                    REST_uri: selected.data.uri,
                    data: selected.data,
                    dataSaved: function() {
                        self.benchmark_display_panel.updateMetric(dialog);
                    },
                    form_authenticity_token: self.form_authenticity_token
                });
                this.progress_dialog = dialog;
                dialog.on('show', function(comp) {
                   // Fix for IE: for some reason (an ext bug I think), the duration field does not show unless I do the following.
                   comp.doLayout();
                });
                dialog.show();
            },
            datastore: new Ext.data.Store(),
            column_model: column_model,
            border: false,
            manualProgressDismiss: true,
            display_show_panel: false,
            width: 220,
            listPanelConfig: {
                title: 'Measurements',
                frame: true,
                region: 'west',
                width: 220,
                split: false
            },
            progress_dialog: twowayfitness.null_progress_dialog,
            display_toolbar: true,
            object_name: 'measurement',
            collection_path: 'measurements'
        });
        // call the superclass's initComponent implementation       
        twowayfitness.MeasurementsPanel.superclass.initComponent.call(this);
    }
    
});

twowayfitness.BenchmarkDisplayPanel = Ext.extend(Ext.Panel, {
    constructor: function(config) {
        // Your preprocessing here
        twowayfitness.BenchmarkDisplayPanel.superclass.constructor.apply(this, [ config ]);
        // Your postprocessing here
    },
    updateMetric: function(dialog) {
//        this.display_metric(this.metric_id);
        dialog.startProgress();
        this.findParentByType(twowayfitness.BenchmarksPanel).reload_benchmarks_list(dialog, this.metric_id);
    },
    display_metric: function(metric_id) {
        var self = this;
        self.metric_id = metric_id;
        self.show();

//        alert('display_metric metric_id = ' + metric_id);
        Ext.Ajax.request({
           url: '/metrics/' + metric_id,
           method: 'GET',
           params: { 'format':'ext_json' },
           success : function (response, options) {
               var data = Ext.util.JSON.decode(response.responseText);
               self.description_panel.body.update(data.summary_html);
               self.measurements_panel.displayMetric(data);
               self.chart_panel.setData(data.chart_xml);
               self.doLayout();
           },
           failure : function (response, options) {
               alert("Failed to fetch information about benchmark from server. Please try again later.");
           }
        });
    },
    setData: function(data) {
        this.display_metric(data.id);
    },
    // override initComponent
    initComponent: function() {
        var self = this;
        self.description_panel = new Ext.Panel({
            autoHeight: true,
            region: 'north',
            border: false
        });
        
        self.measurements_panel = new twowayfitness.MeasurementsPanel({
            region: 'west',
            form_authenticity_token: this.form_authenticity_token,
            benchmark_display_panel: self
        });

        self.chart_panel = new twowayfitness.AnyChartPanel({
            min_aspect_ratio: 1.5,
            max_aspect_ratio: 3.0,
            aspect_ratio: false,

            border: false,
            should_log: true,
            anchor: '100%',
            form_authenticity_token: this.form_authenticity_token
        });

        Ext.applyIf(this, {
            layout: 'border',
            plugins: twowayfitness.micksPlugin,
            min_width: 650,
            min_height: 500,
            items: [
                self.description_panel,
                self.measurements_panel,
                {
                    layout: 'fit',
                    region: 'center',
                    border: false,
                    items:  self.chart_panel
                }
            ],
            border: false
        });
        
        // call the superclass's initComponent implementation
        twowayfitness.BenchmarkDisplayPanel.superclass.initComponent.call(this);
    }
});

twowayfitness.BenchmarkDialog = Ext.extend(twowayfitness.RestDialog, {
    initComponent: function() {
        var self = this;

        var fc = new twowayfitness.FieldCreator({
            data: this.data,
            submission_object_name: 'metric'
        });

        var descriptionField = fc.text_field('description', 'Description', {
            // allowBlank: false
        });

        var detailsField = fc.text_area('details', 'Details', {
        });

         var store = new Ext.data.SimpleStore({
             fields: [ 'type', 'unit' ],
             data : [
                    [ 'Number', 'count' ],
                    [ 'Time', 'time' ],
                    [ 'Length/Height', 'centimetres' ],
                    [ 'Length/Height', 'metres' ],
                    [ 'Length/Height', 'kilometres' ],
                    [ 'Length/Height', 'inches' ],
                    [ 'Length/Height', 'feet' ],
                    [ 'Length/Height', 'miles' ],
                    [ 'Weight', 'kg' ],
                    [ 'Weight', 'lb' ]
                ]
         });
         
         var units_combo = new Ext.form.ComboBox({
             tpl: '<tpl for="."><div class="x-combo-list-item">{type}: {unit}</div></tpl>',
             store: store,
             name: 'metric[units]',
//             value: self.data ? self.data['metric[units]'] : '',
             value: self.data ? self.data.units : '',
             disabled: self.data ? true : false, // once units are set for a benchmark, they cannot be changed.
             displayField:'unit',
             fieldLabel: 'Units',
             typeAhead: true,
             mode: 'local',
             triggerAction: 'all',
             hiddenName: 'metric[units]',
             emptyText:'Select a unit...',
             editable: false,
             selectOnFocus:true
         });             

         // jstracer.write('BenchmarkDialog id = ' + this.data.id);
         Ext.applyIf(this, {
             submitOnEnter: false,
              title: 'Benchmark',
              help_key: 'benchmark',
              object_name: 'metric',
              REST_container_uri: '/metrics',
              manualProgressDismiss: true,
              dataSaved: function(result) {
                  self.benchmarks_panel.reload_benchmarks_list(self, result.metric_id);
              },
              modal: true,
              form_items: [
                  descriptionField,
                  detailsField,
                  units_combo
              ]
          });
         
         twowayfitness.BenchmarkDialog.superclass.initComponent.call(this);
    }
});

twowayfitness.BenchmarksPanel = Ext.extend(twowayfitness.GridWithShowPanel, {
    constructor: function(config) {
        // Your preprocessing here
        twowayfitness.BenchmarksPanel.superclass.constructor.apply(this, [ config ]);
        // Your postprocessing here
    },
    displayPanel: function() {
        if(!this.display_panel) {
            this.display_panel = new twowayfitness.BenchmarkDisplayPanel({
                form_authenticity_token: this.form_authenticity_token
            });
            this.setCenterPanel(this.display_panel);
        }
        return this.display_panel;
    },
    display_metric: function(metric_id) {
        this.displayPanel().display_metric(metric_id);
    },
    reload_benchmarks_list: function(dialog, metric_id) {
        if(dialog) {
            this.progress_dialog = dialog;
        }
        this.reloadList(metric_id);
        this.display_metric(metric_id);
    },
    editable_and_deletable: function(data) {
       return true;
    },
    new_metric: function() {
    },
    // override initComponent
    initComponent: function() {
        var self = this;
        var url = this.client_id ? '/clients/' + this.client_id + '/metrics.ext_json': '/metrics.ext_json';
        
        var datastore = new Ext.data.Store({
            url: url,

            reader: new Ext.data.JsonReader
                (
                    {
                        root: 'metrics',
                        id: 'id',
                        totalProperty: 'results'
                    },
                    [
                        {name: 'id', mapping: 'id'},
                        {name: 'uri', mapping: 'uri'},
                        {name: 'client_id', mapping: 'client_id'},
                        {name: 'units', mapping: 'units'},
                        {name: 'description', mapping: 'description'},
                        {name: 'details', mapping: 'details'},
                        {name: 'last_measurement_value_as_string', mapping: 'last_measurement_value_as_string'},
                        {name: 'is_automatic', mapping: 'is_automatic'}
                    ]
                )
        });
        
        datastore.addListener({
            'create': {
                fn: function() {
                }
            },
            'loadexception': {
                fn: function() {
                    self.progress_dialog.hideProgress();
                    self.progress_dialog = twowayfitness.null_progress_dialog;
                }
            },
            'load': {
                fn: function() {
                    self.progress_dialog.hideProgress();
                    self.progress_dialog = twowayfitness.null_progress_dialog;
                }
            }
        });
        
        var column_model = new Ext.grid.ColumnModel([
          {header:"description", width: 200, dataIndex: 'description', sortable: true },
          {header:"units", width: 100, dataIndex: 'units', sortable: true},
          {header:"value", width: 100, dataIndex: 'last_measurement_value_as_string' }
        ]);

        var html = '';
        html += "<div class='instructions'>";
        html += "<p>A Benchmark is something about you that can be measured. You can set goals/targets for each benchmark and track your progress towards those goals. Examples of benchmarks you might like to create are benchmarks for tracking things like your weight, your resting pulse rate, the time it takes you to complete a regular run or ride, the number of situps you can do, etc.</p>";
        html += "<p>Click on the 'New ...' button to create a new benchmark.</p>";
        html += "<p>Click on an existing benchmark in the list to the left in order to view a record of measurements for that benchmark, or to add a new measurement or edit or delete an existing measurement.</p>";
        html += "<p>Click on the '?' icon on the right hand side of this window for additional help.</p>";

        Ext.applyIf(this, {
            autoScroll: false,
            progress_dialog: twowayfitness.null_progress_dialog,
            showPanelWrapperConfig: {
                autoScroll: true
            },
            showPanelConfig: {
                id: 'instructions',
                // autoScroll: true,
                html: html
            },
            listPanelConfig: {
                region: 'west',
                width: 400
            },
            tools: [
                {
                    id: 'help',
                    handler: function(event, toolEl, panel) {
                            twowayfitness.displayHelp('benchmarks');
                        }
                }
            ],
            title: 'Benchmarks & Measurements',
            datastore: datastore,
            column_model: column_model,
            // height: '30%',
            display_show_panel: true,
            display_toolbar: true,
            object_name: 'benchmark',
            collection_path: 'metrics',
            on_new: function() {
               var window = new twowayfitness.BenchmarkDialog({
                   form_authenticity_token: this.form_authenticity_token,
                   client_id: this.client_id,
                   benchmarks_panel: self
               });
               window.show();
            },
            after_delete: function() {
                self.display_panel.hide();
                return true;
            },
            on_edit: function(selected) {
                var window = new twowayfitness.BenchmarkDialog({
                    form_authenticity_token: this.form_authenticity_token,
                    benchmarks_panel: self,
                    REST_uri: selected.data.uri,
                    data: selected.data
                });
                window.show();
            },
            on_rowclick: function(data) {
              self.displayPanel().setData(data);
            }
        });

        // call the superclass's initComponent implementation
        twowayfitness.BenchmarksPanel.superclass.initComponent.call(this);
        this.datastore.load({
            callback: function() {
                return true;
            }
        });
    }
});



twowayfitness.text_field = function(name, label) {
    return new Ext.form.TextField(this.field_params(name, label));
};

twowayfitness.ArticleDialog = Ext.extend(twowayfitness.RestDialog, {
    dataSaved: function(result) {
        this.articles_panel.reloadList(result.article_id);
    },
    initComponent: function() {
        twowayfitness.ArticleDialog.superclass.initComponent.call(this);
    }
});

twowayfitness.PublishArticleDialog = Ext.extend(twowayfitness.ArticleDialog, {
    setData: function(data) {
        this.data = data;

        var fc = new twowayfitness.FieldCreator({
            container: this,
            data: this.data,
            object_name: 'article'
        });

        fc.updateFieldByName('title');
        fc.updateFieldByName('publication_date');
        fc.updateField(this.public_checkbox);
        fc.updateField(this.clients_checkbox);
    },
    initComponent: function() {
        var fc = new twowayfitness.FieldCreator({
            data: this.data,
            object_name: 'article'
        });
         
         this.titleField = fc.text_field('title', 'Title', {
             anchor: '100%',
             disabled: true
         });
         
         this.dateField = fc.date_field('publication_date', 'Publication Date', {
                     format: 'Y-m-d',
                     allowBlank: false,
                     value: new Date()
                 }
             );
             
         this.public_checkbox = new Ext.form.Checkbox(
             fc.checkbox_params('published_to_public', 'public website', {
                 // the rendering on FF 3.0 and IE is buggered if the height is not provided below. Don't know what causes it.
                 height: 40
             })             
         );
         this.clients_checkbox = new Ext.form.Checkbox(
             fc.checkbox_params('published_to_clients', 'my clients', {
                 // The rendering on FF 3.0 and IE is buggered if the height is not provided below. Don't know what causes it.
                 height: 40
             })             
         );
         
         var published_checkboxes = {
             // Use the default, automatic layout to distribute the controls evenly
             // across a single row
             xtype: 'checkboxgroup',
             columns : 2,
             fieldLabel: 'Published to',
             items: [
                 this.public_checkbox,
                 this.clients_checkbox
             ]
         };

        Ext.applyIf(this, {
             width: 500,
             title: 'Publish article',
             height: 250,
             stateful: false,
             help_key: 'publish_article',
             REST_key: 'articles/publish',
             object_name: 'article',
             // use_max_possible_height: true,
             form_items: [
                this.titleField,
                published_checkboxes,
                this.dateField
             ]
         });
         
         twowayfitness.PublishArticleDialog.superclass.initComponent.call(this);
    }
});

twowayfitness.ArticleContentDialog = Ext.extend(twowayfitness.RestDialog, {
    beforeSubmit: function() {
        // this forces the tinyMCE field to save its value to the underlying text area,
        // which will cause the correct value to be submitted.
        //var value = this.contentField.getValue();
        this.contentField.syncValue();
    },
    setData: function(data) {
        this.data = data;

        var fc = new twowayfitness.FieldCreator({
            container: this,
            data: this.data,
            object_name: 'article'
        });

        fc.updateField(this.titleField);
        fc.updateFieldByName('content');
    },
    twoWaybeingResized: function() {
        // this is a hack to get this window being correctly size.
        // I don't fully understand why it's needed.
        // this.contentField.setSize(this.contentField.getEl().getWidth(), new_height - 300);
    },
    initComponent: function() {
        var self = this;

        var fc = new twowayfitness.FieldCreator({
            data: this.data,
            object_name: 'article'
        });
        
         
         // this.contentField = new Ext.ux.form.TinyMCE({
         //     fieldLabel: 'Content',
         //     name: 'article[content]',
         //     anchor: '100% 85%',
         //     enableColors: false,
         //     monitorResize: true,
         //     stateful: false,
         //     value: self.data ? self.data['article[content]'] : ''
         // });

         //this.contentField = new Ext.ux.TinyMCE({
         //    // height: 1900,
         //    anchor: '100% -30',
         //    fieldLabel: 'Content',
         //    name: 'article[content]',
         //    autoScroll: true,
         //    bodyStyle: 'padding: 10px',
         //    value: self.data ? self.data['article[content]'] : '',
         //
         //   tinymceSettings: {
         //         "content_css": "/stylesheets/gravity2.css",
         //         "debug":false,
         //         "mode":"none",
         //         "theme":"advanced",
         //         "strict_loading_mode":true,
         //         "auto_reset_designmode":true,
         //         "browsers":"msie,gecko,opera,safari",
         //         "button_tile_map":true,
         //         "language":"en",
         //         "docs_language":"en",
         //         "object_resizing":true,
         //         "table_inline_editing":false,
         //         "plugins":"preview,fullscreen,inlinepopups,style,media,advlink,advimage,paste,searchreplace,table,xhtmlxtras",
         //         "apply_source_formatting":true,
         //         "cleanup":true,
         //         "cleanup_on_startup":true,
         //         "convert_fonts_to_spans":true,
         //         "convert_newlines_to_brs":false,
         //         "doctype":"<!DOCTYPE html PUBLIC \"-\/\/W3C\/\/DTD XHTML 1.0 Strict\/\/EN\" \"http:\/\/www.w3.org\/TR\/xhtml1\/DTD\/xhtml1-strict.dtd\">",
         //         "entity_encoding":"raw",
         //         "fix_content_duplication":true,
         //         "fix_list_elements":true,
         //         "fix_table_elements":true,
         //         "force_p_newlines":true,
         //         "force_br_newlines":false,
         //         "force_hex_style_colors":true,
         //         "forced_root_block":"p",
         //         "inline_styles":true,
         //         "remove_trailing_nbsp":false,
         //         "trim_span_elements":true,
         //         "verify_css_classes":false,
         //         "verify_html":false,
         //         "convert_urls":true,
         //         "relative_urls":false,
         //         "remove_script_host":true,
         //         "width":"100%",
         //         "visual":true,
         //         theme_advanced_blockformats: "p,div,h2,h3,h4,h5,h6,blockquote,dt,dd,code,samp",
         //         "theme_advanced_layout_manager":"SimpleLayout",
         //         "theme_advanced_toolbar_location":"top",
         //         "theme_advanced_toolbar_align":"left",
         //         "theme_advanced_resizing":true,
         //         "theme_advanced_resize_horizontal":false,
         //         "theme_advanced_resizing_use_cookie":false,
         //         "theme_advanced_buttons1":"formatselect,styleselect,|,undo,redo,|,cut,pastetext,|,search,replace,|,visualaid,",
         //         "theme_advanced_buttons2":"bold,italic,underline,strikethrough,|,tablecontrols,|,fullscreen",
         //         "theme_advanced_buttons3":"justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,indent,outdent,|,link,unlink,anchor,|,image,media,|,sub,sup,|,charmap,|,blockquote,cite,abbr,acronym"
         //
         //
         //
         //
         //       // theme : "advanced",
         //       // plugins: "safari,pagebreak,style,layer,table,advhr,advimage,advlink,emotions,iespell,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,noneditable,visualchars,nonbreaking,xhtmlxtras,template",
         //       // theme_advanced_buttons1 : "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect,fontselect,fontsizeselect",
         //       // theme_advanced_buttons2 : "cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor",
         //       // theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,charmap,emotions,iespell,media,advhr,|,print,|,ltr,rtl,|",
         //       // theme_advanced_buttons4 : "insertlayer,moveforward,movebackward,absolute,|,styleprops,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,template,pagebreak",
         //       // theme_advanced_toolbar_location : "top",
         //       // theme_advanced_toolbar_align : "left",
         //       // theme_advanced_statusbar_location : "bottom",
         //       // theme_advanced_resizing : false,
         //       // extended_valid_elements : "a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]",
         //       // template_external_list_url : "example_template_list.js"
         //   }
         //});

         this.titleField = fc.text_field('title', 'Title', {
             anchor: '100%',
             region: 'north'
//             autoHeight: true
//             height: 100
             // region: 'north'
         });

        this.contentField = new Ext.form.HtmlEditor({
            fieldLabel: 'Content',
            name: 'article[content]',
            value: self.data ? self.data['article[content]'] : '',
            flex: 1.0,
            anchor: '100% 100%'
//            width: '100%',
//            width: 1000,
//            height: 600
        });

        // this.contentField = new Ext.form.TextArea({
        //     anchor: '100% -30',
        //     fieldLabel: 'Content',
        //     name: 'article[content]',
        //     autoScroll: true,
        //     bodyStyle: 'padding: 10px',
        //     value: self.data ? self.data['article[content]'] : ''
        // });
         
        Ext.applyIf(this, {
//            layout: 'fit',
            width: 700,
            constrain_to: twowayfitness.main_panel,
            // labelWidth: 80,
            title: 'Article',
            autoHeight: false,
            // style: 'background-color: #ff0000',
            stateful: false,
//            autoScroll: false,
            help_key: 'create_or_edit_article',
            REST_key: 'articles',
            object_name: 'article',
            use_max_possible_height: true,
            form_items: [
//                {
//                    html: 'hello'
//                }
//                {
//                    xtype: 'fieldset',
//                    items: [
//                        this.titleField
//                    ]
//                },
//                {
//                    xtype: 'fieldset',
//                    items: [
//                        this.contentField
//                    ]
//                }
                        this.titleField,
                        this.contentField
            ],
            form_panel_config: {
//                layout: 'vbox',
//                autoScroll: false,
                labelWidth: 60
            }
         });
         
         twowayfitness.ArticleContentDialog.superclass.initComponent.call(this);
    }
});

debug_show_article_dialog = function() {
    var dialog = new twowayfitness.ArticleContentDialog({
        // autoHeight: false,
        // height: 900,
        form_authenticity_token: this.form_authenticity_token
    });
    dialog.show();
};


Ext.grid.CheckColumn = function(config){
    Ext.apply(this, config);
    if(!this.id){
        this.id = Ext.id();
    }
    this.renderer = this.renderer.createDelegate(this);
};

Ext.grid.CheckColumn.prototype ={
    renderer : function(v, p, record) {
        return '<div class="' + (record.data[this.dataIndex]? 'micks-checked' : '')  + '"</div>';
    }
};  

twowayfitness.ArticlesPanel = Ext.extend(twowayfitness.GridWithShowPanel, {
    // override initComponent
    on_new: function() {
        var window = new twowayfitness.ArticleContentDialog({
            form_authenticity_token: this.form_authenticity_token,
            articles_panel: this
        });
        window.show();
    },
    on_edit: function(selected) {
        this.showDialog(selected.data.id, twowayfitness.ArticleContentDialog);
        
        // // TODO: refactor with other users of twowayfitness.Dialog
        // var params = {
        //     format: 'ext_json'
        // };
        // // alert('datax = ' + datax + ' selected.data = ' + selected.data);
        // Ext.Ajax.request({
        //    url: '/articles/' + selected.data.id,
        //    method: 'GET',
        //    params: params,
        //    scope: this,
        //    success : function (response, options) {
        //        var data2 = Ext.util.JSON.decode(response.responseText);
        //        
        //        if(this.dialog) {
        //            this.dialog.setData(data2.data);
        //        } else {
        //            this.dialog = new twowayfitness.ArticleContentDialog({
        //                form_authenticity_token: this.form_authenticity_token,
        //                articles_panel: this,
        //                data: data2.data
        //            });
        //        }
        //        this.dialog.show();
        //    },
        //    failure : function (response, options) {
        //        alert("Failed to fetch information from server. Please try again later.");
        //    }
        // });
    },
    showDialog: function(object_id, dialog_class) {
        // TODO: refactor with other users of twowayfitness.Dialog
        var params = {
            format: 'ext_json'
        };
        // alert('datax = ' + datax + ' selected.data = ' + selected.data);
        Ext.Ajax.request({
           url: '/articles/' + object_id,
           method: 'GET',
           params: params,
           scope: this,
           success : function (response) {
               var data2 = Ext.util.JSON.decode(response.responseText);

               var dialog = new dialog_class({
                   form_authenticity_token: this.form_authenticity_token,
                   articles_panel: this,
                   data: data2.data
               });
               dialog.show();
           },
           failure : function() {
               alert("Failed to fetch information from server. Please try again later.");
           }
        });
        
    },
    initComponent: function() {
        var datastore = new Ext.data.Store(
            {
            url: '/articles.ext_json',
            
            // proxy: new Ext.data.HttpProxy(
            //   new Ext.data.Connection(
            //     {
            //         url: '/articles',
            //         extraParams: {
            //             'format':'ext_json'
            //         },
            //         method: 'GET'
            //     }
            //   )
            // ),
            reader: new Ext.data.JsonReader(
                    {
                        root: 'articles',
                        id: 'id',
                        totalProperty: 'results'
                    },
                    [
                        {name: 'id', mapping: 'id'},
                        {name: 'title', mapping: 'title'},
                        {name: 'published_to_public', mapping: 'published_to_public'},
                        {name: 'published_to_clients', mapping: 'published_to_clients'},
                        {name: 'updated_at', mapping: 'updated_at'},
                        {name: 'publication_date', mapping: 'publication_date'},
                        {name: 'content', mapping: 'content'}
                    ]
                )
          }
        );

        var checkColumn1 = new Ext.grid.CheckColumn({
           header: "public",
           dataIndex: 'published_to_public',
           sortable: true,
           align: 'center',
           width: 55
        });
        var checkColumn2 = new Ext.grid.CheckColumn({
           header: "clients",
           dataIndex: 'published_to_clients',
           sortable: true,
           align: 'center',
           width: 55
        });
        
        var column_model = new Ext.grid.ColumnModel({
            columns: [
                {header:"title", width: 250, dataIndex: 'title', sortable: true },
                checkColumn1,
                checkColumn2,
                {header:"publication date", width: 250, dataIndex: 'publication_date', sortable: true }
            ],
            rows: [
                [
                    {},
                    {header: 'published to', colspan: 2, align: 'center'},
                    {}
                ]
            ]
            
        });
        
        this.publish_button = new Ext.Toolbar.Button({
            text:'Publish ...',
            tooltip:'Change whether this article is published, or to whom it is published.',
            handler: function() {
                var selected = this.grid.getSelectionModel().getSelected();
                this.showDialog(selected.data.id, twowayfitness.PublishArticleDialog);
            },
            scope: this
            // ,
            // iconCls:'add'
        });
        
        Ext.applyIf(this, {
            showPanelConfig: {
                // cls: 'article'
                autoScroll: true
            },
            additional_tbar_buttons: [
                this.publish_button
            ],
            tools: [
                {
                    id: 'help',
                    handler: function() {
                            twowayfitness.displayHelp('articles');
                        }
                }
            ],
            title: 'Articles',
            datastore: datastore,
            column_model: column_model,
            display_show_panel: true,
            display_toolbar: true,
            object_name: 'article',
            collection_path: 'articles',
            grid_config: {
                plugins: [new Ext.ux.plugins.GroupHeaderGrid()]
            }
        });

        // call the superclass's initComponent implementation       
        twowayfitness.ArticlesPanel.superclass.initComponent.call(this);
        this.datastore.load();
    }
});



twowayfitness.QuotationDialog = Ext.extend(twowayfitness.RestDialog, {
    dataSaved: function(result) {
        this.quotations_panel.reloadList(result.quotation_id);
    },
    setData: function(data) {
        this.data = data;

        var fc = new twowayfitness.FieldCreator({
            container: this,
            data: this.data,
            object_name: 'quotation'
        });

        fc.updateFieldByName('quote');
        fc.updateFieldByName('author');
    },
    initComponent: function() {
        var self = this;

        var fc = new twowayfitness.FieldCreator({
            data: this.data,
            object_name: 'quotation'
        });

        var quotationField = fc.text_area('quote', 'Text', {
                 // height: 100,
                 anchor: '100% 90%'
             }
         );

         var authorField = fc.text_field('author', 'Author', {
             anchor: '100%'
         });

        Ext.applyIf(this, {
             title: 'Quotation',
             // layout: 'fit',
             // autoHeight: true,
             // need to do better than hard coding height and width.
             height: 400,
             width: 500,
             help_key: 'create_or_edit_quotation',
             REST_key: 'quotations',
             object_name: 'quotation',
             form_items: [
                      authorField,
                      quotationField
                  ]
         });
         
         twowayfitness.QuotationDialog.superclass.initComponent.call(this);
    }
});

twowayfitness.QuotationsPanel = Ext.extend(twowayfitness.GridWithShowPanel, {
    // override initComponent
    on_new: function() {
        var window = new twowayfitness.QuotationDialog({
            form_authenticity_token: this.form_authenticity_token,
            quotations_panel: this
        });
        window.show();
    },
    on_edit: function(selected) {
        var params = {
            format: 'ext_json'
        };
        Ext.Ajax.request({
           url: '/quotations/' + selected.data.id,
           method: 'GET',
           params: params,
           scope: this,
           success : function (response, options) {
               var data2 = Ext.util.JSON.decode(response.responseText);
               // jstracer.write('data2 = ' + Object.keys(data2));
               // jstracer.write('data2.data = ' + Object.keys(data2.data));

               if(this.dialog) {
                   this.dialog.setData(data2.data);
               } else {
                   this.dialog = new twowayfitness.QuotationDialog({
                      form_authenticity_token: this.form_authenticity_token,
                      quotations_panel: this,
                      data: data2.data
                  });
               }
               this.dialog.show();
               
               // 
               // var window = new twowayfitness.QuotationDialog({
               //     form_authenticity_token: this.form_authenticity_token,
               //     quotations_panel: this,
               //     data: data2.data
               // });
               // window.show();
           },
           failure : function (response, options) {
               alert("Failed to fetch information from server. Please try again later.");
           }
        });
    },
    initComponent: function() {
        // jstracer.write('BenchmarksPanel initComponent autoHeight = ' + this.autoHeight);
        var self = this;
        var datastore = new Ext.data.Store(
          {
              url: '/quotations.ext_json',
            // proxy: new Ext.data.HttpProxy(
            //   new Ext.data.Connection(
            //     {
            //         url: '/quotations',
            //         extraParams: {
            //             'format':'ext_json'
            //         },
            //         method: 'GET'
            //     }
            //   )
            // ),
            reader: new Ext.data.JsonReader(
                    {
                        root: 'quotations',
                        id: 'id',
                        totalProperty: 'results'
                    },
                    [
                        {name: 'id', mapping: 'id'},
                        {name: 'quote', mapping: 'quote'},
                        {name: 'author', mapping: 'author'}
                    ]
                )
          }
        );

        var column_model = new Ext.grid.ColumnModel([
          {header:"author", width: 150, dataIndex: 'author', sortable: true },
          {header:"quote", width: 400, dataIndex: 'quote', sortable: true}
        ]);
        
        Ext.applyIf(this, {
            // on_new: function() {
            //     var window = new twowayfitness.BenchmarkDialog({
            //         form_authenticity_token: this.form_authenticity_token,
            //         client_id: this.client_id,
            //         benchmarks_panel: self
            //     });
            //     window.show();
            // },
            // after_delete: function() {
            //     self.display_panel.hide();
            //     return true;
            // },
            // on_edit: function(selected) {
            //     var window = new twowayfitness.BenchmarkDialog({
            //         form_authenticity_token: this.form_authenticity_token,
            //         benchmarks_panel: self,
            //         data: selected.data
            //     });
            //     window.show();
            // },
            tools: [
                {
                    id: 'help',
                    handler: function(event, toolEl, panel) {
                            twowayfitness.displayHelp('quotations');
                        }
                }
            ],
            title: 'Quotations',
            datastore: datastore,
            column_model: column_model,
            display_show_panel: true,
            display_toolbar: true,
            object_name: 'quotation',
            collection_path: 'quotations'
            // ,
            // on_rowclick: function(data) {
            //   self.display_panel.setData(data);
            // }
        });

        // call the superclass's initComponent implementation       
        twowayfitness.QuotationsPanel.superclass.initComponent.call(this);
        this.datastore.load();
    }
});



twowayfitness.CouponDialog = Ext.extend(twowayfitness.RestDialog, {
    dataSaved: function(result) {
        this.coupons_panel.reloadList(result.coupon_id);
    },
    initComponent: function() {
        var self = this;

        var fc = new twowayfitness.FieldCreator({
            data: this.data,
            submission_object_name: 'coupon'
        });

        var keyField = fc.text_field('key', 'Key', {
                 anchor: '100%'
             }
         );

        var expiryField = fc.date_field('free_subscription_expiry', 'Free Subscription Expiry Date', {
                anchor: '100%',
                format: 'd M Y',
                editable: true,
                readOnly: false,
                allowBlank: true
             }
         );

        var freeSubscriptionLengthField = fc.text_field('free_subscription_length', 'Free Subscription Period Length', {
                 anchor: '100%'
             }
         );

        Ext.applyIf(this, {
             title: 'Coupon',
             height: 400,
             width: 500,
             //help_key: 'create_or_edit_quotation',
             REST_key: 'coupons',
             object_name: 'coupon',
             form_items: [
                     keyField,
                     {
                         border: false,
                         html: "<div class = 'instructions'><p>Set one or other or both of the fields below</p><p>When a new user uses a coupon, their free subscription end date will be either the specified free subscription end date, or the current date + the free subscription length, or the end date of their trial period, whichever comes last.</p></div>"
                     },
                     expiryField,
                     freeSubscriptionLengthField
                  ]
         });

         twowayfitness.CouponDialog.superclass.initComponent.call(this);
    }
});

twowayfitness.CouponsPanel = Ext.extend(twowayfitness.GridWithShowPanel, {
    // override initComponent
    on_new: function() {
        var window = new twowayfitness.CouponDialog({
            form_authenticity_token: this.form_authenticity_token,
            coupons_panel: this
        });
        window.show();
    },
    on_edit: function(selected) {
        var params = {
            format: 'ext_json'
        };
        Ext.Ajax.request({
           url: selected.data.uri,
           method: 'GET',
           params: params,
           scope: this,
           success : function (response, options) {
               var data = Ext.util.JSON.decode(response.responseText);

               this.dialog = new twowayfitness.CouponDialog({
                  form_authenticity_token: this.form_authenticity_token,
                  coupons_panel: this,
                  data: data,
                  REST_uri: data.uri
              });
               this.dialog.show();
           },
           failure : function (response, options) {
               alert("Failed to fetch information from server. Please try again later.");
           }
        });
    },
    initComponent: function() {
        var self = this;
        var datastore = new Ext.data.Store(
          {
            url: '/coupons.ext_json',
            reader: new Ext.data.JsonReader(
                    {
                        root: 'coupons',
                        id: 'uri',
                        totalProperty: 'results'
                    },
                    [
                        {name: 'uri', mapping: 'uri'},
                        {name: 'key', mapping: 'key'},
                        {name: 'free_subscription_expiry', mapping: 'free_subscription_expiry', type: 'date' },
                        {name: 'free_subscription_length', mapping: 'free_subscription_length'}
                    ]
                )
          }
        );

        var column_model = new Ext.grid.ColumnModel([
            {header:"Key", width: 200, dataIndex: 'key', sortable: true },
            {header:"Free Subscription End", width: 200, dataIndex: 'free_subscription_expiry', sortable: true, xtype: 'datecolumn', format: 'd M Y' },
            {header:"Free Subscription Length", width: 200, dataIndex: 'free_subscription_length', sortable: true }
        ]);

        Ext.applyIf(this, {
            title: 'Coupons',
            datastore: datastore,
            column_model: column_model,
            display_show_panel: false,
            display_toolbar: true,
            object_name: 'coupon',
            collection_path: 'coupons'
        });

        // call the superclass's initComponent implementation
        twowayfitness.CouponsPanel.superclass.initComponent.call(this);
        this.datastore.load();
    }
});



// panel for displaying the goals for a simple series (i.e. a benchmark)
twowayfitness.SimpleGoalsPanel = Ext.extend(Ext.Panel, {
    fetchData: function(dialog) {
        var self = this;
        Ext.Ajax.request({
           url: this.data.series_url,
           method: 'GET',
           params: {
               single: 'true',
               format: 'ext_json'
           },
           scope: this,
           success : function (response, options) {
                var data = Ext.util.JSON.decode(response.responseText);
                var store = self.goals_store;
                store.loadData(data, false);
                if(dialog) {
                    dialog.hideProgress();
                }
           },
           failure : function (response, options) {
               if(dialog) {
                   dialog.hideProgress();
               }
               alert("Failed to fetch information from server. Perhaps the item has been deleted.");
           }
        });
    },
    initComponent: function() {
        var self = this;

        self.goals_store = new Ext.data.Store({
            reader: new Ext.data.JsonReader(
                {
                    root: 'goals'
                },
                [
                    { name: 'date', mapping: 'date', type:'date' },
                    { name: 'value', mapping: 'value' },
                    {name: 'duration_hrs', mapping: 'duration_hrs'},
                    {name: 'duration_min', mapping: 'duration_min'},
                    {name: 'duration_sec', mapping: 'duration_sec'},
                    { name: 'uri', mapping: 'uri' }
                ]
            ),
            proxy: new Ext.data.MemoryProxy(),
            data: self.data,
            autoDestroy: true
        });
        
        var column_model = new Ext.grid.ColumnModel([
          {header:"date", width: 140, dataIndex: 'date', sortable: true, renderer: Ext.util.Format.dateRenderer('jS F, Y') },
          {header:"value", width: 100, dataIndex: 'value', sortable: true}
        ]);
        
        self.grid = new twowayfitness.GridWithShowPanel({
            title: 'Goals',
            manualProgressDismiss: true,
            display_toolbar: true,
            border: true,
            frame: true,
            form_authenticity_token: self.form_authenticity_token,
            height: 200,
            width: 260,
            datastore: self.goals_store,
            column_model: column_model,
            on_new: function() {
                var uri = self.data.series_url;
                var dialog = new twowayfitness.MeasurementDialog({
                    manualProgressDismiss: true,
                    title: 'Add goal',
                    isDuration: self.data.units == 'time',
                    REST_uri: uri,
                    dataSaved: function() {
                        self.fetchData(dialog);
                    },
                    form_authenticity_token: self.form_authenticity_token
                });
                dialog.on('show', function(comp) {
                    // Fix for IE: for some reason (an ext bug I think), the duration field does not show unless I do the following.
                   comp.doLayout();
                });
                dialog.show();
            },
            on_edit: function(selected) {
                var dialog = new twowayfitness.MeasurementDialog({
                    manualProgressDismiss: true,
                    title: 'Edit goal',
                    isDuration: self.data.units == 'time',
                    REST_uri: selected.data.uri,
                    data: selected.data,
                    dataSaved: function() {
                        self.fetchData(dialog);
                    },
                    form_authenticity_token: self.form_authenticity_token
                });
                dialog.on('show', function(comp) {
                    // Fix for IE: for some reason (an ext bug I think), the duration field does not show unless I do the following.
                   comp.doLayout();
                });
                dialog.show();
            },
            after_delete: function() {
                // self.goals_panel.fetchData();
                self.fetchData(self.grid);
                return false;
            }
        });
        
        Ext.applyIf(this, {
            frame: true,
            layout: 'hbox',
            width: 600,
            collapsible: true,
            style: 'padding: 10px',
            items: [
                {
                    style: 'padding-right: 10px',
                    width: 300,
                    html: self.data.summary_html
                },
                self.grid
            ]
        });
        
        twowayfitness.SimpleGoalsPanel.superclass.initComponent.call(this);
    }
});

twowayfitness.SetGoalsPanel = Ext.extend(Ext.Panel, {
    display_goals: function() {
        var self = this;
        
        if(!self.have_removed_instructions_panel) {
            // get rid of the instructions panel if it is being displayed
            self.have_removed_instructions_panel = true;
            self.center_panel.remove(self.instructions_panel, true);
            self.center_panel.add(self.goals_panel);
            self.center_panel.doLayout();
        }
    
        var node = this.current_node;
        if(node) {
            var attributes = node.attributes;
            if(attributes.series_url) {
                var url = attributes.series_url + '/goals';
                this.goals_panel.setUrl(url);
            }
        }
    },
    gotData: function(data) {
        var self  = this;
        var arr = data.goals_and_values;
        var last_element_index = arr.length - 1;
        this.goals_panel.add({
            border: false,
            style: 'padding: 10px',
            html: data.summary_html
        });
        var instructions;
        if(arr.length > 1) {
            instructions = "The panels below allow you to create one or more goals for this series for each of the different time periods (weekly, monthly, quarterly, and yearly).";
        } else {
            instructions = "The panel below allows you to create one or more goals for this series. You can also edit or delete any goals you have created previously.";
        }
        this.goals_panel.add({
            min_width: 400,
            border: true,
            bodyBorder: false,
            html: "<p class = 'instructions'>" + instructions + "</p>"
        });
        for(var i = 0; i <= last_element_index; ++i) {
            var element = arr[i];
            var title = element.name ? element.name : 'Goals';
            var gpanel = new twowayfitness.SimpleGoalsPanel({
                title: title,
                form_authenticity_token: self.form_authenticity_token,
                data: element
            });

            this.goals_panel.add(gpanel);
        }
        // this.goals_panel.layout.setActiveItem(last_element_index);

        // for IE, we seem to need to do the following 2 doLayout calls. Not sure why.
        this.goals_panel.doLayout();
        this.doLayout();
    },
    initComponent: function() {
        var self = this;

        self.instructions_panel = twowayfitness.makePanel({
            min_width: 400,
            border: true,
            bodyBorder: false,
            html: "<p class = 'instructions'>You can set one or more goals for each of the series displayed to the left. Click on a series in order to view or edit your current goals or to set new goals.</p>"
        });
        
        self.center_panel = new Ext.Panel({
            region: 'center',
            border: false,
            layout: 'fit',
            items: [
                self.instructions_panel
            ]
        });

        self.goals_panel = twowayfitness.makePanel({
            autoScroll: true,
            border: false,
            fetchData: function() {
                this.removeAll(true);
                Ext.Ajax.request({
                   url: self.url,
                   method: 'GET',
                   params: {
                       format: 'ext_json'
                   },
                   scope: this,
                   success : function (response, options) {
                        var data = Ext.util.JSON.decode(response.responseText);
                        self.gotData(data);
                   },
                   failure : function (response, options) {
                       alert("Failed to fetch information from server. Perhaps the item has been deleted.");
                   }
                });
            },
            setUrl: function(url) {
                self.url = url;
                this.fetchData();
            }
        });

        var tree = new twowayfitness.ChartsTreePanel({
            region: 'west',
            split: true,
            collapsible: true,
            dataUrl: '/series',
            listeners: {
                'click' : {
                    fn: function(node, e) {
                        self.current_node = node;
                        self.display_goals();
                    }
                }
            }
        });
        
        Ext.applyIf(this, {
            title: 'Set Goals',
            border: false,
            autoScroll: false,
            layout: 'border',
            help_key: 'set_goals',
            tools: [
                {
                    id: 'help',
                    handler: function(event, toolEl, panel) {
                            twowayfitness.displayHelp(self.help_key);
                        }
                }
            ],
            items: [
                tree,
                self.center_panel
            ]
        });

        twowayfitness.SetGoalsPanel.superclass.initComponent.call(this);
    }
});


twowayfitness.WeekPanel = Ext.extend(Ext.Panel, {
    setData: function (data, is_edit) {
        //alert('set data');
        // there is likely a javascript function for fetching day names somewhere.
        var day_names = [
            "Monday",
            "Tuesday",
            "Wednesday",
            "Thursday",
            "Friday",
            "Saturday",
            "Sunday"
        ];
        
        var self = this;
        //this.doLayout(); // is this needed?
        
        // alert('data = '+ Object.keys(data));
        if(this.north_panel) {
            this.set_north_panel_data(data, is_edit);
        }
        this.week_start_date = new Date(data.date);
        
        var date = new Date(this.week_start_date);
        this.dateField.setValue(date);

        var column_index = 0;
        for (column_index=0; column_index<7; column_index++)
        {
            var col = this.columns[column_index];
            twowayfitness.remove_all_components(col);
            col.add(new Ext.Panel({
                border: false,
                cls: 'day',
                html: '<h3>' + day_names[column_index] + ' ' + date.getDate()  + '</h3>'
            }));
            col.data = data.days[column_index];
            var entries = col.data.entries;
            
            if(entries.size() == 0) {
                col.add(new Ext.Panel({
                    height: 200,
                    border: false
                }));
            } else {
                for (var entry_index = 0; entry_index < entries.size(); entry_index++)
                {
                    var entry = entries[entry_index];
                    var html = entry.html;
                    col.add(new Ext.Panel({
                        border: false,
                        entry_id: entry.id,
                        entry_data: entry,
                        html: html,
                        listeners: {
                            render: function(cmp) {
                                cmp.body.on('click', function(e) {
                                    if(self.allow_edit) {
                                        self.onClick(cmp.entry_data, e);
                                        // show_activity_dialog(true, cmp.entry_id, self.form_authenticity_token, self);
                                    }
                                });
                            }
                        }
                    }));
                }
            }
            date.setDate(date.getDate() + 1);
        }
        this.doLayout();

        //if(data.highlight_date) {
        //    Ext.get('date').highlight('FF6900',
        //        {
        //            endColor: 'ffffff',
        //            duration: 1
        //        }
        //    );
        //}

        if(data.highlight) {
            Ext.get(data.highlight).highlight('FF6900',
                {
                    endColor: 'ffffff',
                    duration: 2
                }
            );
        }
    },
    performFetch: function(params) {
        params['format'] = 'ext_json';
        if(this.client_id) {
            params['client_id'] = this.client_id;
        }
        Ext.Ajax.request({
           url: this.base_url,
           method: 'GET',
           params: params,
           scope: this,
           success : function (response) {
               var data = Ext.util.JSON.decode(response.responseText);
               if(!data.success) {
                   alert('we got an error man');
               }
               this.setData(data);
           },
           failure : function () {
               alert("Failed to fetch information from server. Please try again later.");
           }
        });
    },
    fetchNextOrPreviousWeek: function(next_or_previous) {
        this.performFetch({
            'format':'ext_json',
            'year': this.week_start_date.getFullYear(),
            'month': this.week_start_date.getMonth() + 1,
            'day': this.week_start_date.getDate(),
            'what': next_or_previous
        });
    },
    fetchPreviousWeek: function() {
        this.fetchNextOrPreviousWeek('previous');
    },
    fetchNextWeek: function() {
        this.fetchNextOrPreviousWeek('next');
    },
    fetchCurrentWeek: function() {
        this.performFetch({});
    },
    fetchWeekIncludingDate: function(date) {
        this.performFetch({
            'format':'ext_json',
            'year': date.getFullYear(),
            'month': date.getMonth() + 1,
            'day': date.getDate(),
            'what': 'specified'
        });

    },
    initComponent: function() {
        var self = this;
        
        Ext.applyIf(this, {
            allow_edit: true,
            add_button_text: 'add ...',
            add_button_css: 'add'
        });
        
        var one_seventh = 1.0/7;
        this.columns = [];
        var column_index = 0;
        for(column_index=0; column_index<7; column_index++)
        {
            var column_panel = new Ext.Panel({
                //layout: 'fit',
                //title: day_names[column_index],
                columnWidth: one_seventh,
                //flex: 1,
                //autoHeight: true,
                //height: 400,
                border: false,
                ctCls: 'diary-day-column',
                tbar: this.allow_edit ? [
                    {
                        column_index: column_index,
                        text: this.add_button_text,
                        iconCls: this.add_button_css,
                        handler: function(button,e) {
                            var col = this.columns[button.column_index];
                            var data = col.data;
                            this.on_add(data,e);
                        },
                        scope: this
                    }
                ] : []
            });

            this.columns.push(column_panel);
        }

        var dateFieldTooltip = 'choose a specific week';
        this.dateField = new Ext.form.DateField({
            fieldLabel: 'Week commencing',
            width: 120,
            format: 'M j, Y',
            readOnly: true,
            listeners: {
                'select' : {
                    fn: function(field, date) {
                        self.fetchWeekIncludingDate(date);
                    }
                },
                render: function(c){
                    Ext.get(this.id).set({qtip:dateFieldTooltip});
                    Ext.get(this.id).next('img').set({qtip:dateFieldTooltip});
                }
            }
        });

        var items = [];

        if(this.north_panel) {
            items.push(this.north_panel);
        }
        
        items.push({
            //autoWidth: true,
            anchor: '100%',
            layout: 'column',
            border: false,
            items: this.columns
        });

        items.push({
            html: "<div class='instructions'><p>Click on the '?' icon on the right hand side of this window for help using this feature.</p></div>",
            width: 400,
            border: false
        });
       
        var buttonWidth = 30;
        Ext.applyIf(this, {
            layout: 'fit',
            autoScroll: true,
            border: false,
            //monitorResize: true,
            items : new Ext.Panel({
                layout: 'anchor',
                autoHeight: true,
                //autoWidth: true,
                //border: true,
                min_width: 1100,
                plugins: twowayfitness.micksPlugin,
                border: false,
                items: items
            }),
            tools: [
                {
                    id: 'help',
                    handler: function(event, toolEl, panel) {
                            twowayfitness.displayHelp(self.help_key);
                        }
                }
            ],
            tbar: [
                {
                    xtype: 'tbtext',
                    text: 'Week commencing:'
                },
                this.dateField,
                '-',
                {
                    //text: 'Current',
                    icon: '/images/icon-date-now.png',
                    scale: 'large',
                    //icon: '/images/icons/calendar_view_week.png',
                    iconAlign: 'bottom',
                    tooltip: 'view current week',
                    //width: buttonWidth,
                    handler: function() {
                        this.fetchCurrentWeek();
                    },
                    scope: this

                },
                '-',
                {
                    //text: 'Previous',
                    //icon: '/images/icons/arrow_left.png',
                    icon: '/images/icon-left-arrow.png',
                    scale: 'large',
                    iconAlign: 'bottom',
                    tooltip: 'view previous week',
                    width: buttonWidth,
                    handler: function() {
                        this.fetchPreviousWeek();
                    },
                    scope: this
                },
                {
                    //text: 'Next',
                    //icon: '/images/icons/arrow_right.png',
                    icon: '/images/icon-date-next.png',
                    scale: 'large',
                    iconAlign: 'bottom',
                    tooltip: 'view next week',
                    //width: buttonWidth,
                    handler: function() {
                        this.fetchNextWeek();
                    },
                    scope: this
                }
            ]
        });        
        
        this.addListener({
            'render': {
                fn: function() {
                    this.fetchCurrentWeek();
                },
                scope: this
            }
        });
        
        
        twowayfitness.WeekPanel.superclass.initComponent.call(this);
        // alert('this.border = ' + this.border);
        
    }
});




twowayfitness.DietPanel = Ext.extend(twowayfitness.WeekPanel, {
    on_add: function(data) {
        var date = new Date(data.date);
        twowayfitness.edit_dietary_intake_from_date(
            date.getFullYear(),
            date.getMonth() + 1,
            date.getDate(),
            this.form_authenticity_token,
            this
        );
    },
    onClick: function(data) {
        twowayfitness.edit_dietary_intake_from_id(
            data.id,
            this.form_authenticity_token,
            this
        );
    },
    initComponent: function() {
        this.summary_panel = new Ext.Panel({
             region: 'center',
             border: false
        });

        Ext.applyIf(this, {
            border: false,
            autoScroll: true,
            title: 'Diet',
            base_url: '/client/week/diet',
            add_button_text: 'edit ...',
            add_button_css: 'edit',
            help_key: 'diet'
        });
        
        twowayfitness.DietPanel.superclass.initComponent.call(this);
    }
});




Ext.namespace('twowayfitness.metrics');

twowayfitness.metrics.show_measurements_chart = function(metric_id, type) {
  var url = "/metrics/" + metric_id + ".xml?";
  flashObject = $("micks_chart");
  flashObject.setParam("values.y.type", type);
  flashObject.reloadData(url);
};

twowayfitness.metrics.show_metric_chart = function(metric_id, type, allow_delete, authenticity_token_param) {
    // alert("show_metric_chart");
  var element_id = "benchmark-" + metric_id + "-table-slot";
  twowayfitness.metrics.show_measurements_chart(metric_id, type);
  // twowayfitness.metrics.update_measurements_table(metric_id, type, true, allow_delete, authenticity_token_param);
  // alert("4000");
  // twowayfitness.metrics.update_measurements_table(metric_id, type, false, allow_delete, authenticity_token_param);
};

twowayfitness.metrics.set_toolbar_state = function(grid_panel, row_index)
{
    // alert("set_toolbar_state()");
    var store = grid_panel.getStore();
    var record = store.getAt(row_index);
    var is_auto = record.get('is_automatic');
    // alert("set_toolbar_state() is_auto = "+ is_auto);
    if(is_auto) {
        grid_panel.edit_button.disable();
        grid_panel.delete_button.disable();
    } else {
        grid_panel.edit_button.enable();
        grid_panel.delete_button.enable();
    }
};

twowayfitness.metrics.show_metric = function(metric_id, authenticity_token)
{
    alert("show_metric() id = " + metric_id);
    var chart_and_table_element = $("chart-and-table-inner");
    var chart_already_exists_param_value = chart_and_table_element ? "true" : "false";
    
    var url = "/metrics/chart_and_table/" + metric_id +
          "?recordIndex=" + 0 +
          "&recordId=" + "bla" +
          "&chart_exists=" + chart_already_exists_param_value +
          "&authenticity_token=" + authenticity_token;
          
    Ext.Ajax.request({
        url: url,
        method: 'GET'
    });
};

twowayfitness.metrics.update_measurements_table = function(metric_id, amcharts_type, goals, allow_delete, authenticity_token_param) {
    alert("update_measurements_table()");
	var suffix = goals ? "_goals" : "";
	var cssSelector = ".measurements-table" + suffix;
	
	var outer_div = $$(cssSelector)[0];
	var inner_div_id = "benchmark-" + metric_id + "-table-slot" + suffix;
	outer_div.update("<div id='" + inner_div_id + "'></div>");
	
    // twowayfitness.metrics.create_measurements_table(metric_id, inner_div_id, amcharts_type, goals, allow_delete, authenticity_token_param);
};

twowayfitness.metrics.create_measurements_table = function(metric_id, element_id, amcharts_type, goals, allow_delete, authenticity_token_param) {
  alert("110 allow_delete = "+ allow_delete);

  var months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
  
  my_date_formatter = function(el, oRecord, oColumn, oData) {
        el.innerHTML = "" + months[oData.getMonth()] + " " + oData.getDate() + ", " + oData.getFullYear();
    };

  var url = "/metrics/" + metric_id +  ".json?goals=" + (goals ? "true" : "false") + "&bla=foo";
  var myDataSource = new YAHOO.util.DataSource(url);
  myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
  
  myDataSource.responseSchema = {
      resultsList: "measurements",
      fields: [
        { key:'date', parser:YAHOO.util.DataSource.parseDate },
        { key:"value_as_string" },
        { key:'id' }
      ]
  };   

  var myColumnDefs = [];
  if(allow_delete)
  {
	myColumnDefs.push({ key:'delete', label:' ', formatter: function(el) {
			el.innerHTML = '<button type="button" class="yui-dt-button">x</button>';
		}
	  });
  }
	myColumnDefs.push({key:"date", minWidth: 80, resizeable:true,sortable:true, formatter:my_date_formatter, editor:"date"});
	myColumnDefs.push({key:"value_as_string", minWidth: 50, label:"value", resizeable:true,sortable:true, editor:"textbox", editorOptions:{validator:YAHOO.widget.DataTable.validateNumber}});

  var myDataTable = new YAHOO.widget.DataTable(
      element_id,
      myColumnDefs,
      myDataSource ,
      {
          sortedBy:{
                  key:'date',
                  dir:'asc'
          }
      }
  );
  //alert("170 myDataTable = " + myDataTable);

  myDataTable.subscribe('cellClickEvent',function(ev) {
      var target = YAHOO.util.Event.getTarget(ev);
      var column = myDataTable.getColumn(target);

	  // alert("cellClickEvent column = " + column);

      if (column.key == 'delete') {
	      var record = this.getRecord(target);
	      id = record.getData('id');
          if (confirm('Are you sure you wish to remove this measurement?')) {
            var recordIndex = myDataTable.getRecordSet().getRecordIndex(record);
            html_element = myDataTable.getTrEl(record);
            var tr_id = html_element.id;

			var url = "/measurements/" + id
					+ "?" + authenticity_token_param +
					"&recordIndex=" + recordIndex +
                    "&recordId=" + tr_id;
            // myDataTable.deleteRow(target);
            new Ajax.Request(url, { method: 'delete'});
          }
      }
  });                    

  //alert("171");
  
  this.highlightEditableCell = function(oArgs) { 
    var elCell = oArgs.target; 
    if(YAHOO.util.Dom.hasClass(elCell, "yui-dt-editable")) { 
      this.highlightCell(elCell); 
    } 
  };          
  // alert("172 myDataTable = " + myDataTable);
  
  myDataTable.subscribe("cellClickEvent", myDataTable.onEventShowCellEditor);

  // alert("174");
  myDataTable.subscribe("editorSaveEvent", function(oArgs) {
       if(oArgs.editor.column.key === "date") {
           //alert("date edited");
       }
   });

  // alert("180");

   myDataTable.onEventSaveCellEditor = function(oArgs, oSelf) {
      var key = this._oCellEditor.column.key;
      //alert("key = " + key);
      var newData = this._oCellEditor.value;
      var oRecord = this._oCellEditor.record;
      var id = oRecord.getData('id');
       var url;
      if(key == "date") {
        //alert("100 key = " + key);
        url = "/measurements/" + id + "/change_date?" + authenticity_token_param + "&date_year=" + newData.getFullYear() + "&date_month=" + (newData.getMonth()+1) + "&date_day=" + newData.getDate();
        new Ajax.Request(url, { method: 'put'});
      } else if(key == "value_as_string") {
        // alert("200 key = " + key);
        url = "/measurements/" + id + "/change_value?" + authenticity_token_param + "&value=" + newData;
        new Ajax.Request(url, { method: 'put'});
      }
      this.resetCellEditor();
   };
   
  // alert("190");
};


twowayfitness.ExercisePanel = Ext.extend(twowayfitness.WeekPanel, {
    set_north_panel_data: function(data, is_edit) {
        this.summary_panel.body.update(data.summary_html);
        this.historical_panel.setData(data.historical_snapshot_chart_xml);
        this.pie_charts_panel.setData(data.pie_charts_panel_xml);
//        this.weekly_ep_panel.setData(data.weekly_ep_gauge_xml);
//        if(is_edit) {
//            this.ep_gauges_panel.fetchInfo();
//        }
    },
    
    new_activity_from_template: function(template_id, data) {
        var self = this;
        show_activity_dialog(template_id, this.form_authenticity_token, {
            submission_succeeded: function(result) {
                self.setData(result, true);
            },
            duplicate: true,
            date: data.date
        });
    },
    new_activity_menu_item_clicked: function(menu_item) {
        this.new_activity_from_template(menu_item.template_id, menu_item.new_activity_data);
    },
    on_add: function(data, e) {
        var self = this;
        var event_x = e.getXY()[0];
        var event_y = e.getXY()[1];
        var templatesMenu = new Ext.menu.Menu({
            items: [
                {
                    text: '... fetching activities'
                }
            ],
            listeners: {
                'beforeshow': function(menu) {
                    // var box = Ext.Msg.wait('Retrieving activities');
                    Ext.Ajax.request({
                        // scope: templatesMenu,
                        url: '/activity_templates',
                        method: 'GET',
                        params: {
                            'format': 'json',
                            'as_array': 1
                        },
                        success : function(response, options) {
                            var templates = Ext.util.JSON.decode(response.responseText).templates;

                            if(templates.size() > 0) {
                                menu.removeAll();
                                Ext.each(templates, function(template_info, index) {
                                    menu.addItem(
                                        new Ext.menu.Item({
                                            scope: self,
                                            text: template_info[1],
                                            handler: self.new_activity_menu_item_clicked,
                                            template_id: template_info[0],
                                            new_activity_data: data
                                        })
                                    );
                                });
                            } else {
                                menu.items.get(0).setText('no available activities');
                            }

                            // var maxHeight = self.el.getHeight() - event_y;
                            // var maxHeight = twowayfitness.viewport.el.getHeight() - event_y - 20;
                            var maxHeight = twowayfitness.viewport.el.getHeight() - menu.el.getY() - 10;
                            if(menu.el.getHeight() > maxHeight) {
                                menu.el.setHeight(maxHeight);
                                menu.el.applyStyles('overflow:auto;');
                            }
                            // box.hide();
                        },
                        failure: function(response, options) {
                            // box.hide();
                            alert('failure');
                        }
                    });
                }
            }
        });
        
        var menu = new Ext.menu.Menu({
            items: [
                {
                    text: 'Add new activity ...',
                    handler: function() {
                        newExerciseActivity(self.form_authenticity_token, {
                            date: new Date(data.date),
                            submission_succeeded: function(result) {
                                self.setData(result, true);
                            }
                        });
                    }
                },
                {
                    text: 'Select from regular activities ...',
                    menu: templatesMenu
                }            
            ]
        });
        menu.showAt([event_x-50, event_y]);
    },
    onClick: function(data, e) {
        var self = this;
        var menu = new Ext.menu.Menu({
            // floating: false,
            items: [
                {
                    text: 'Edit ...',
                    handler: function() {
                        show_activity_dialog(data.id, self.form_authenticity_token, {
                            is_edit: true,
                            submission_succeeded: function(result) {
                                self.setData(result, true);
                            }
                        });
                    }
                },
                {
                    text: 'Save as Regular Activity ...',
                    handler: function() {
                        Ext.Ajax.request({
                           url: "/exercise_diary_entries/" + data.id,
                           method: 'GET',
                           params: {
                               format: 'ext_json'
                           },
                           scope: this,
                           success : function (response, options) {
                               var data = Ext.util.JSON.decode(response.responseText);

                               showExerciseActivityDialog(self.form_authenticity_token, true, data, {
                                   submission_succeeded: function(result) {
                                       Ext.Msg.show({
                                           minWidth: 600,
                                           icon: Ext.MessageBox.INFO,
                                           title: 'Success',
                                           buttons: Ext.MessageBox.OK,
                                           msg: 'The activity was succesfully saved as a regular activity. You can now use the activity when recording a new exercise diary entry by selecting "add ... Select from regular activities".'
                                       });
                                   },
                                   is_template: true,
                                   is_edit: false
                               });
                           },
                           failure : function (response, options) {
                               alert("Failed to fetch information from server. Perhaps the item has been deleted.");
                           }
                        });
                    }
                },
                '-',
                {
                    text: 'Delete ...',
                    handler: function() {
                        Ext.Msg.confirm('Delete Exercise Entry', 'Are you sure you wish to delete this entry?', function(btn, text) {
                            if (btn == 'yes') {
                                Ext.Ajax.request({
                                   scope: this,
                                    url: '/exercise_diary_entries/' + data.id,
                                    params: {
                                        '_method': 'delete',
                                        'authenticity_token': self.form_authenticity_token
                                    },
                                    waitMsg:'Deleting Entry ...',
                                    success : function (response, options) {
                                        var result = Ext.util.JSON.decode(response.responseText);
                                        self.setData(result, true);
                                    },
                                    failure: function(response, options) {
                                        //var result = Ext.util.JSON.decode(response.responseText);
                                        twowayfitness.showPlainMessage("Failed to remove the item. Perhaps it has already been deleted.");
//                                        Ext.Msg.alert('Notice', "Failed to remove the item. Perhaps it has already been deleted.");
                                    }
                                });
                            }
                        });
                    }
                }
            ]
        });
        menu.showAt(e.getXY());
        // menu.show(e.getTarget());
    },
    initComponent: function() {
        var self = this;
        this.summary_panel = new Ext.Panel({
             height: 150,
             width: 200,
             border: false
        });

        this.historical_panel = new twowayfitness.AnyChartPanel({
            aspect_ratio: false,
            width: 500,
            min_height: false
        });

        this.historical_holder_panel = new Ext.Panel({
            layout: 'fit',
            border: false,
            height: 200,
            items: this.historical_panel
        });

        this.pie_charts_panel = new twowayfitness.AnyChartPanel({
            should_log: true,
            aspect_ratio: false,
            width: 300,
            min_height: false
        });

        this.pie_charts_holder_panel = new Ext.Panel({
            layout: 'fit',
            border: false,
            height: 200,
            items: this.pie_charts_panel
        });

        var north_panel = new Ext.Panel({
           layout: 'column',
           border: false,
           // frame: true,
           items: [
                this.summary_panel,
                this.pie_charts_holder_panel,
                this.historical_holder_panel
//                this.weekly_ep_panel,
//                this.ep_gauges_panel
           ]
        });
        
        Ext.applyIf(this, {
            //autoScroll: true,
            base_url: '/client/week/activities',
            title: 'Activity',
            help_key: 'exercise',
            north_panel: north_panel
        });
        
        twowayfitness.ExercisePanel.superclass.initComponent.call(this);
    }
});


twowayfitness.ClientsPanel = Ext.extend(twowayfitness.BoxesPanel, {
    numItems: function() {
        // jstracer.write('numItems = ');
        return this.data.clients.size();
    },
    createBox: function(item_index) {
        var self = this;
        var clients = this.data.clients;
        var client = clients[item_index];
        var client_html = client.summary_html;
        
        return new Ext.Panel({
            client_id: client.id,
            client_user_id: client.user_id,
            client_name: client.display_name,
            border:  false,
            html: client_html,
            listeners: {
                render: function(cmp) {
                  cmp.getEl().on('click', function() {
                      var window = new twowayfitness.ClientWindow({
                          form_authenticity_token: self.form_authenticity_token,
                          title: cmp.client_name,
                          client_id: cmp.client_id,
                          client_user_id: cmp.client_user_id
                      });
                      
                      window.show();
                   });
                }
            }
        });
    },
    fetchData: function() {
        Ext.Ajax.request({
           url: '/trainer_clients',
           method: 'GET',
           params: { 'format':'ext_json' },
           scope: this,
           success : function (response, options) {
               // alert('success');
               var data = Ext.util.JSON.decode(response.responseText);
               this.setData(data);
           },
           failure : function (response, options) {
               alert("Failed to fetch information from server. Please try again later.");
           }
        });
    },
    initComponent: function() {
        Ext.applyIf(this, {
            title: 'Clients',
            tools: [
                {
                    id: 'help',
                    handler: function(event, toolEl, panel) {
                            twowayfitness.displayHelp('clients');
                        }
                }
            ]
        });
        
        twowayfitness.ClientsPanel.superclass.initComponent.call(this);
    }
});


twowayfitness.ActivityTemplatesPanel = Ext.extend(twowayfitness.GridWithShowPanel, {
    on_new: function() {
        var self = this;
        newExerciseActivity(self.form_authenticity_token, {
            submission_succeeded: function() {
                self.datastore.load();
            },
            is_template: true
        });
    },
    on_edit: function(selected) {
        var self = this;
        Ext.Ajax.request({
           url: "/activity_templates/" + selected.data.id,
           method: 'GET',
           params: {
               format: 'ext_json'
           },
           scope: this,
           success : function (response) {
               var data = Ext.util.JSON.decode(response.responseText);

               showExerciseActivityDialog(self.form_authenticity_token, true, data, {
                   submission_succeeded: function() {
                       self.datastore.load();
                       self.showItem(selected.data);
                   },
                   is_template: true,
                   is_edit: true
               });
           },
           failure : function () {
               alert("Failed to fetch information from server. Perhaps the item has been deleted.");
           }
        });
    },
    initComponent: function() {
        var datastore = new Ext.data.Store(
          {
            url: '/activity_templates.json',
             
            // proxy: new Ext.data.HttpProxy(
            //   new Ext.data.Connection(
            //     {
            //         method: 'GET',
            //         extraParams: {
            //             format: 'ext_json'
            //         }
            //     }
            //   )
            // ),
            reader: new Ext.data.JsonReader(
                    {
                        root: 'templates',
                        id: 'id'
                    },
                    [
                        {name: 'id', mapping: 'id'},
                        {name: 'name', mapping: 'name'},
                        {name: 'sections', mapping: 'sections'},
                        {name: 'exertion', mapping: 'exertion'},
                        {name: 'duration', mapping: 'duration'},
                        {name: 'eps', mapping: 'eps'}
                    ]
                )
          }
        );

        var column_model = new Ext.grid.ColumnModel([
          {header:"Name", width: 300, dataIndex: 'name', sortable: true},
          {header:"Sections", width: 80, dataIndex: 'sections', sortable: true},
          {header:"Duration (minutes)", width: 130, dataIndex: 'duration', sortable: true},
          {header:"Expected Exertion", dataIndex: 'exertion', sortable: true},
          {header:"EPs", dataIndex: 'eps', sortable: true}
        ]);
        
        var help_html = "<div class='instructions'>";
        help_html += "<p>A Regular Exercise Activity is an activity, such as a run or a training session, that you perform regularly.</p>";
        help_html += "<p>In 2Way Fitness Analytics, regular exercise activites save you from having to re-enter the same or similar information over and over again when recording your training activities.</p>";
        help_html += "<p>Regular exercise activites can also be used to help you plan your training.</p>";
        help_html += "<p>Click on the '?' icon on the right hand side of this window for instructions on using this feature.</p>";
        help_html += "</div>";
        
        Ext.applyIf(this, {
            showPanelConfig: {
                autoScroll: true,
                html: help_html
            },
            tools: [
                {
                    id: 'help',
                    handler: function() {
                            twowayfitness.displayHelp('activity_templates');
                        }
                }
            ],
            title: 'Regular Exercise Activities',
            datastore: datastore,
            column_model: column_model,
            display_show_panel: true,
            display_toolbar: true,
            object_name: 'regular exercise activity',
            collection_path: 'activity_templates'
        });

        // call the superclass's initComponent implementation       
        twowayfitness.ActivityTemplatesPanel.superclass.initComponent.call(this);
        this.datastore.load();
    }
});



twowayfitness.ClientPanel = Ext.extend(Ext.TabPanel, {
    setData: function (data) {
        this.data = data;
        var client_data = data.client;
        
        var about_panel = new Ext.Panel({
           title: 'about',
           html: client_data.about_html
        });
        
        var benchmarksPanel = new twowayfitness.BenchmarksPanel({
            client_id: this.client_id,
            // hideMode: 'offsets',
            form_authenticity_token: this.form_authenticity_token,
            autoScroll: true
        });
        
        var exercisePanel = new twowayfitness.ExercisePanel({
            allow_edit: false,
            client_id: this.client_id,
            form_authenticity_token: this.form_authenticity_token
        });
        
        var dashboardPanel = new twowayfitness.DashboardPanel({
                form_authenticity_token: this.form_authenticity_token,                
                client_id: this.client_id,
                border: false
        });

        // var dashboard2Panel = new twowayfitness.AnyChartPanel({
        //         title: 'dashboard 2',
        //         init_url: "trainer/client/" + this.client_id + "/dashboard",
        //         form_authenticity_token: this.form_authenticity_token,
        //         client_id: this.client_id,
        //         border: false
        // });

        // alert('setData form_authenticity_token = ' + this.form_authenticity_token);
        // alert('client_data.display_name = ' + client_data.display_name);
        var messagesPanel = new twowayfitness.MessageMasterDetail(
            this.form_authenticity_token,
            {
                correspondent_id: this.client_user_id,
                generic_description: 'client',
                name: client_data.name
            }
        );
        
        // We can retrieve a reference to the data store
        // via the StoreMgr by its storeId
        // TODO: get rid of this
        // Ext.StoreMgr.get('gridMessageStore').load(
        //     {
        //         method: 'GET'
        //     }
        // );
        
        
        var dietPanel = new twowayfitness.DietPanel({
            allow_edit: false,
            client_id: this.client_id,
            form_authenticity_token: this.form_authenticity_token
            // ,
            // height: 700,
            // width: 500
        });
        
        // new Ext.Panel({
        //     client_id: this.client_id,
        //     form_authenticity_token: this.form_authenticity_token,
        //     height: 700,
        //     width: 500
        // });
        
        this.add(about_panel);
        this.add(dashboardPanel);
        // this.add(dashboard2Panel);
        this.add(benchmarksPanel);
        this.add(exercisePanel);
        this.add(dietPanel);
        this.add(messagesPanel);
        
        this.setActiveTab(0);
        // this.ownerCt.setSizeAndPosition();
        // this.doLayout();
        // this.benchmarksPanel.doLayout();
    },
    fetchClient: function() {
        Ext.Ajax.request({
           url: '/trainer_clients/' + this.client_id,
           method: 'GET',
           params: { 'format':'ext_json' },
           scope: this,
           success : function (response, options) {
               // alert('success');
               var data = Ext.util.JSON.decode(response.responseText);
               this.setData(data);
           },
           failure : function (response, options) {
               alert("Failed to fetch information from server. Please try again later.");
           }
        });
        // sleep(10);
    },
    initComponent: function() {
        // Ext.apply(this, {
        //     id: 'clients_panel'
        // });
        // Ext.ComponentMgr.register(this);
        
        // jstracer.write('clients_panel autoScroll = ' + this.autoScroll);
        
        Ext.applyIf(this, {
            tools: [
                {
                    id: 'help',
                    handler: function(event, toolEl, panel) {
                            twowayfitness.displayHelp('client');
                        }
                }
            ],
            defaults: {
                border: false,
                autoScroll: true
            },
            border: false
        });
        
        // jstracer.write('client_panel autoScroll = ' + this.autoScroll);
        
        this.addListener({
            'beforerender': {
                fn: function() {
                    this.fetchClient();
                },
                scope: this
            }
        });
         
        twowayfitness.ClientPanel.superclass.initComponent.call(this);
    }
});

twowayfitness.ClientWindow = Ext.extend(twowayfitness.PopupWindow, {
    constructor: function(config) {
        // jstracer.write('PopupWindow constructor keys = ' + Object.keys(this));
        
        // Your preprocessing here
        twowayfitness.ClientWindow.superclass.constructor.apply(this, [ config ]);
        // Your postprocessing here
    },
    initComponent: function() {
        var client_panel = new twowayfitness.ClientPanel({
            client_id: this.client_id,
            client_user_id: this.client_user_id,
            form_authenticity_token: this.form_authenticity_token
        });
        Ext.applyIf(this, {
            // autoHeight: true,
            autoScroll: false,
            // showCloseButtons: false,
            layout: 'fit',
            // constrain: true,
            // autoWidth: true,
            height: 1000,
            width: 1000,
            items: [
                client_panel
            ]
        });
        twowayfitness.ClientWindow.superclass.initComponent.call(this);
    }
});


twowayfitness.DashboardBenchmarksBoxesPanel = Ext.extend(twowayfitness.BoxesPanel, {
    numItems: function() {
        return this.data ? this.data.benchmarks.size() : 0;
    },
    createBox: function(item_index) {
        var self = this;
        var benchmark_data = this.data.benchmarks[item_index];
        // var client = clients[item_index];
        // var client_html = client.summary_html;
        
        // jstracer.write('CREATING PANEL');
        
        var chart_panel = new twowayfitness.BenchmarkChartPanel({
            // border: false,
            metric_id: benchmark_data.metric_id,
            height: 230,
            width: 200,
            // init_data: benchmark_data.chart_xml,
            form_authenticity_token: self.form_authenticity_token
        });

        return chart_panel;
    },
    fetchData: function() {
        var params = {};
        params['format'] = 'ext_json';
        if(this.client_id) {
            params['client_id'] = this.client_id;
        }
        Ext.Ajax.request({
           url: '/client/dashboard',
           method: 'GET',
           params: params,
           scope: this,
           success : function (response, options) {
               var data = Ext.util.JSON.decode(response.responseText);
               this.setData(data);
           },
           failure : function (response, options) {
               alert("Failed to fetch information from server. Please try again later.");
           }
        });
        // this.setData(this.data);
    },
    initComponent: function() {
        Ext.applyIf(this, {
            // title: 'Benchmarks'
            box_width: 300,
            borders: false
        });
        twowayfitness.DashboardBenchmarksBoxesPanel.superclass.initComponent.call(this);
    }
});

twowayfitness.DashboardBenchmarksPanel = Ext.extend(Ext.Panel, {
    relayout: function() {
        this.boxes_panel.relayout();
    },
    setData: function(data) {
        this.boxes_panel.setData(data);
    },
    initComponent: function() {
        this.boxes_panel = new twowayfitness.DashboardBenchmarksBoxesPanel({
           form_authenticity_token: this.form_authenticity_token,
           client_id: this.client_id
        });
        
        Ext.applyIf(this, {
            items: [
                {
                    xtype: 'panel',
                    border: false,
                    html: "<p class='padded'>Click on a chart to view the benchmark in detail.<p>"
                },
                this.boxes_panel
            ]
        });
        twowayfitness.DashboardBenchmarksPanel.superclass.initComponent.call(this);
    }
});

twowayfitness.EpGaugesPanel = Ext.extend(Ext.Panel, {
    setData: function (data) {
        this.daily_ep_panel.setData(data.daily_ep_gauge_xml);
        this.weekly_ep_panel.setData(data.weekly_ep_gauge_xml);
        this.monthly_ep_panel.setData(data.monthly_ep_gauge_xml);
    },
    fetchInfo: function() {
        var params = {};
        params['format'] = 'ext_json';
        if(this.client_id) {
            params['client_id'] = this.client_id;
        }
        Ext.Ajax.request({
           url: '/client/ep_gauges',
           method: 'GET',
           params: params,
           scope: this,
           success : function (response, options) {
               var data = Ext.util.JSON.decode(response.responseText);
               this.setData(data);
           },
           failure : function (response, options) {
               alert("Failed to fetch information from server. Please try again later.");
           }
        });
    },
    initComponent: function() {
        var aspect_ratio = 1.4;
        this.daily_ep_panel = new twowayfitness.AnyGaugePanel({
            // title: 'daily',
//            margins: {top:0, right:-40, bottom:0, left:0},
            aspect_ratio: aspect_ratio,
            size_determined_by: 'width',
            anchor: '100%',
            flex: 1.0
//             width     : 170,
//             height    : 150
        });
        this.weekly_ep_panel = new twowayfitness.AnyGaugePanel({
            // title: 'weekly',
            aspect_ratio: aspect_ratio,
            size_determined_by: 'width',
            anchor: '100%',
             flex: 1.0
//             width     : 170,
//             height    : 150
        });
        this.monthly_ep_panel = new twowayfitness.AnyGaugePanel({
            // title: 'monthly',
            aspect_ratio: aspect_ratio,
            size_determined_by: 'width',
            anchor: '100%',
             flex: 1.0
//            ,
//             aspect_ratio: 1.6
//             width     : 170,
//             height    : 150
        });
        
        Ext.applyIf(this, {
            // layout: 'column',
            // height    : 150,
            layout: 'anchor',
            border: false,
            autoHeight: true,
            plugins: twowayfitness.micksPlugin,
            size_determined_by: 'width',
            aspect_ratio: 0.5,
            // columns: 1,
            monitorResize: true,
//            layout: 'vbox',
            items: [
                this.daily_ep_panel,
                this.weekly_ep_panel,
                this.monthly_ep_panel
            ]
        });
        
        this.addListener({
            'beforerender': {
                fn: function() {
                    this.fetchInfo();
                },
                scope: this
            }
        });
        twowayfitness.EpGaugesPanel.superclass.initComponent.call(this);
    }
});

twowayfitness.DashboardPanel = Ext.extend(Ext.Panel, {
    setData: function (data) {
        // this.ep_gauges_panel.setData(data);
        this.dashboard_benchmarks_panel.setData(data);
    },
    fetchDashboardInfo: function() {
        var params = {};
        params['format'] = 'ext_json';
        if(this.client_id) {
            params['client_id'] = this.client_id;
        }
        Ext.Ajax.request({
           url: '/client/dashboard',
           method: 'GET',
           params: params,
           scope: this,
           success : function (response, options) {
               var data = Ext.util.JSON.decode(response.responseText);
               this.setData(data);
           },
           failure : function (response, options) {
               alert("Failed to fetch information from server. Please try again later.");
           }
        });
    },
    initComponent: function() {
        this.ep_gauges_panel = new twowayfitness.EpGaugesPanel({
            client_id: this.client_id
        });
        
        this.dashboard_benchmarks_panel = new twowayfitness.DashboardBenchmarksPanel({
            form_authenticity_token: this.form_authenticity_token,
            client_id: this.client_id
        });
        
        // var main_panel = new Ext.Panel({
        //    html: '<h4>Under construction</h4><p>Tony, Ian ... This page is just the start of a dashboard that we could come up with ... I imagine us displaying benchmarks, goals, DPs, HPs, etc</p>'
        // });
        
        // this.id = 'exercise_panel';
        Ext.apply(this, {
            id: 'dashboard_panel'
        });
        Ext.ComponentMgr.register(this);
        Ext.applyIf(this, {
            title: 'Dashboard',
            monitorResize: true,
            items : [
                    this.ep_gauges_panel,
                    this.dashboard_benchmarks_panel
            ],
            tools: [
                {
                    id: 'help',
                    handler: function(event, toolEl, panel) {
                        twowayfitness.displayHelp('dashboard');
                    }
                }
            ],
            border: false
        });
        
        this.addListener({
            'beforerender': {
                fn: function() {
                    this.fetchDashboardInfo();
                },
                scope: this
            }
        });
        
        this.addListener({
            bodyresize: {
                fn: function(component, adjWidth, adjHeight, rawWidth, rawHeight) {
                    // jstracer.write('dashboard panel resize');
                    this.doLayout();
                    // alert('this.dashboard_benchmarks_panel = ' + this.dashboard_benchmarks_panel);
                    this.dashboard_benchmarks_panel.relayout();
                },
                scope: this,
                buffer: 50
            }
        });
         
        twowayfitness.DashboardPanel.superclass.initComponent.call(this);
    }
});




twowayfitness.ChangeEmailAddressDialog = Ext.extend(twowayfitness.RestDialog, {
    dataSaved: function() {
//      Ext.Msg.alert('Change email address', 'A confirmation email has been sent to the new email address. Please follow the instructions in that email to confirm that the new address is correct. We will not change over to using the new address until we have received confirmation.');
        twowayfitness.showPlainMessage(
                'A confirmation email has been sent to the new email address. Please follow the instructions in that email to confirm that the new address is correct. We will not change over to using the new address until we have received confirmation.',
                {
                    title: 'Change Email Address'
                }
            );
    },
    initComponent: function() {
        var self = this;

        var fc = new twowayfitness.FieldCreator({
            data: this.data,
            object_name: 'email_address_change'
        });
         
        this.addressField = fc.text_field('new_email_address', 'new address', {
        });
         
        Ext.applyIf(this, {
             width: 500,
             title: 'Change email address',
             help_key: 'change_email_address',
             REST_key: 'email_address_changes',
             object_name: 'email_address_change',
             modal: true,
             form_items: [
                 {
                     xtype: 'panel',
                     border: false,
                     width: 480,
                     html: '<p class="instructions">To set or change the email address associated with your account enter the new email address in the field below and click on "Save Changes".<p>'
                 },
                this.addressField
             ]
         });
         
         twowayfitness.ChangeEmailAddressDialog.superclass.initComponent.call(this);
    }
});

twowayfitness.show_change_email_address_dialog = function(form_authenticity_token, user_id) {
   var dialog = new twowayfitness.ChangeEmailAddressDialog({
       form_authenticity_token: form_authenticity_token,
       user_id: user_id
   });
   dialog.show();
};

        



twowayfitness.RegistrationForm = Ext.extend(Ext.FormPanel, {
    dataSaved: function() {
        // Ext.Msg.alert('Change email address', 'A confirmation email has been sent to the new email address. Please follow the instructions in that email to confirm that the new address is correct. We will not change over to using the new address until we have received confirmation.');
    },
    initComponent: function() {
        var self = this;

        var fc = new twowayfitness.FieldCreator({
            data: this.data,
            object_name: 'account_creation_attempt'
        });
         
         // -#         = f.submit_button 'Sign up'
         
        this.addressField = fc.text_field('email', 'Your email address', {
            labelAlign: 'right',
            width: 230
        });

        this.passwordField = fc.text_field('password', 'Password', {
            inputType: 'password'
        });
        this.confirmPasswordField = fc.text_field('password_confirmation', 'Retype password', {
            inputType: 'password'
        });
         
        // alert('this.contentEl = ' + this.contentEl);
        Ext.applyIf(this, {
            method: 'POST',
             defaults: {
                 labelAlign: 'right',
                 width: 230,
                 style: 'margin-bottom: 5px'
             },
             bodyStyle: 'padding:15px',
             labelWidth: 140,
             // bbar: [
             //    {
             //        text: 'Sign Up'
             //    }
             // ],
             width: 500,
             title: '2Way Fitness Analytics Registration',
             help_key: 'registration',
             REST_key: 'account_creation_attempts',
             object_name: 'account_creation_attempt',
             // modal: true,
             items: [
                {
                    xtype: 'panel',
                    width: '100%',
                    border: false,
                    contentEl: 'instructions'
                },
                // {
                //     xtype: 'panel',
                //     border: false,
                //     width: 480,
                //     html: '<p class="instructions">To set or change the email address associated with your account enter the new email address in the field below and click on "Save Changes".<p>'
                // },
                this.addressField,
                this.passwordField,
                this.confirmPasswordField,
                {
                    xtype: 'checkbox',
                    width: '100%',
                    // labelStyle: 'font-weight: normal;',
                    hideLabel: true,
                    // boxLabel: Ext.get('terms-checkbox-content').dom
                    boxLabel: '<span>By clicking on this checkbox you confirm that you have read and agreed to the terms and conditions and privacy policy for 2WayFitness</span>'
                },
                {
                    xtype: 'button',
                    // icon: '/images/cyclist.jpg',
                    text: 'Sign Up',
                    handler: function() {
                        self.getForm().submit();
                    }
                }
             ]
         });
         
         this.labelAlign = 'right';
         
         twowayfitness.RegistrationForm.superclass.initComponent.call(this);
    }
});



// twowayfitness.RegistrationDialog = Ext.extend(twowayfitness.RestDialog, {
//     dataSaved: function() {
//         // Ext.Msg.alert('Change email address', 'A confirmation email has been sent to the new email address. Please follow the instructions in that email to confirm that the new address is correct. We will not change over to using the new address until we have received confirmation.');
//     },
//     initComponent: function() {
//         var self = this;
// 
//         var fc = new twowayfitness.FieldCreator({
//             data: this.data,
//             object_name: 'account_creation_attempt'
//         });
//          
//          
//          // -#         = f.text_field :email, :label => 'Your email address'
//          // -# 
//          // -#         = f.password_field :password
//          // -#         = f.password_field :password_confirmation, :label => "Retype password"
//          // -# 
//          // -#         = f.submit_button 'Sign up'
//          
//         this.addressField = fc.text_field('email', 'Your email address', {
//         });
// 
//         this.passwordField = fc.text_field('password', 'Password', {
//         });
//         this.confirmPasswordField = fc.text_field('password_confirmation', 'Retype password', {
//         });
//          
//         alert('this.contentEl = ' + this.contentEl);
//         Ext.applyIf(this, {
//              width: 500,
//              title: '2Way Fitness Logbook Registration',
//              help_key: 'registration',
//              REST_key: 'account_creation_attempts',
//              object_name: 'account_creation_attempt',
//              // modal: true,
//              form_items: [
//                 // {
//                 //     xtype: 'panel',
//                 //     border: false,
//                 //     width: 480,
//                 //     html: '<p class="instructions">To set or change the email address associated with your account enter the new email address in the field below and click on "Save Changes".<p>'
//                 // },
//                 this.addressField,
//                 this.passwordField,
//                 this.confirmPasswordField
//              ]
//          });
//          
//          twowayfitness.RegistrationDialog.superclass.initComponent.call(this);
//     }
// });

// twowayfitness.show_change_email_address_dialog = function(form_authenticity_token, user_id) {
//    var dialog = new twowayfitness.ChangeEmailAddressDialog({
//        form_authenticity_token: form_authenticity_token,
//        user_id: user_id
//    });
//    dialog.show();
// };

        



// replace the entire panel's content with the specified component
twowayfitness.replace_component = function(container, component) {
    twowayfitness.remove_all_components(container);
    container.add(component);
    container.doLayout();
};

twowayfitness.remove_all_components = function(container) {
    var i;
    if(container.items) {
        while(i = container.items.last()){
            container.remove(i, true);
        }
    }
};

twowayfitness.display_mobile_app = function() {
    var location_count = 0;
    var geo_watcher_id = 0;
    var display_panel = new Ext.Panel({
       html: 'output will go here'
    });

    function handler(location) {
        location_count++;
        display_panel.body.update("<p>Longitude: " + location.coords.longitude + "</p><p>Latitude: " + location.coords.latitude + "</p><p>location updated " + location_count + " time(s)");
    }

    //function errorCallback(location) {
    //    location_count++;
    //     alert("Longitude: " + location.coords.longitude);
    //}

    var start_button = new Ext.Button({
       text: 'Start',
       listeners: {
           'click': {
               fn: function() {
                   //alert('start button clicked');
                    //navigator.geolocation.getCurrentPosition(handler);

                   geo_watcher_id = navigator.geolocation.watchPosition(handler); //, errorCallback, [Optional] in PositionOptions options);
               }
           }
       }
    });

    var stop_button = new Ext.Button({
       text: 'Stop',
       listeners: {
           'click': {
               fn: function() {
                    navigator.geolocation.clearWatch(geo_watcher_id);
               }
           }
       }
    });

    var panel = new Ext.Panel({
        title: 'this is the app',

        items: [
            {
                html: 'hello there, this is the app'
            },
            start_button,
            stop_button,
            display_panel
        ]
    });
    twowayfitness.viewport = new Ext.Viewport({
        cls: 'application',
        border: false,
        layout:'fit',
        items: panel
    });

};

twowayfitness.display_app = function(app_config) {
    twowayfitness.app_config = app_config;
    Ext.QuickTips.init();

    Ext.History.init();
    if(!app_config.logged_in) {
        var dialog = new twowayfitness.LoginDialog({
            form_authenticity_token: app_config.form_authenticity_token
        });
        dialog.show();
        return;
    }

    Ext.log('is production = ' + app_config.is_production);
    if(!app_config.is_production)
    {
        Ext.log('setting large timeout');
        Ext.Ajax.timeout = 1000000;
    }
    
    var chart_settings = app_config.chart_settings;
    chart_settings.timespan.end.date.value = new Date(chart_settings.timespan.end.date.value);
    chart_settings.timespan.beginning.date.value = new Date(chart_settings.timespan.beginning.date.value);

     // Handle this change event in order to restore the UI to the appropriate history state
     Ext.History.on('change', function(token){
        Ext.log('Ext.History.on');
         if(token) {
             if(token != twowayfitness.current_history_token) {
                 switch(token) {
                    case 'dashboard':
                        twowayfitness.main_panel.display_home_panel();
                        break;
                     case 'charts':
                         twowayfitness.main_panel.display_charts_panel();
                         break;
                    case "articles":
                        twowayfitness.main_panel.display_articles_panel();
                        break;
                    case "quotations":
                        twowayfitness.main_panel.display_quotations_panel();
                        break;
                    case "coupons":
                        twowayfitness.main_panel.display_coupons_panel();
                        break;
                    case "set-goals":
                        twowayfitness.main_panel.display_set_goals_panel();
                        break;
                    case "activity":
                        twowayfitness.main_panel.display_exercise_panel();
                        break;
                   case "regular-activities":
                        twowayfitness.main_panel.display_activity_templates_panel();
                        break;
                   case "benchmarks":
                        twowayfitness.main_panel.display_benchmarks_panel();
                        break;
                   case "historical-snapshots":
                        twowayfitness.main_panel.display_historical_snapshots_panel();
                        break;
                    case "donuts":
                        twowayfitness.main_panel.display_donuts_panel();
                        break;
                    case "diet":
                        twowayfitness.main_panel.display_diet_panel();
                        break;
                     default:
                 }                 
             }
             // var parts = token.split(tokenDelimiter);
             // var tabPanel = Ext.getCmp(parts[0]);
             // var tabId = parts[1];
             //
             // tabPanel.show();
             // tabPanel.setActiveTab(tabId);


         } else {
             // This is the initial default state.  Necessary if you navigate starting from the
             // page without any existing history token params and go back to the start state.
             // tp.setActiveTab(0);
             // tp.getItem(0).setActiveTab(0);
         }
     });


    // Ext.state.Manager.setProvider(new Ext.state.SessionProvider({state: Ext.appState}));

    var form_authenticity_token = app_config.form_authenticity_token;
    var settingsMenu = new Ext.menu.Menu({
        id: 'settingsMenu',
        items: [
            {
                text: 'Profile',
                icon: '/images/icons/user.png',
                menu: {
                    items: [
                        {
                            text: 'View profile ...',
                            icon: '/images/icons/user.png',
                            handler: function() {
                                twowayfitness.displayHtmlFromUrlPopup('/profiles/' + app_config.profile_id, { title: 'View Profile' });
                            }
                        },
                        {
                            text: 'Change profile ...',
                            icon: '/images/icons/user_edit.png',
                            handler: function() {
                                twowayfitness.editProfile(app_config.profile_id, form_authenticity_token);
                            }
                        }
                    ]
                }
            },
            {
                text: 'Change email address ...',
                icon: '/images/icons/email.png',
                handler: function() {
                    twowayfitness.show_change_email_address_dialog(form_authenticity_token, app_config.user_id);
                }
            },
            {
                text: app_config.paying ? 'Cancel subscription' : 'Start subscription',
                handler: function() {
                    document.location.href = app_config.paying ? '/subscriptions/cancel' : "/subscriptions/new";
                }
            }

            // ,
            // {
            //     text: 'Change password',
            //     handler: function() {
            //         window.open("https://dreamfolk.fogbugz.com/default.asp?W3");
            //     }
            // }
        ]
    });


    var helpMenu = new Ext.menu.Menu({
        id: 'helpMenu',
        items: [
            {
                text: 'About',
                icon: '/images/icons/information.png',
                handler: function() {
                    twowayfitness.displayHtmlFromUrlPopup('/client/about', { title: 'About 2Way Fitness Analytics'});
                }
            },
            {
                text: 'Help me use the application',
                icon: '/images/icons/information.png',
                handler: function() {
                    twowayfitness.displayHelp('overall');
                }
            },
            '-',
            {
                text: 'Report Bug',
                icon: '/images/icons/bug_add.png',
                handler: function() {
                    window.open("/forums/2/topics/new");
                }
            },
            '-',
            {
                text: 'Visit 2Way Fitness Website',
                icon: '/images/icons/world.png',
                handler: function() {
                    window.open("/");
                }
            }
        ]
    });

    // if(!app_config.premium) {
    //     twowayfitness.ad_panel = new Ext.ux.ManagedIframePanel({
    //         region: 'west',
    //         width: 200,
    //         defaultSrc: '/public/skyscraper_ad'
    //     });
    // }

    var center_panel = new Ext.Panel({
        region: 'center',
        layout: 'fit',
        app_config: app_config,
        // add a method which updates the body of the panel
        replace_component: function(component) {
            Ext.log('replace_component');
            twowayfitness.current_panel = component;
            if(twowayfitness.ad_panel) {
                // change ads randomly
                var rand = Math.random() * 3;
                if(rand > 1.4) {
                    twowayfitness.ad_panel.setSrc();
                }
            }

            var i;
            if(this.items) {
                while(i = this.items.last()) {
                    this.remove(i, true);
                }
            }
            this.add(component);
            // component.autoScroll = true;
            this.doLayout();
            Ext.log('leaving replace_component');
        },
        add_history: function(name) {
            twowayfitness.current_history_token = name;
            Ext.History.add(name);
        },
        display_messages_panel: function() {
            var messagesPanel = new twowayfitness.MessageMasterDetail(
                this.app_config.form_authenticity_token,
                app_config.correspondent_details
            );
            this.replace_component(messagesPanel);
        },
        display_articles_panel: function() {
            this.add_history("articles");

            var panel = new twowayfitness.ArticlesPanel({
                form_authenticity_token: this.app_config.form_authenticity_token
            });
            this.replace_component(panel);
        },
        display_quotations_panel: function() {
            this.add_history("quotations");

            var panel = new twowayfitness.QuotationsPanel({
                form_authenticity_token: this.app_config.form_authenticity_token
            });
            this.replace_component(panel);
        },
        display_coupons_panel: function() {
            this.add_history("coupons");

            var panel = new twowayfitness.CouponsPanel({
                form_authenticity_token: this.app_config.form_authenticity_token
            });
            this.replace_component(panel);
        },
        display_set_goals_panel: function() {
            this.add_history("set-goals");

            var panel = new twowayfitness.SetGoalsPanel({
            // var panel = new FooPanel({
                form_authenticity_token: this.app_config.form_authenticity_token
            });
            this.replace_component(panel);
        },
        display_home_panel: function() {
            var panel;
            
            this.add_history("dashboard");

            if(app_config.view == 'client') {
                panel = new twowayfitness.HomePanel({
                    view_name: app_config.view,
                    app_config: app_config,
                    form_authenticity_token: this.app_config.form_authenticity_token
                });
            } else {
                var url = '/' + app_config.view + '/home_fragment';
                panel = new Ext.Panel(
                    {
                        title: 'Dashboard',
                        autoLoad: {
                                url: url,
                                params: {
                                  fragment: 'true'
                                },
                                method: 'GET',
                                text: '',
                                scripts: true
                            },
                        border: false
                    }
                );
            }
            this.replace_component(panel);
        },
        display_client: function(client_id) {
            var panel = new twowayfitness.ClientPanel({
                client_id: client_id
            });
            this.replace_component(panel);
        },
        display_exercise_panel: function() {
            this.add_history("activity");

            var exercisePanel = new twowayfitness.ExercisePanel({
                form_authenticity_token: this.app_config.form_authenticity_token
            });
            this.replace_component(exercisePanel);
        },
        display_activity_templates_panel: function() {
            this.add_history("regular-activities");

            var panel = new twowayfitness.ActivityTemplatesPanel({
                form_authenticity_token: this.app_config.form_authenticity_token
            });
            this.replace_component(panel);
        },
        display_clients_panel: function() {
            var clientsPanel = new twowayfitness.ClientsPanel({
                form_authenticity_token: this.app_config.form_authenticity_token
            });
            this.replace_component(clientsPanel);
        },
        display_benchmarks_panel: function() {
            this.add_history("benchmarks");

            var benchmarksPanel = new twowayfitness.BenchmarksPanel({
                form_authenticity_token: this.app_config.form_authenticity_token
            });
            this.replace_component(benchmarksPanel);
        },
        display_charts_panel: function() {
            Ext.log('display_charts_panel 1');
            this.add_history("charts");
            Ext.log('display_charts_panel 2');
            var panel = twowayfitness.makeChartsPanel(this.app_config);
            Ext.log('display_charts_panel 3');
            this.replace_component(panel);
            Ext.log('display_charts_panel 4');
        },
        display_historical_snapshots_panel: function() {
            this.add_history("historical-snapshots");

            var panel = make_historical_snapshots_panel(this.app_config, {
                chart_panel_config: {
                  min_height: false,
                  should_log: true,
                  aspect_ratio: false
                },
                border: false,
                layout: 'fit',
                starting_period: 'weekly'
            });
            this.replace_component(panel);
        },
        display_donuts_panel: function() {
            this.add_history("donuts");

            var panel = make_donuts_panel(this.app_config, {
                border: false,
                layout: 'fit',
                height: 400,
                autoScroll: true,
                orientation: 'horizontal',
                displayLabels: true,
                starting_period: 'weekly'
            });
            this.replace_component(panel);
        },
        display_XmlSwfChart_panel: function() {
            var panel = new twowayfitness.XmlSwfChartPanel({
                form_authenticity_token: this.app_config.form_authenticity_token
            });
            this.replace_component(panel);
        },
        display_emprise_panel: function() {
            var panel = new twowayfitness.EmprisePanel({
                form_authenticity_token: this.app_config.form_authenticity_token
            });
            this.replace_component(panel);
        },
        display_fusion_panel: function() {
            var panel = new twowayfitness.FusionPanel({
                form_authenticity_token: this.app_config.form_authenticity_token
            });
            this.replace_component(panel);
        },
        display_diet_panel: function() {
            this.add_history("diet");
            var panel = new twowayfitness.DietPanel({
                form_authenticity_token: this.app_config.form_authenticity_token
            });
            this.replace_component(panel);
        }
    });

    if(app_config.panel == 'home') {
//        center_panel.display_exercise_panel();
//        center_panel.display_benchmarks_panel();
        center_panel.display_home_panel();
    } else if(app_config.panel == 'charts') {
        center_panel.display_charts_panel();
    } else if(app_config.panel == 'benchmarks') {
        center_panel.display_benchmarks_panel();
    } else if(app_config.panel == 'record_activity') {
        center_panel.display_exercise_panel();
    }

//    var center_panel = new twowayfitness.MainPanel();

//    center_panel = new Ext.Panel({
//        html: 'this is da center panel'
//    });

    twowayfitness.main_panel = center_panel;

    var logo_panel = new Ext.Panel({
        contentEl: 'header',
        border: false,
        region: 'center'
    });

    var logged_in_info_panel = new Ext.Panel({
        contentEl: 'logged_in_info',
        border: false,
        // height: 50,
        width: 300,
        // autoWidth: true,
        cls: 'white-on-black',
        region: 'east'
    });

    var menu_items = [
        {
            text: 'Dashboard',
            icon: '/images/icons/application_view_tile.png',
            handler: function() {
                if(Ext.isIE) {
                    // We refresh the whole page so as to avoid Anychart memory leaks.
                    // Possibly will be fixed in Anychart 5.1.3
                    document.location.href = '/' + app_config.view;
                } else {
                    center_panel.display_home_panel();
                }
            }
        }
    ];

    if (app_config.view == 'client') {
        menu_items = menu_items.concat([
            {
                text: 'Train',
                icon: '/images/icons/heart.png',
                // icon: '/images/phone_16.png',
                menu: {
                    items: [
                        // {
                        //     disabled: true,
                        //     text: 'Calendar'
                        // },
                        {
                            text: 'Regular Activities',
                            icon: '/images/icons/sitemap_color.png',
                            
                            handler: function() {
                                center_panel.display_activity_templates_panel();
                            }
                        }
                    ]
                }
            },
                {
                    text: 'Record',
                    icon: '/images/icons/report_edit.png',
                    menu: {
                        items: [
                            {
                                text: 'Activity',
                                icon: '/images/icons/heart.png',
                                handler: function() {
                                    if(Ext.isIE) {
                                        // We refresh the whole page so as to avoid Anychart memory leaks.
                                        // Possibly will be fixed in Anychart 5.1.3
                                        document.location.href = '/client/record_activity';
                                    } else {
                                        center_panel.display_exercise_panel();
                                    }
                                }
                            },
                            {
                                text: 'Measurements',
                                icon: '/images/icons/page_white_edit.png',
                                handler: function() {
                                    if(Ext.isIE) {
                                        // We refresh the whole page so as to avoid Anychart memory leaks.
                                        // Possibly will be fixed in Anychart 5.1.3
                                        document.location.href = '/client/benchmarks';
                                    } else {
                                        center_panel.display_benchmarks_panel();
                                    }

                                }
                            },
                            // {
                            //     text: 'Quick Measurements ...',
                            //     disabled: true,
                            //     handler: function() {
                            //     }
                            // },
                            // {
                            //     text: 'Injuries',
                            //     disabled: true,
                            //     handler: function() {
                            //     }
                            // },
                            {
                                text: 'Diet',
                                icon: '/images/icons/cup.png',
                                handler: function() {
                                    center_panel.display_diet_panel();
                                }
                            }

                        ]
                    }
                },
                {
                    text: 'Analyze',
                    icon: '/images/icons/chart_pie.png',
                    menu: {
                        items: [
                            // {
                            //     disabled: true,
                            //     text: 'Reports'
                            // },
                            {
                                text: 'Charts',
                                icon: '/images/icons/chart_curve.png',
                                handler: function() {
                                    if(Ext.isIE) {
                                        // We refresh the whole page so as to avoid Anychart memory leaks.
                                        // Possibly will be fixed in Anychart 5.1.3
                                        document.location.href = '/client/charts';
                                    } else {
                                        center_panel.display_charts_panel();
                                    }
                                }
                            },
                            {
                                text: 'Historical Snapshot',
                                icon: '/images/icons/chart_bar.png',
                                handler: function() {
                                    center_panel.display_historical_snapshots_panel();
                                }
                            },
                            {
                                text: 'Donuts',
                                icon: '/images/icons/chart_pie.png',
                                handler: function() {
                                    center_panel.display_donuts_panel();
                                }
                            }
                            // ,
                            // {
                            //     disabled: true,
                            //     text: 'Search ...'
                            // }
                        ]
                    }

                },
                {
                    text: 'Improve',
                    icon: '/images/icons/shape_align_bottom.png',
                    menu: {
                        items: [
                            // {
                            //     disabled: true,
                            //     text: 'View Goals'
                            // },
                            {
                                text: 'Set Goals',
                                icon: '/images/icons/award_star_bronze_3.png',
                                handler: function() {
                                    center_panel.display_set_goals_panel();
                                }
                            }
                        ]
                    }

                }
                // {
                //     text: 'Charts and Benchmarks',
                //     handler: function() {
                //         center_panel.display_benchmarks_panel();
                //     }
                // },
                // {
                //     text: 'Diet',
                //     handler: function() {
                //         center_panel.display_diet_panel();
                //         // this.this.add_history("main-tabs:tab3");
                //     }
                // }
            ]);

        // if(app_config.correspondent_details.correspondent_id || app_config.is_trainer) {
        //     menu_items.push(
        //         {
        //             text: 'Messages',
        //             handler: function() {
        //                 center_panel.display_messages_panel();
        //             }
        //         }
        //     );
        // }

        menu_items.push(
            {
                text: 'Network',
                icon: '/images/icons/group.png',
                menu: {
                    id: 'forumsMenu',
                    items: [
                        {
                            text: 'All Forums',
                            icon: '/images/icons/group.png',
                            handler: function() {
                                window.open("/forums");
                            }
                        },
                        // {
                        //     text: 'Announcements',
                        //     handler: function() {
                        //         window.open("/forums/1");
                        //     }
                        // },
                        {
                            text: 'The 2Way Fitness Analytics Application Forum',
                            icon: '/images/icons/group.png',
                            handler: function() {
                                window.open("/forums/2");
                            }
                        },
                        {
                            text: 'Health and Fitness Forum',
                            icon: '/images/icons/group.png',
                            handler: function() {
                                window.open("/forums/3");
                            }
                        }
                    ]
                }
            }
        );
    }
    else if (app_config.view == 'trainer') {
        menu_items = menu_items.concat([
            {
                text: 'Clients',
                handler: function() {
                    center_panel.display_clients_panel();
                }
            },
            {
                text: 'Messages',
                handler: function() {
                    center_panel.display_messages_panel();
                }
            }
        ]);
    }
    else if (app_config.view == 'content_author') {
        menu_items = menu_items.concat([
            {
                text: 'Articles/News',
                handler: function() {
                    center_panel.display_articles_panel();
                }
            },
            {
                text: 'Quotations',
                handler: function() {
                    center_panel.display_quotations_panel();
                }
            }
        ]);
    }
    else if (app_config.view == 'founder') {
        menu_items = menu_items.concat([
            {
                text: 'Coupons',
                handler: function() {
                    center_panel.display_coupons_panel();
                }
            }
        ]);
    }

    menu_items.push({
        text: 'Settings',
        // icon: '/images/icons/script_gear.png',
        icon: '/images/icons/wrench.png',
        menu: settingsMenu
    });

    menu_items.push({
        text: 'Help',
        icon: '/images/icons/information.png',
        menu: helpMenu
    });

    var roles = app_config.roles;
    if(roles.size() > 1) {
        var views_menu_items = [];
        var index = 0;
        for(index = 0; index < roles.size(); ++index) {
            views_menu_items.push({
               text: roles[index][0],
               href: '/' + roles[index][1],
               handler: function(button) {
                   document.location.href = this.href;
               },
               scope: this
            });
        }
        menu_items.push('->');
        menu_items.push({
            text: 'Views',
            menu: {
                items: views_menu_items
            }
        });
    };

    var north_panel = new Ext.Panel({
        center_panel: center_panel,
        // height: 126,
        height: 0,
        // layout: 'border',
        region: 'north',
        border: false,
        items: null,
        bbar: menu_items
    });

    var app_panel = new Ext.Panel({
       layout: 'border',
       border: false,
       region: 'center',
       items: [
           north_panel,
           center_panel
        ]
    });

    var top_panel = new Ext.Panel({
        center_panel: center_panel,
        height: 30,
        layout: 'border',
        region: 'north',
        border: false,
        items:
        [
            logo_panel,
            logged_in_info_panel
        ]
    });

    // alert('1000');

    var viewport_items = [
        top_panel,
        app_panel
    ];
    if(twowayfitness.ad_panel) {
        viewport_items.push(twowayfitness.ad_panel);
    }

    twowayfitness.viewport = new Ext.Viewport({
        display_page: function() {
          alert('display_page');
        },
        cls: 'application',
        border: false,
//        layout: 'fit',
//        items: [
//            {
//                xtype: 'panel',
//                html: "<p>viewport item</p>"
//            }
//        ]
        layout:'border',
        items: viewport_items
    });

    // just for development
    // newExerciseActivity(this.form_authenticity_token, {});
    // debug_show_article_dialog();

    // alert('checking');
    if(app_config.flash_notice != '') {
        Ext.MessageBox.alert('notice', app_config.flash_notice);
    }
    if(app_config.flash_error != '') {
        Ext.MessageBox.alert('error', app_config.flash_error);
    }
};

twowayfitness.display_client = function(client_id) {
    twowayfitness.viewport.getComponent('main-panel').display_client(client_id);
};

twowayfitness.replace_inner = function(dom_id, url) {
    var mgr = new Ext.Updater(dom_id);
    mgr.loadScripts = true;
    mgr.showLoadIndicator = false;
    mgr.update(
      {
        url: url,
        method : "GET",
        params: {
          fragment: "true"
        }
      }
    );

};



twowayfitness.LoginDialog = Ext.extend(twowayfitness.RestDialog, {
    initComponent: function() {
        var self = this;

        var fc = new twowayfitness.FieldCreator({
            data: this.data,
            object_name: 'session'
        });
         
        this.emailField = fc.text_field('email', 'Email', {
            el: 'session_email_or_login',
            value: Ext.get('session_email_or_login').getAttribute('value')
        });

        this.passwordField = fc.text_field('password', 'Password', {
            inputType: 'password',
            el: 'session_password'
        });
        
        // console.log('checked = ' + (Ext.get('remember_me').getAttribute('checked')));
        var checked = (Ext.get('remember_me').getAttribute('checked') == 'checked');
        // console.log('checked = ' + checked);
        this.rememberMeField = new Ext.form.Checkbox(
            fc.checkbox_params('remember_me', 'Automatically log me in on this computer in future', {
                checked: checked
            })
        );
        
        
        var hidden_form = Ext.get('session_1');
        var form_uri = hidden_form.getAttribute('action');
        
        var form_items = [];
        if(Ext.get('error')) {
            form_items.push(
                {
                    el: 'error',
                    width: '95%',
                    border: false
                }
            );
        }
        if(Ext.get('notice')) {
            form_items.push(
                {
                    el: 'notice',
                    width: '95%',
                    border: false
                }
            );
        }
        
        var forgot_password_html = "<p>Click <a href='#' onclick='twowayfitness.show_forgot_password_dialog(\"" + self.form_authenticity_token + "\")'>here</a> if you have forgotten your password</p>";
        forgot_password_html += "<p>Don't have an account yet? Click <a href='/new_user'>here</a> to signup for a free 30 day trial.</p>";
        form_items = form_items.concat([
                this.emailField,
                this.passwordField,
                this.rememberMeField,
                {
                    width: '100%',
                    border: false,
                    html: forgot_password_html
                }
            ]);
        
        Ext.applyIf(this, {
            standardSubmit: true,
            save_button_text: 'Login',
            submit_progress_message: 'Logging in',
            width: 500,
            title: '2Way Fitness Analytics - Login',
            REST_key: 'sessions',
            object_name: 'session',
            REST_uri: form_uri,
            // REST_container_uri: 
            modal: true,
            form_panel_config: {
                method: 'POST'
            },
            form_items: form_items
         });
         
         this.addListener({
             'cancelled': {
                 fn: function(dialog) {
                     // redirect to public home page
                     document.location.href = '/';
                 }
             },
             'submitted': {
                 fn: function(dialog, result) {
                     // twowayfitness.display_app(result.app_config);
                     document.location.href = '/client';
                 }
             }
         });

         twowayfitness.LoginDialog.superclass.initComponent.call(this);
    }
});


        

