if (!dwidgets) {
// VelociKit / DWidgets [Dynamic web widgets]
//
// Copyright (C) 2010 Niall McCarroll
// 
// Dual Licensed under the Apache License, Version 2.0 and the GNU General Public License, Version 2.0 or later
// 
// For more information see:
// 
//     http://www.apache.org/licenses/LICENSE-2.0
//     http://www.gnu.org/licenses/gpl-2.0.txt
//


var dwidgets = {};

dwidgets.loading_widgets = {};
dwidgets.loaded_widgets = {};
dwidgets.widgets_by_id = {};
dwidgets.widget_count = 0;
dwidgets.focus_widget = null;
dwidgets.stack = [];
dwidgets.base_zindex = 0;
dwidgets.was_init = false;
dwidgets.icon_height = 16;

dwidgets.getRemote = function() {
    return null;
}

dwidgets.catalogue = {
    'resize':'Resize window',
    'close':'Close window',
    'fullscreen':'Toggle fullscreen',
    'help':'Show help window',
    'tabright':'Show next tab(s)',
    'tableft':'Show previous tab(s)'
};

dwidgets.tooltip_css = { 'position':'fixed', 'top':0, 'left':0, 'display':'none', 'background-color':'white', 'z-index':'2' };

dwidgets.parameters = {};

dwidgets.configure = function(key,value) {
    this.parameters[key] = value;
}

dwidgets.load_queue = [];

dwidgets.processLoadQueue = function() {
    var queue = dwidgets.load_queue;
    
    if (queue) {
        dwidgets.load_queue = null;
        for(var i=0;i<queue.length;i++) {
            dwidgets.sload(queue[i][0],queue[i][1],queue[i][2]);
        }
    }
}

document.addEventListener("load", dwidgets.processLoadQueue, true );

dwidgets.init = function() {
    if (this.was_init) {
        return;
    }
    
    dwidgets.addStyle(dwidgets.base_css);
    this.was_init = true;
}    


dwidgets.load = function(widget_path, parameters) {
    if (dwidgets.load_queue) {
        dwidgets.load_queue.push([widget_path,parameters]);
        return null;
    } else {
        return dwidgets.sload(widget_path,parameters);
    }
}

dwidgets.sload = function(
        widget_path,
        parameters) {
    dwidgets.init();
    try {
        return dwidgets.wload( 
                    widget_path,parameters);
    } catch(ex) {
        dwidgets.log("Load error: "+widget_path+": "+ex.message,dwidgets.ERROR);
        return null;
    }
}

dwidgets.initiate_load = function(widget_name,widget_path,parameters,load_callback) {
    dwidgets.log("initiate_load:"+widget_name);
    if (!(widget_name in this.loading_widgets)) {
        this.loading_widgets[widget_name] = [];
    }
    this.loading_widgets[widget_name].push({ "callback":load_callback, "parameters":parameters });    
    if (widget_name in this.loaded_widgets) {
        return;
    }
    this.loaded_widgets[widget_name] = null;
    var head = document.getElementsByTagName("head")[0];
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = widget_path;
    head.appendChild(script);
    dwidgets.log("append script:"+widget_path);
}    

dwidgets.complete_load = function(widget_name) {
    if (widget_name in dwidgets.loading_widgets) {
        var load_list = dwidgets.loading_widgets[widget_name];
        for(var i=0; i<load_list.length; i++) {
            var callback = load_list[i]['callback'];
            var parameters = load_list[i]['parameters'];
            var jsonar = dwidgets.loaded_widgets[widget_name];
            callback(widget_name,jsonar,parameters);
        }
        delete dwidgets.loading_widgets[widget_name];
    }
}
    
dwidgets.wload = function(
        widget_path,  
        parameters) {

    var widget_id = parameters['id'];
    if (!widget_id) {
        widget_id = "dwidgets_gen_"+String(dwidgets.widget_count++);
        parameters['id'] = widget_id;
    }    
    
    parameters['z-index'] = this.base_zindex + this.stack.length;

    var last_separator = widget_path.lastIndexOf("/");
    var widget_name = widget_path;
   
    var widget_dir = "";

    if (last_separator > 0) {
        widget_dir = widget_path.slice(0,last_separator);
        widget_name = widget_path.slice(last_separator+1);
    }

    last_separator = widget_name.lastIndexOf(".");
    if (last_separator > 0) {
        widget_name = widget_name.slice(0,last_separator);
    }

    widget_name = widget_name.slice(0,widget_name.length-3);  // strip "_dw"
    
    var makepath = function(filename,dir) {
        if (dir != "") {
            return dir + "/" + filename;
        } else {
            return filename;
        }
    }

    var load_callback = function(widget_name,jsonar,parameters) {

        dwidgets.log("load callback:"+widget_name);

        var metadata_obj = null;
        var html_data = "";
        var css_data = "";
        var js_data = null;
        var apyax_js = "";
        var obj = null;

        var js_name = widget_name + ".js";
        var html_name = widget_name + ".html";
        var metadata_name = widget_name + ".json";
        var css_name = widget_name + ".css";
        var apyax_name = "apyax.js";
        
        if (jsonar[metadata_name]) {
            metadata_obj = dwidgets.parseJSON(jsonar[metadata_name]);
        }
      
        var settings = {};
        
        if (metadata_obj != null) {
	        if ('defaults' in metadata_obj) {
		        settings = metadata_obj['defaults'];
	        }
        }

        dwidgets.merge_properties(settings,parameters);

        if ('_factory_' in jsonar) {
            js_data = jsonar['_factory_']();
        }
        
        if (jsonar[html_name]) {
            html_data = dwidgets.substituteParameters(jsonar[html_name],settings);
        }

        if (jsonar[css_name]) {
            css_data = dwidgets.substituteParameters(jsonar[css_name],settings);
        }

        if (jsonar[apyax_name]) {
            apyax_js = jsonar[apyax_name];
        } 
       
        if (!js_data && html_data == '') {
        	throw "could not load javascript or html for widget";
        }
        
        var obj = null;
        if (js_data) {
            obj = js_data;
        } else {
            obj = dwidgets.createDummyWidget();
        }

        var widget = {};
        widget.settings = {};
        widget.settings.widget_path = widget_dir;
        widget.settings.widget_name = widget_name;
        widget.settings.widget_id = widget_id;
            
        dwidgets.assignIds(widget_id,widget);    
        
        var htmlinsert = '';
       
        if (css_data != '') {
           dwidgets.addStyle(css_data);
        }
        
        dwidgets.setupState(widget);
        htmlinsert += dwidgets.loadHtml(widget_id,html_data,settings,widget);
        if (htmlinsert != '') {
           var holder = document.getElementById(widget_id);
           if (!holder) {
                holder = document.createElement('div');
                holder.setAttribute('id',widget_id);
                document.body.appendChild(holder);
           }
           holder.innerHTML = htmlinsert;
        }   

        dwidgets.endow(widget_id,widget_name,widget_dir,widget);

        // add buttons
        if (widget.settings.closable) {
            widget.addButton({
                    'id':widget.ids.close_id,
                    'image_url':dwidgets.close_img,
                    'tooltip':dwidgets.catalogue['close'],
                    'toggle':false,
                    'location':'top'},
                    function(event) {
                        widget.close();        
                        dwidgets.platform.stopPropagation(event);
                    });
        }  
        
        if (widget.settings.fullscreen) {
            widget.addButton({
                    'id':widget.ids.fullscreen_id,
                    'image_url':dwidgets.fullscreen_img,
                    'tooltip':dwidgets.catalogue['fullscreen'],
                    'toggle':true,
                    'location':'top'},
                    function(event) {
                        widget.focus();
                        widget.toggleFullscreen();
                        dwidgets.platform.stopPropagation(event);
                    });
        }
        
        if (widget.settings.help_widget_path) {
            widget.addButton({
                    'id':widget.ids.help_id,
                    'image_url':dwidgets.help_img,
                    'tooltip':dwidgets.catalogue['help'],
                    'toggle':false,
                    'location':'top'},
                    function(event) { 
                        widget.help(event); 
                    });
        }

        dwidgets.setCallbacks(widget);
        dwidgets.initTabs(widget);
        
        dwidgets.setEventHandlers(widget);
        dwidgets.platform.computeDimensions(widget);
        
        var status_element = document.getElementById(widget.ids.status_id);
        if (status_element) {
            status_element.style.top = widget.dimensions['header_height'] + widget.dimensions['tabs_height'];
        }
        
        widget.obj = obj;
        obj.dwidget = widget;
            
        dwidgets.widgets_by_id[widget_id] = widget;
        
        var h = widget.dimensions['height'];
        if (h) {
            widget.setHeight(h);
        }
        var w = widget.dimensions['width'];
        if (w) {
            widget.setWidth(w);
        }
        
        dwidgets.stack.push(widget);
                   
        obj.init(widget,settings,jsonar);

        if (widget.tabs.length > 0) {
           widget.selectPanel(widget.tabs[0]['key']);
        }
        widget.focus();
        dwidgets.fireWidgetLoadEvent(widget);
    }                       

    var jsonar = null;
    if (widget_name in this.loaded_widgets) {
        jsonar = this.loaded_widgets[widget_name];        
        load_callback(widget_name,jsonar,parameters);
    } else {
        this.initiate_load(widget_name,widget_path,parameters,load_callback); 
    }
    
}

dwidgets.focus = function(widget) {
    var shuffled = false;
    for(var i=0; i<this.stack.length; i++) {
        if (widget == this.stack[i]) {
            var shuffle = this.stack.slice(0,i);
            shuffle = shuffle.concat(this.stack.slice(i+1));
            this.stack = shuffle.concat([widget]);
            shuffled = true;
            break;
        }
    }
   
    for(var i=0; i<this.stack.length; i++) {
        var w = this.stack[i];
        var ele = document.getElementById(w.ids.window_id);
        var updated_zindex = this.base_zindex + i;
        w.state.zindex = updated_zindex;
        if (ele) {
            ele.style.zIndex = String(updated_zindex);
        } 
    }
    dwidgets.focus_widget = widget;
}

dwidgets.close = function(widget) {
    for(var i=0; i<this.stack.length; i++) {
        if (widget == this.stack[i]) {
            var shuffle = this.stack.slice(0,i);
            this.stack = shuffle.concat(this.stack.slice(i+1));
            break;
        }
    }
    if (widget == this.focus_widget) {
        if (this.stack.length > 0) {
            this.focus_widget = this.stack[this.stack.length-1];
        } else {
            this.focus_widget = null;
        }
    }
    delete dwidgets.widgets_by_id[widget.getId()];
}

dwidgets.createDummyWidget = function() {
    return { "init": function(widget,parameters) {} };
}

dwidgets.getWidget = function(id) {
    return dwidgets.widgets_by_id[id];
}

dwidgets.setupState = function(widget) {
    widget.state = {};
    widget.state.fullscreen = false;
    widget.state.statusfadelevel = 100;
    widget.state.statusfader = null;
    widget.state.current_panel = 0;
    widget.state.tab_scroll = 0;
    widget.state.buttoncount = 0;
}

dwidgets.assignIds = function(widget_id,widget) {
    widget.ids = {};
    widget.ids.header_id = widget_id + '_header';
    widget.ids.footer_id = widget_id + '_footer';
    widget.ids.status_id = widget_id + '_status';
    widget.ids.status_text_id = widget_id + '_status_text';
    widget.ids.status_progress_id = widget_id + '_status_progress';
    widget.ids.window_id = widget_id + '_window';
    widget.ids.content_id = widget_id + '_content';
    widget.ids.tabcontent_id = widget_id + '_tabcontent';
    widget.ids.title_id = widget_id + '_title';
    widget.ids.topright_id = widget_id + '_topright';
    widget.ids.bottomleft_id = widget_id + '_bottomleft';
    widget.ids.nextbutton_id = widget.ids.topcorner_id;
    widget.ids.help_id = widget_id + '_help';
    widget.ids.resize_id = widget_id + '_resize';
    widget.ids.fullscreen_id = widget_id + '_fullscreen';
    widget.ids.close_id = widget_id + '_close';
    widget.ids.tabs_id = widget_id + '_tabs';
    widget.ids.tabs_outer_id = widget_id + '_tabs_outer';
    widget.ids.tabs_middle_id = widget_id + '_tabs_middle';
    widget.ids.tabs_inner_id = widget_id + '_tabs_inner';
    widget.ids.tabs_left_id = widget_id + '_tabs_left';
    widget.ids.tabs_right_id = widget_id + '_tabs_right';
}
dwidgets.setCallbacks = function(widget) {        

    var titleTxt = document.getElementById(widget.ids.title_id);
    if (titleTxt) {
        dwidgets.setFocusHandler(titleTxt);
    }
   
    var header = document.getElementById(widget.ids.header_id);
    if (header) {
        dwidgets.platform.setHandler(header, function(event) {
            widget.focus();
            dwidgets.platform.stopPropagation(event);
        });
    }
         
    if (widget.settings.showframe && widget.settings.movable) {
        var title = document.getElementById(widget.ids.title_id);
        
        if (title) {
            title.onkeydown = function(event) {
            
                widget.dragging.inDrag = true;
                widget.dragging.dragStartX = 0;
                widget.dragging.dragStartY = 0;
                
                var off_x = 0;
                var off_y = 0;
                
                var code = event.charCode || event.keyCode;
                if (code == 37) {
                    off_x -= 10;
                } else if (code == 38) {
                    off_y -= 10;
                } else if (code == 39) {
                    off_x += 10;
                } else if (code == 40) {
                    off_y += 10;
                }
                
                widget.dragging.dragCurrentX = off_x;
                widget.dragging.dragCurrentY = off_y;
                widget.reposition(true);
                widget.dragging.inDrag = false;
            
                dwidgets.platform.stopPropagation(event);
            }
        
            title.onmousedown = function(event) {
                widget.focus(); 
                widget.dragging.inDrag = true;
                widget.dragging.dragStartX = event.clientX;
                widget.dragging.dragStartY = event.clientY;
                
                widget.dragging.oldmousemove = window.onmousemove;
                widget.dragging.oldmouseup = window.onmouseup;
                
                window.onmousemove = function(event) { 
                    if (widget.dragging.inDrag) {
                        widget.dragging.dragCurrentX = event.clientX;
                        widget.dragging.dragCurrentY = event.clientY;
                        widget.reposition();
                        dwidgets.platform.stopPropagation(event);
                    }
                }; 
                
                window.onmouseup = function(event) { 
                    widget.dragging.dragCurrentX = event.clientX;
                    widget.dragging.dragCurrentY = event.clientY;
                    widget.reposition(true);
                    widget.dragging.inDrag = false;
                    window.onmousemove = widget.dragging.oldmousemove;
                    window.onmouseup = widget.dragging.oldmouseup;
                    dwidgets.platform.stopPropagation(event);
                };
                
                dwidgets.platform.stopPropagation(event);
                
            };
        }    
    }
                    
    if (widget.settings.showframe && widget.settings.resizable) {
 
        var resizer = document.getElementById(widget.ids.resize_id);
        
        if (resizer) {
            this.configureTooltip(widget.ids.resize_id);
            resizer.onkeydown = function(event) {
            
                widget.dragging.inDrag = true;
                widget.dragging.dragStartX = 0;
                widget.dragging.dragStartY = 0;
                
                var off_x = 0;
                var off_y = 0;
                
                var code = event.charCode || event.keyCode;
                if (code == 37) {
                    off_x -= 10;
                } else if (code == 38) {
                    off_y -= 10;
                } else if (code == 39) {
                    off_x += 10;
                } else if (code == 40) {
                    off_y += 10;
                }
                
                widget.dragging.dragCurrentX = off_x;
                widget.dragging.dragCurrentY = off_y;
                widget.resize(true);
                widget.dragging.inDrag = false;
            
                dwidgets.platform.stopPropagation(event);
            }
            
            resizer.onmousedown = function(event) { 
                var btn = document.getElementById(widget.ids.resize_id);
                dwidgets.clearTooltip(widget.ids.resize_id);
                widget.focus();
                widget.dragging.inDrag = true;
                widget.dragging.dragStartX = event.clientX;
                widget.dragging.dragStartY = event.clientY;
                
                widget.dragging.oldmousemove = window.onmousemove;
                widget.dragging.oldmouseup = window.onmouseup;
                
                window.onmousemove = function(event) { 
                    if (widget.dragging.inDrag) {
                        widget.dragging.dragCurrentX = event.clientX;
                        widget.dragging.dragCurrentY = event.clientY;
                        widget.resize();
                        dwidgets.platform.stopPropagation(event);
                    }
                };
                
                window.onmouseup = function(event) { 
                    widget.dragging.dragCurrentX = event.clientX;
                    widget.dragging.dragCurrentY = event.clientY;
                    widget.resize(true);
                    widget.dragging.inDrag = false;
                    window.onmousemove = widget.dragging.oldmousemove;
                    window.onmouseup = widget.dragging.oldmouseup;
                    dwidgets.platform.stopPropagation(event);
                };
                
                dwidgets.platform.stopPropagation(event);
            }
            dwidgets.setFocusHandler(resizer);
        }    
    }
}        


dwidgets.endow = function(widget_id,widget_name,widget_path,widget) {

    widget.dragging = {};
    widget.dragging.inDrag = false;
    
    widget.dragging.dragStartX = 0;
    widget.dragging.dragStartY = 0;
    widget.dragging.dragCurrentX = 0;
    widget.dragging.dragCurrentY = 0;
    widget.dragging.oldmousemove = null;
    widget.dragging.oldmouseup = null;


    
   
    
    
    widget.focus = function() {
        /*
        if (dwidgets.focus_widget && dwidgets.focus_widget == this) {
            return;
        } 
        var recieve_focus = document.getElementById(this.ids.window_id);
        if (!recieve_focus) { return; }
        if (dwidgets.focus_widget) {
            dwidgets.focus_widget.defocus();
        }
        recieve_focus.style.zIndex = '1';
        
        dwidgets.focus_widget = this;
        */
        dwidgets.focus(this);
    }
    
    
    widget.getContent = function() {
        return document.getElementById(this.ids.content_id);
    }
    
    widget.reposition = function(complete) {
        // don't allow moving when in fullscreen mode
        if (this.state.fullscreen) {
            return;
        }
            
        var window_div = document.getElementById(this.ids.window_id);
        
        // recompute new coordinates
        var top = this.dimensions['top'] + (this.dragging.dragCurrentY - this.dragging.dragStartY);
        var left = this.dimensions['left'] + (this.dragging.dragCurrentX - this.dragging.dragStartX);
        
        // don't allow the window to be dragged offscreen!
        if (top < 0) { top = 0; }
        if (left < 0) { left = 0; }
        
        window_div.style.top = String(top)+"px";
        window_div.style.left = String(left)+"px";
        if (complete) {
            this.dimensions['top'] = top;
            this.dimensions['left'] = left;
        }
    }

    widget.repaint = function() {
        dwidgets.platform.computeDimensions(this);
        var w = this.dimensions['width'];
        if (w) {
            this.setWidth(w);
        }        
        var h = this.dimensions['height'];
        if (h) {
            this.setHeight(h);
        }
    }

    widget.resize = function(complete) {
        // don't allow resizing when in fullscreen mode
        if (this.state.fullscreen) {
            return;
        }
        
        var window_div = document.getElementById(this.ids.window_id);
        var w = this.dimensions['width'];
        var h = this.dimensions['height'];
        if (h) {
            h = this.setHeight(h + (this.dragging.dragCurrentY - this.dragging.dragStartY));
            if (complete) {
                this.dimensions['height'] = h;
            }
        }
        if (w) {
            w = this.setWidth(w + (this.dragging.dragCurrentX - this.dragging.dragStartX));
            if (complete) {
                this.dimensions['width'] = w;
            }
        }
    }


    
    
    widget.toggleFullscreen = function() {
        var fullscreenBtn = document.getElementById(widget.ids.fullscreen_id);
        var w = document.getElementById(this.ids.window_id);
        if (!this.state.fullscreen) {    
            // expand window to fullscreen
            
            w.style.position = 'absolute';
            w.style.top = '0px';
            w.style.left = '0px';
            
            fullscreenBtn.ariaPressed = true;
            
            // hide resize button in fullscreen
            var resizer = document.getElementById(this.ids.resize_id);
            if (resizer) {
                resizer.style.display = 'none';
            }
            
            var frame_size = (2*this.dimensions.frame_margin)+(2*this.dimensions.frame_width);
            this.setWidth(window.innerWidth-dwidgets.platform.getVScrollBarWidth()-frame_size);
            this.setHeight(window.innerHeight-dwidgets.platform.getHScrollBarWidth()-frame_size);
            this.state.fullscreen = true;
            this.dimensions['scrollTop'] = document.body.scrollTop;
            this.dimensions['scrollLeft'] = document.body.scrollLeft;
            
            document.body.scrollTop = 0;
            document.body.scrollLeft = 0;
        } else {
            // contract window from fullscreen
            
            w.style.top = String(this.dimensions['top'])+'px';
            w.style.left = String(this.dimensions['left'])+'px';
            w.style.position = this.settings.position;
            
            fullscreenBtn.ariaPressed = false;
            
            // reveal resize button (if configured) when leaving fullscreen
            var resizer = document.getElementById(this.ids.resize_id);
            if (resizer) {
                resizer.style.display = 'block';
            }
            
            this.setWidth(this.dimensions.width);
            this.setHeight(this.dimensions.height);
            this.state.fullscreen = false;
            document.body.scrollTop = this.dimensions['scrollTop'];
            document.body.scrollLeft = this.dimensions['scrollLeft'];
        }
    }
    
    
    widget.setHeight = function(h) {
        var window_div = document.getElementById(this.ids.window_id);
        var content_div = document.getElementById(this.ids.content_id);
        if (widget.tabs.length > 0) {
            content_div.style.height = 'auto';
            content_div = document.getElementById(this.ids.tabcontent_id);
        }
        
        if (!h) {
            window_div.style.height = 'auto';
            content_div.style.height = 'auto';
            return null;
        }    
        
        var min_height = this.dimensions['min_height'];
        if (min_height && h < min_height) {
            h = min_height;
        }
        
        var header_height = this.dimensions['header_height'];
        var tabs_height = this.dimensions['tabs_height'];
        var footer_height = this.dimensions['footer_height'];
        var content_padding = this.dimensions['content_padding'];
        var frame_width = this.dimensions['frame_width'];
        var frame_margin = this.dimensions['frame_margin'];

        var chrome_height = header_height+footer_height+tabs_height+(2*content_padding); // +(2*frame_width)+(2*frame_margin);
        
        var content_height = h-chrome_height;
        if (content_height < 0) {
            content_height = 0;
            h = chrome_height;
        }
        
        window_div.style.height = String(h)+"px";
        content_div.style.height = String(content_height)+"px";
               
        return h;
    }
    
    
    widget.setWidth = function(w) {
        var window_div = document.getElementById(this.ids.window_id);
        if (!w) {
            window_div.style.width = 'auto';
            return null;
        }
        var min_width = this.dimensions['min_width'];
        if (min_width && w < min_width) {
            w = min_width;
        }
        
        window_div.style.width = String(w)+"px";
        
        this.reconfigureTabs(w);
        return w;
    }
        
    
    widget.getName = function() {
        return widget_name;
    }
    
    
    widget.getId = function() {
        return widget_id;
    }

    
    widget.log = function(logtxt,severity) {
        if (!severity) { severity = dwidgets.INFO; }
        if (severity >= this.loglevel) {
            var src = "[name="+this.getName()+",id="+this.getId()+"]";
            dwidgets.log(logtxt,severity,src); 
        }
    }

    widget.loglevel = dwidgets.WARNING;

    widget.setLogLevel = function(newloglevel) {
        if (newloglevel != dwidgets.DEBUG &&
                newloglevel != dwidgets.INFO &&
                newloglevel != dwidgets.WARNING &&
                newloglevel != dwidgets.ERROR) {
            return;
        }
        this.loglevel = newloglevel;
        if (newloglevel < dwidgets.loglevel) {
            dwidgets.setLogLevel(newloglevel);
        }
    }

    
    widget.setTitle = function(title_html) {
        document.getElementById(this.ids.title_id).innerHTML = title_html;
        this.displayHeader(true);
    }

    
    widget.setContent = function(content_html) {
        document.getElementById(this.ids.content_id).innerHTML = content_html;
        this.repaint();
    }

    
    widget.displayHeader = function(enable) {
        document.getElementById(this.ids.header_id).style.display = enable?'block':'none';
        widget.repaint();
    }

    
    widget.displayFooter = function(enable) {
        document.getElementById(this.ids.footer_id).style.display = enable?'block':'none';
        widget.repaint();
    }
    
    
    widget.setProgress = function(msg,progress,duration) {
        this.setStatus(msg,duration);
        var w = (this.dimensions['status_width']-10) * (progress/100);
        var prog = document.getElementById(this.ids.status_progress_id);
        prog.style.width = w;
        prog.ariaValuenow = progress;
        prog.ariaValuetext = String(progress)+"%";
    }

    
    
    widget.setStatus = function(msg,duration) {
        // clear an existing interval timer for fading status
        if (this.state.statusfader) {
            clearInterval(this.state.statusfader);
            this.state.statusfader = null;
        }
        var status = document.getElementById(this.ids.status_id);
        var status_text = document.getElementById(this.ids.status_text_id);
        
        if (duration==null) {
            duration = 5000; // 5 seconds
        }
        
        if (status && status_text) {
            if (!msg) {
                status.style.display = 'none';
                return;
            }
            
            status_text.innerHTML = '&nbsp;'+msg;
            dwidgets.platform.setOpacity(status,100);
            status.style.display = 'block';
            var hider = function() {
                status.style.display = 'none';
            }
            widget.state.statusfadelevel = 100;
           
            if (duration > 0) {
                widget.state.statusfader = window.setInterval(function(){ widget.statusFade(); },duration/100);
            }
            
            status.onclick = function(event) {
                widget.state.statusfadelevel = 0;
                widget.statusFade();
                dwidgets.platform.stopPropagation(event);
            }    
            
        } 
    }
    
    widget.statusFade = function() {
        var status = document.getElementById(this.ids.status_id);
        if (!status) { return; }
        this.state.statusfadelevel -= 1;
        if (this.state.statusfadelevel == 0) {
            status.style.display = 'none';
            dwidgets.platform.setOpacity(status,100);
            clearInterval(this.state.statusfader);
            this.state.statusfader = null;
        } else {
            if (this.state.statusfadelevel <50) {
                dwidgets.platform.setOpacity(status,this.state.statusfadelevel*2);
            }
        }
    }
    

    widget.close = function() {
        var parent_div = document.getElementById(widget_id);
        if (parent_div) {
            dwidgets.removeDirectElementsByName(parent_div,'');
        }
        dwidgets.close(this);
    }
    
    widget.load = function() {
        var crumbs = document.cookie.split(';');
        for(var i=0;i < crumbs.length;i++) {
            var crumb = crumbs[i];
            while (crumb.charAt(0)==' ') {
                crumb = crumb.substring(1,crumb.length);
            }
            if (crumb.indexOf(widget_id) == 0) {
                try {
                    var crumbvalue = crumb.substring(widget_id.length+1,crumb.length);
                    var jsonstr = dwidgets.decode(crumbvalue);
                    var data = dwidgets.parseJSON(jsonstr);
                    return data;
                } catch(ex) {
                    return null;
                }
            }
        }
        return null;   
    }
    
    widget.save = function(data) {
        var jsonstr = dwidgets.createJSON(data);
        var crumbvalue = dwidgets.encode(jsonstr);
        var crumb = widget_id + "=" + crumbvalue + ";";
        document.cookie = crumb; 
    }
    
    widget.fetchUrl = function(url) {
        var wurl = "";
        if (widget_path) {
            wurl = widget_path + "/";
        }
        wurl += url;
       
        return dwidgets.fetch_url(wurl);
    }

    widget.loadWidget = function(path,wparameters) {
        adjusted_path = path;
        if (this.settings.widget_path != "") {
            adjusted_path = this.settings.widget_path + "/" + path;
        }
        return dwidgets.sload(adjusted_path,wparameters);
    }

    var content_id = widget.ids.content_id;
    var tabcontent_id = widget.ids.tabcontent_id;    
    widget.$ = function(tag) {
        var nodes = [];        
        var e1 = document.getElementById(content_id);
        var result1 = e1 ? e1.getElementsByTagName(tag) : [];
        for(var i=0; i<result1.length; i++) {
            nodes.push(result1[i]);
        }
        var e2 = document.getElementById(tabcontent_id);
        var result2 = e2 ? e2.getElementsByTagName(tag) : [];
        for(var i=0; i<result2.length; i++) {
            nodes.push(result2[i]);
        }
        return dwidgets.arrayWrap(nodes);
    }

    widget.addButton = function(button_properties, handler) {
  
        var id = button_properties['id'];
        var img_url = button_properties['image_url'];
        var html = button_properties['html'];
        var tooltip_text = button_properties['tooltip'];
        var is_toggle = button_properties['toggle'];
        var location = button_properties['location'];

        if (!location) {
            location = 'top';
        }
  
        var pos = this.state.buttoncount;

        if (!id) {
            id = this.ids.widget_id + "_btn" + String(pos);
        }    

        var buttonbox = null;
        if (location == 'bottom') { buttonbox = document.getElementById(this.ids.bottomleft_id); }
        if (location == 'top') { buttonbox = document.getElementById(this.ids.topright_id); }

        var button = null;
        if (img_url) {
            button = document.createElement('img');
            button.setAttribute('src',img_url);
        } else if (html) {
            button = document.createElement('span');
            button.innerHTML = html;   
        } else {
            return null;
        }
     
        button.style.border = '2px solid transparent';
        button.style.width='auto'; 
        button.style.padding='2px';
        button.style.cursor='default';
        button.style.verticalAlign='middle';

        button.setAttribute('role','button');
        button.setAttribute('id',id);
        button.setAttribute('tabindex','0');
        
        if (is_toggle) {
            button.setAttribute('aria-pressed','false');
        }

        if (buttonbox.firstChild) {
            buttonbox.insertBefore(button,buttonbox.firstChild);
        } else {
            buttonbox.appendChild(button);
        }

        if (tooltip_text) {
            var tooltip = document.createElement('span');
            tooltip.style.position = 'fixed';
            tooltip.style.top = '0px';
            tooltip.style.left = '0px'; 
            tooltip.style.display = 'none';
            tooltip.style.backgroundColor = 'white';
            tooltip.style.zIndex = '2';
                
            var tooltip_id = dwidgets.getTooltipId(id);
            tooltip.setAttribute('id',tooltip_id);
            tooltip.innerHTML = tooltip_text;  
            buttonbox.appendChild(tooltip);
            dwidgets.configureTooltip(id);
        }

        this.state.buttoncount += 1;

        if (handler) {
            dwidgets.platform.setHandler(button, handler);
        }

        dwidgets.setFocusHandler(button);

        var container = (location == 'top') ?
                document.getElementById(this.ids.header_id) : document.getElementById(this.ids.footer_id);
        if (container) {
            container.style.minHeight = String(dwidgets.icon_height+16)+'px';
        }
        if (location == 'top') {
            this.displayHeader(true);
        } else {
            this.displayFooter(true);
        }
        return button;        
    }

    widget.help = function(event) { 
        
        var left = event.clientX;
        var top = event.clientY;
        var help_parameters = { 
            'width':200, 'height':200, 
            'top':top, 'left':left, 
            'mode':'window',
            'showframe':true, 'closable':true, 'movable':true, 'fullscreen':true };
        dwidgets.merge_properties(help_parameters,this.settings.help_widget_parameters);
        widget.loadWidget(
            this.settings.help_widget_path,
            help_parameters);
        dwidgets.platform.stopPropagation(event);
    }

    
}

dwidgets.DEBUG      = 0;
dwidgets.INFO       = 1;
dwidgets.WARNING    = 2;
dwidgets.ERROR      = 3;

dwidgets.loglevel = dwidgets.INFO;

dwidgets.setLogLevel = function(newloglevel) {
    if (newloglevel != dwidgets.INFO &&
            newloglevel != dwidgets.INFO &&
            newloglevel != dwidgets.WARNING &&
            newloglevel != dwidgets.ERROR) {
        return;
    }
    dwidgets.loglevel = newloglevel;
}

dwidgets.log = function(logtxt,severity,src) {
    var severitytxt = '';
    if (!severity) {
        severity = dwidgets.INFO;
    }                
    switch(severity) {
        case dwidgets.DEBUG: 
            severitytxt = "DEBUG";
            break;
        case dwidgets.INFO:
            severitytxt = "INFO";
            break;
        case dwidgets.WARNING:
            severitytxt = "WARNING";
            break;
        case dwidgets.ERROR:
            severitytxt = "ERROR";
            break;
        default:
            return;
    }
    if (src || severity >= dwidgets.loglevel) {
        var errortxt = "[dwidgets "+severitytxt+"]";
        if (src) {
            errortxt += "["+src+"]";
        }
        errortxt += logtxt;
        setTimeout(function() { throw new Error(errortxt); }, 0);
    }
}


dwidgets.help_img='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAThSURBVDiNjZRrbFRFGIafmTPntm2Bgm2XO7tsLZctd+QqAQkksiAmGhISQ1QiKCgmRqReEn8YZUlI0IjIH/gBURMTIyFsAMFyEaQQJZSWUuhlWwqUNkUotN2223OOP3bboIA4yZv5M/PMl3m/9xOe5/GkFYhEDSAM3ANq4rGiJ14SjwMHItEZwDpgNjAS6ARkWpeBE8DWeKzo5v8Cp6vbDKwNh/wZcyaOJBzyU5jvB6C8uomy6kZOX6hLllc3JYC34rGi7/8THIhExwIx21S5m15bkLF4Vj7F52oor22iorYZKSSFIT/hUB7zpwY49PtVoruPtSW6kieAFfFYUcdD4EAkagKV44J5I7/58EVxrryBrXt/ozvpoJSGpkmklAghEAIybYN3V85mfDCHd6L7u8qqG/fGY0VvPAq8zbb0NQe3v+7buuckJ87XMX38cF5aOJ4JIT852Rkkexwab7dx6EwV+09W4rgeC6YGWLVkEs+v39We6Eoui8eKjvWB00YVf7ZusU/XNT7fdRzT0Nm46llWLCp8pLk//nqJPbFSHNflvZUzabnbzsdfH2z2PEbHY0VtMn3u7UkFg33PPRNi23enMU0d09TxgMMl1Xyys5i1Ww7ww5FLfeCF0wLYtoltGew+cIHFM/OZPGZoBhAh3ToAs+dODnCkpIoex8PQFaahs/dQGTt//pOr1+/QlnA4XXa9D6w0ic82sC0DxxOcq7jJvGmjfcBMABmIRC1gxIT8wVTEm9F1DUNXGIZCVxqmoWOZBj7bYPXSSX3gi7Ut2JaJZRlYpkFd410KQ34hpZjXW/FEIFGY76eyrgWlNHRd9ckwUt+ydvlkJj+dB8C1pnvESuqwLQPbNDBNnfqm+4wdlYPneWMBFNAGSCEEUpMoTUNpEj39gKErXpgbYtqYVEDqm+6z9+hVdENHSImUAgToSqVaEdHZW/FlQFXUNhMO5iGlRNNSUpqGUhoTQ7l9X1BcehNd17EtA8vUMQwdXSlGD8vm6rUWhBQXAFQ8VuQGItHKippbE8cFcym5dAMpU2HQpEDTJDv2XcRnG1iWkYLaBj2OiwAcxyWpJMEh/amobnQdxz35YFecOFVa78yfGsAyVCo5kE6Z4JVFY1gTCfPqogKysyx8tomuNKQmEVJgG4rCYA7FZ6s6gZIHwVtKSusTZ8sbWL18CgAe4OHheR652T78A33kDrDBc0l0dtPT4+C6Lp7rsXRWkFMX6r3zlTcqgMN94PToW//pt790zAwPY0rBYFzXxXU8XNdNvZJeXd09JBJddHYl6U72UDCsPwF/Fh99FetwHHdF76z+x3QLLo0emVE4ct6295cZ56/c4qfjlQhNwzJ7jVIopSGFQGmCxVOHE/D3Y/3mfR1/XGrYWHtg045e1r/HZqYQYntWhvnyFxuWZEwfN5TzV25xrfk+N1ra0XWNUf4BjMjLojAwiDNlDd6mLw90tHd0f/Ag9CEwKcMy/bPejNjZI3bMmRL0zZ8WMsOj80T+iEEAVDf8RXnNLffomSvJs6U1tberjm1orT52GWj1PK/tkWAhRDYwEBikZ+QM6ReYu9DIzAmbWU8VoDJyBI7rdLY2J1obq7pbGy+31hw/Dd5t4A5wG7jpeV7icRUrwAZ8QFZa/YDMtNkJUmm9n97b0+r0HoD9DcIi5yD3PoxAAAAAAElFTkSuQmCC';

dwidgets.fullscreen_img='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1gMQEww2YmW/YQAAADV0RVh0Q29tbWVudAAoYykgMjAwNCBKYWt1YiBTdGVpbmVyCgpDcmVhdGVkIHdpdGggVGhlIEdJTVCQ2YtvAAACjklEQVQ4y7WVTUhUURTHf+fMK5m0dAZCwo8MFBGEVkFYpBtB+gKL2kQtWhhkYi2SIFq0MEaHlgUJBS2CQrBFn2ZRtKloK0mgDNoXZeZHSs44zmvx7nvzxmamFnZ49517373nf77vg/9EAhDp7b4GtK0SZt+5rvMnMMD2alGkt9sGsPyqtrXdylD9pKcli4+CIIBNc9ejjK23fUe8uWbzRVU8UDEvQRBxIEVARHga3Y2qZI2HZgNdH1zDmauvEVEQRVBQAyzqjWORF6wrsLACkh9YBAYjLWwKB6kuK+beq3HHOgUVF9jx4PbzUeqrwpSGggxF9xJYYXkG8FDvHkSUK507qdhYRGkoyPsPc46FiBNfEUY/zVFdVkJNeTHXzzaBKM8u78tvsZjktO7awobCAuo2l6AIqBirldryEkJFazncVI0gqOC45SMrE1gxCUcF6qvCjjZXqW0SKUJtZdgkV7AF1CYfsPjaxjVCnMcG2+gVn3WOQvmjDKyVocBUqbOwfbWb3nfXnpymj+aIsZt1R3BkYgYhnThEvVqe+DbvzFW9MswD7BxSUfoevGNyZpGxz7PeNzHKP07OM7uQYODlWDo0kqfcGk/fRUQ5dPExI+PTDMd+UFMR8gRd6ypLixmOTfFm5CsHLjwEYMep/tzAtg2NnQNM/4wT+zJHx8GtXnjcUnRr+WhzHcOxKb7P/qKhvf/vLZ2yIb60zP3I/oymEFFf9zljMNrKcsrOeh1rrku1ob0fdZsCTTePUYAo20/eySUesHJde/9Cec6LBZBMJm/0RC8dX43fRyKeuOnrMQJAECg03DLxt3xz9eUkZcYSkDQ8ASwCC0BcViTSBRIfkPh4wAdsA8s+njJ8CUj9BrtK5as85v9RAAAAAElFTkSuQmCC';

dwidgets.close_img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1QoRFysAQytH+wAABIVJREFUOMuNlVtoVEcYx39zzm72kmziDbW1akhbTQ0W3GbFGA0WlVIKgb5ExAaUtthCKbZUi9EHlcR6gfrQh0L7FqFQQRCprbYJpSjagqYYc9G0SZvburtJ3N3s2es5c6YPu67GROnAxzzMzG+++S7/ETxjHIclgHjGlkgL2HMtPPXQSfhCwacC5FzrCjQB5yW80wLqf4FPwunqhoaPtjY1uXWXC5QqmrJtsCysVIqf29szg31930vY8yR8FvgEnKmur/9g286d7nhfH6nxcbBtsO08VEqUlLgXLWL+mjVcOXcuM9Tb+93n8O7jHP0J6FfVdXXvb9u1yxPv6yMdCiFE4W6lHs1KYRkGlmFQU1/viMbj1a+Fw8s74IdZ4BPw9epAYM/25mZPrKeHdCRCzONBKoXLtmeEwxCC6ZISHLEYZjLJmvXrnVOxWE3txMTSDvipCD4B3672+5u3797tid6+TToSIep2I6qqyJgmdjZbhCeEIOHz4V27lng4jCMWw0qleMXvd0YTibW1ExMLO+CKBiAcjve2Nzd7ol1dZEIhckqRtSwW7NjB0n37SPl8TAuBoWkYZWWsam1lxd69mEKQVgojEuHB4CBbt2zxaB7PJwAagK7raEKQvn8fCk/3WhahM2cQQrDswAFS5eUYpaW83NqKs7SUvw4dwm2auAClFEY4jK5pqEIuHMW6VCqfeSFAKSpsm/jUFMHTp1lx8CAvHj+OrmloSjFw+DAEg/hyOZRSKKWwlQIpi0nWHlW8KpbTw5Iqz+VgcpKpCxdwejw4vV4iFy9ijY0VobZtYz+Ey0e95HgcjG3nPdfy9yV0Hel2s7ixEU0INOC5xkbit25hSYnq7kaaJrZpojQNSkryzs3yWMp8M0hJAjA8Hl46dgxnWRn/nDpF3/79aEJQc/QoU+PjxKUk2dND8t49jP5+5PAwtmnOBD+EKinJSEly3jxWtbWhe7383dZGpquL6Nmz9B85gtPlYmN7OxmXixR5FXIsXozy+WaGQkqJOTiImJoiFQximSZs2kTi5k3uX7pE7vp1SkdHKQcSly/TrWm80NSEq6ICKy9I6C4XYunSmS29zbatseHhunUNDc5cJEJuYgJnIsGDcBg1MoJnYAC7ANCmp4neuUMumcQVjZIbGcGzciVVgQA9N26YocnJ2x3wjQ7QAVfrUik1Oja2cd3mzc6cYZAJBtGGhtBDoSLULphTSnK9vWRHRiitrKQyEOBOb6/55927f9jweidYRa3ogKsb02k5Oj5e76+vd+aSSbLxeBGm5pjLKitZWVvL752d2f6xsV9teLMFsrPUrQOu1WUy5mgwuMkfCDhzmQzZdBp0HaXroGmogpVXVbHc7+faL79khmKxH214uwWsp+mxE1jyMXxW4/N9+NaGDSXO+fMRZWX54i9ospIS5fXSef682R2P//YlHLIhAoSB9JPgUmA58DywrAl2vApvAELl9wkFQuSjoASoAehvh3PAOBAE/gUGAVPM8VV5AR9QASwEFgCLgHmFFxlAHHhQsCgwDcQoxBfgP5iXZPCieQjzAAAAAElFTkSuQmCC';

dwidgets.next_img='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAI2SURBVDiNlZJLSFRhHMV/3+POw0bDFFLEXkQgaBQEhdNGaNEiggRbRoFCuMlyjDZCKzeNkIsochMUvaRFYj5wES1m0CmkFDfRIiwznbGBHuN479z7tQhfMxPUgbP5/ofD+Z//hzGGfIa7dKyxU7cVm+VTUgTGo3F39YG+cJc1EI5YoWKaNRQ1ALjS0hs8efTsaQSz4YjV8N8GSmqaDp/xtTdfrw36QxPhiNVWTCcaI/orhp1bHhXZm+2DganPY1SV7cMnt/F4/NbKh/mZYWM4H4s6PzcMOrXpuXgfKRRKKISQCAQAiU9DeLiU+Xewq7ye+PS4MzY5sIAxp2JRZwZAA7hejtjHZyipUUKBEAgBQgHCY9meI700z8G6I1ZN1Z7ap2N3J8IRqyMWdfo1QM5bJZ1ZwHaz2G4WpTSlJWWUBEL4LT9GuNhejndLo9SE6kRrc1fJ0KtHfcevWsc0wNKPOd4nX693oH2ClCPRWYnWCr8viE8GUPgpzZWjTJCsnTHrK2wpUILUAmXJP/SBp7KgLBoqmkgvZsyDl3dWsquZjRUAWg5dWzdQlkBpychcL9onqQ7tp277CSbfxO3E2/hX47KpRMHi7Sc9W84oLbKXznUHlFLUVzZRofcy8PxhZjH5ZcS4eWc0xhR8jnDEMpdbu/nlJUmmUubF6OCK7dgdsRtOf762oIM1ODmbxFRidXp2atHbFLmgs78lqCivzHz7nho2Lhc2R/6nBEISX06n7sWihZHz8RtB3gm0bnbltgAAAABJRU5ErkJggg==';

dwidgets.previous_img='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAIhSURBVDiNhZNPSBRxFMe/b2Z+szu7UmJsrRu1QggRCYKVbluH3CJW00xEIogOJXSyoi26eokQAzvEHiTw0CUKgrBuHSRXio4VHiJL91C5bJK77czuzO/36zCZrozug3d6f/i873sPUkrU8qM3tSvxW1rGK6ZhC4unWB0RJqPh5q6FH58Nrxxli+IWED6dPNzfc23gnmcxAG+CeIoNGb668YvJYWPPzmZSaHPQqsgq8r7Iga7BU1cNk6/g4/dpHIn2gFRY8RSTVdWEnySlXIdMU4lDfY0dBzvZ118fULDy0FSGWFMfiBQQAAlASgEhBe6kL7gE8RQbChrbH/SfuOSvr2+g94uvwKUDpugQkmNm/hmICASChKt+e7TXHeHYbfaoqXH/+e7jg0autIB3396AMR90TQdXBCxRgGkWULRWULZLUEiFnwXRujuxpgHnNiz7D0znN0oyD3ABh5uoCBNcckguwR0Jxxbgjjtyrph11zgzal/OLn25/vhl2oTtk617E5B6GUIvgQUAf0CFHlDBDAXMr0DVqFrH9SKSgqm2lli4vS2mzxVeI1+Zh5DA6cgNiH8U3HYdANJP7q41+L9GFZO7dkSS584MBIpsEXPL0+gMDeP+xIjFK/BvusaNh8R0fby3+6wRDocoqIQw+nAEmTGbNuZ6nnJmzJ6wK5WO5y+eZmdn35bL5YpXWrUGXrY6UsO2UDK/nAt4EdR85Vrv/Bdt8zR07MrLCQAAAABJRU5ErkJggg==';

dwidgets.closetab_img='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oJDRUQAacjbBkAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAPUlEQVQY04WPsREAMQzCBPvvrG/yRZzcRS1gcATRcCOxaEi8iWgKcJiWCBB1T/2BRXnQ4+yo6+ycm/J68wNdZCgH5gvMlAAAAABJRU5ErkJggg==';

dwidgets_loadJSON2 = function() {
    
    try {
        if (JSON.stringify && JSON.parse) {
            // JSON2 already loaded
            return;
        }
    } catch(e) {
        // need to load JSON2
    }
    
    // minified version of JSON2 (http://www.json.org/json2.js) (minified using http://www.crockford.com/javascript/jsmin.py.txt)
    if(!this.JSON){this.JSON={};}
    (function(){function f(n){return n<10?'0'+n:n;}
    if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+'-'+
    f(this.getUTCMonth()+1)+'-'+
    f(this.getUTCDate())+'T'+
    f(this.getUTCHours())+':'+
    f(this.getUTCMinutes())+':'+
    f(this.getUTCSeconds())+'Z':null;};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf();};}
    var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);})+'"':'"'+string+'"';}
    function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}
    if(typeof rep==='function'){value=rep.call(holder,key,value);}
    switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
    gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';}
    v=partial.length===0?'[]':gap?'[\n'+gap+
    partial.join(',\n'+gap)+'\n'+
    mind+']':'['+partial.join(',')+']';gap=mind;return v;}
    if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==='string'){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}
    v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+
    mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}}
    if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' ';}}else if(typeof space==='string'){indent=space;}
    rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');}
    return str('',{'':value});};}
    if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}
    return reviver.call(holder,key,value);}
    cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+
    ('0000'+a.charCodeAt(0).toString(16)).slice(-4);});}
    if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j;}
    throw new SyntaxError('JSON.parse');};}}());
}

dwidgets.createJSON = function(obj) {
    dwidgets_loadJSON2();
    return JSON.stringify(obj);
}

dwidgets.parseJSON = function(str) {
    dwidgets_loadJSON2();
    try {
    	return JSON.parse(str);
    } catch(ex) {
        alert("dwidgets.parseJSON error: "+String(ex));
	    // alert("dwidgets.parseJSON error: "+str);
        return null;
    }
}


dwidgets.loadHtml = function(widget_id,html_data,parameters,widget) {
    
    var htmlinsert = new dwidgets.htmlbuilder();
    
    var mode = this.getParameter('mode',parameters,'embedded',['window']);
    var showframe = this.getParameter('showframe',parameters,false,[true]);
    if (mode == 'window') {
        showframe = true;
    } 

    var frame_width = this.getParameter('frame-width',parameters,5);
    var frame_margin = this.getParameter('frame-margin',parameters,5);
    
    var footer_height = 0;
    var content_padding = 0;
    var position = 'relative';
    var iswindow = false;
   
    widget.dimensions = {};   

    var help_widget_path = this.getParameter('help-widget-path',parameters,'');
    var help_widget_parameters = this.getParameter('help-widget-parameters',parameters,{});
    
    var width = this.getParameter('width',parameters);
    var height = this.getParameter('height',parameters);
    var title = this.getParameter('title',parameters,'');
    var min_width = this.getParameter('min-width',parameters);
    var min_height = this.getParameter('min-height',parameters);    
    var top = this.getParameter('top',parameters,0);
    var left = this.getParameter('left',parameters,0);
    
    var zindex = this.getParameter('z-index',parameters,1);

    if (mode == 'window') {
        position = 'absolute';
        iswindow = true;   
    } 

    var movable = this.getParameter('movable',parameters,false,[true,false]);
    var resizable = this.getParameter('resizable',parameters,false,[true,false]);
    var fullscreen = this.getParameter('fullscreen',parameters,false,[true,false]);
    var closable = this.getParameter('closable',parameters,false,[true,false]);
    var closable_tabs = this.getParameter('closable-tabs',parameters,false,[true,false]);
      
    var content_padding = this.getParameter('content-padding',parameters,5);
    
    var style = { "z-index":String(zindex), "position":position ,"display":"inline-block", 
          "top":top, "left":left, "overflow":"hidden" };
    
    var contentstyle = { 'padding':content_padding, 'overflow':'auto' };
    
    var headerstyle = { 'position':'relative', 'overflow':'hidden' };
    var titlestyle = { 'padding':2 };
    var footerstyle = { 'position':'relative', 'bottom':0 }; 
    
    if (mode == 'window') {
        style["z-index"] = String(zindex);
    }
    
    if (showframe) {
        style["border-width"] = frame_width;
        style["border-style"] = "solid";
        style["margin"] = frame_margin;
    }
        
    var showheader = false;
    var showfooter = false;

    if (title != '') {         
        showheader = true;
    }    
    
    if (resizable) {
        showfooter = true;
        footerstyle['min-height'] = 24;
    }

    if (movable) {
        titlestyle['cursor'] = 'move';
    }
    
    if (width) {
        width -= (2*frame_width);
        width -= (2*frame_margin);
        style["width"] = width; 
    } else {
        style["width"] = "auto";
    } 
    
    if (height) {
        height -= (2*frame_width);
        height -= (2*frame_margin);
        style["height"] = height; 
    }
    
    var mainattrs = {'id':widget.ids.window_id, 'style':style, 'role':'application', 'class':'dwidgets_frame' };
    if (title != '') {
        mainattrs['labelled-by'] = widget.ids.title_id;
    }    

    if (width) { widget.dimensions['width'] = widget.dimensions['original_width'] = width; }
    if (height) { widget.dimensions['height'] = widget.dimensions['original_height'] = height; }
    widget.dimensions['status_width'] = status_width;
    widget.dimensions['footer_height'] = footer_height; 
    widget.dimensions['content_padding'] = content_padding; 
    widget.dimensions['frame_width'] = frame_width;
    widget.dimensions['frame_margin'] = frame_margin;
    widget.dimensions['top'] = (top && left) ? top : 0;
    widget.dimensions['left'] = (top && left) ? left : 0;
    widget.dimensions['tabs_height'] = 0;   
    if (min_width) { widget.dimensions['min_width'] = min_width; }
    if (min_height) { widget.dimensions['min_height'] = min_height; }
    
    widget.settings.resizable = resizable;
    widget.settings.closable = closable;
    widget.settings.movable = movable;
    widget.settings.showframe = showframe;
    widget.settings.fullscreen = fullscreen;
    widget.settings.help_widget_path = help_widget_path;
    widget.settings.help_widget_parameters = help_widget_parameters;
    widget.settings.position = position;
    widget.settings.mode = mode;
    widget.settings.maincontent = html_data;
    widget.settings.closable_tabs = closable_tabs;

    widget.state.zindex = zindex;

    htmlinsert.open('div',mainattrs);
       
    // add the header div (including buttons)
    if (!showheader) {
        headerstyle['display'] = 'none';
    }
    htmlinsert.open('div', {'id':widget.ids.header_id, 'style':headerstyle, 'class':'dwidgets_header' });
    htmlinsert.open('span',{'id':widget.ids.title_id, 'tabindex':0, 
            'style':titlestyle, 'class':'dwidgets_title' },true,title?title:'&nbsp;');
   
    htmlinsert.open('div',{ 'id':widget.ids.topright_id, 
            'style':{'display':'inline','position':'absolute','width':'auto','left':'auto','right':'0px'} },true,'&nbsp;');
    
    htmlinsert.close('div');
    
    // add the content
    var hstyle = { 'padding':content_padding, 'overflow':'auto' };
    htmlinsert.open('div', {'id':widget.ids.content_id, 'style':hstyle, 'class':'dwidgets_content' }, 
            true, html_data?html_data:'&nbsp;');

    // setup tabs area
    dwidgets.setupTabs(widget,htmlinsert,contentstyle);   
  
    // add the status area
    var status_width = 100;
    if (width) {
        status_width = Math.round(width * 0.75);
    }
    htmlinsert.open('div', { 'id':widget.ids.status_id, 
        'aria-live':'polite','aria-relevant':'all', 'aria-atomic':'true', 'class':'dwidgets_alert',
        'style':{ 'position':'absolute', 'width':status_width, 'height':'2em', 
                    'top':10, 'left':'50%', 'margin-left':(-0.5*status_width), 
                    'overflow':'hidden', 'text-align':'center', 'display':'none', 'z-index':'10'  }});
    
    htmlinsert.open('span',{ 'id':widget.ids.status_text_id }, true, '&nbsp;');
    htmlinsert.open('div',{ 'id':widget.ids.status_progress_id,
        'aria-valuemin':'0', 'aria-valuemax':100, 'aria-valuenow':'0', 'aria-valuetext':'0%',
        'style': { 'position':'absolute', 'left':5, 'height':8, 'width':0, 'background':'grey' }},'true','&nbsp;');
    htmlinsert.close('div');
    
    // add the footer
    if (!showfooter) {
        footerstyle['display'] = 'none';
    }

    htmlinsert.open('div', { 'id':widget.ids.footer_id, 'style':footerstyle, 'class':'dwidgets_footer' } );
    htmlinsert.open('div',{ 'id':widget.ids.bottomleft_id, 
                    'style':{'display':'inline','position':'absolute',
                    'width':'auto','left':0,'right':'auto', 'top':'auto', 'bottom':0 } },true,'&nbsp;'); 
     
    if (resizable && (width | height)) { 
        
        var stipple_colour = 'black';
        var stipple_bg_colour = 'white';
        
        var resize_style = {
            'cursor':'SE-resize','width':18, 
            'height':18, 'position':'absolute', 
            'right':5, 'top':10 };
        if (height && !width) { resize_style['cursor'] = 'NS-resize'; }
        if (width && !height) { resize_style['cursor'] = 'EW-resize'; }
        htmlinsert.open('div', { 'id':widget.ids.resize_id, 'style':resize_style, 'role':'button', 'tabindex':0 });
        var stipple_style = { 'width':3, 'height':3, 'position':'absolute', 'overflow':'hidden' };
        
        var coords = [];
        // if (footer_size >= 3) { coords = coords.concat([[1,19],[19,19],[13,19],[7,19]]); }
        coords = coords.concat([[7,13],[13,13],[1,13]]); 
        coords = coords.concat([[7,7],[1,7],[1,1]]); 
        
        for(var idx = 0; idx<coords.length; idx++) {
            var coord = coords[idx];
            stipple_style['right'] = coord[0]-1;
            stipple_style['top'] = coord[1]+1; 
            stipple_style['background-color'] = stipple_colour;
            htmlinsert.open('div', {'style':stipple_style},true, '&nbsp;');
            stipple_style['right'] = coord[0];stipple_style['top'] = coord[1]; 
            stipple_style['background-color'] = stipple_bg_colour;
            htmlinsert.open('div', {'style':stipple_style},true, '&nbsp;');
        }
        
        var tooltip_id = this.getTooltipId(widget.ids.resize_id);
        
        htmlinsert.close('div');
        
        htmlinsert.open('span', {'id':tooltip_id, 'style':dwidgets.tooltip_css }, true, dwidgets.catalogue['resize']);
    } 
    
    htmlinsert.close('div');  // footer
    
    htmlinsert.close('div');  // widget
                   
    return htmlinsert.getHtml();
}   




dwidgets.platform = {};

dwidgets.platform.getVScrollBarWidth = function() {
    if (window.scrollMaxY > 0) {
        return 16;
    }
    return 0;
}

dwidgets.platform.getHScrollBarWidth = function() {
    if (window.scrollMaxX > 0) {
        return 16;
    }
    return 0;
}

dwidgets.platform.stopPropagation = function(event) {
    if (event.bubbles) {
        // non IE
        event.stopPropagation();
    } else if (event.bubbles == undefined) {
        // IE
        event.cancelBubble = true;
    }
}    

dwidgets.platform.setHandler = function(element,handler) {
    element.onclick = handler;
    element.onkeydown = function(event) {
        var code = event.charCode || event.keyCode;
        if (code == 13) {
            handler(event);
        }   
    }
}

dwidgets.platform.measure = function(id,property) {
    if (!id) { return null; }
    var ele = document.getElementById(id);
    if (!ele) { return null; }
    if (window.getComputedStyle) {
        var sty = window.getComputedStyle(ele,null);
        var hp = sty.getPropertyValue(property);
        return Number(hp.split('px')[0]);
     } else {
        return null;
     }      
}

dwidgets.platform.computeDimensions = function(widget) {
   
    var header_height = dwidgets.platform.measure(widget.ids['header_id'],'height');
    if (header_height) {
        widget.dimensions['header_height'] = header_height;
    }

    var tabs_height = dwidgets.platform.measure(widget.ids['tabs_outer_id'],'height');
    if (tabs_height) {
        var content_height = dwidgets.platform.measure(widget.ids['content_id'],'height');
        if (content_height) {
            tabs_height += content_height + (2*widget.dimensions['content_padding']); 
        }
        widget.dimensions['tabs_height'] = tabs_height;
    }
    
    var footer_height = dwidgets.platform.measure(widget.ids['footer_id'],'height');
    if (footer_height) {
        widget.dimensions['footer_height'] = footer_height;
    }
    
}

dwidgets.platform.setOpacity = function(element,opacity) {
    element.style.opacity = opacity/100;
	element.style.filter = 'alpha(opacity=' + opacity + ')';
}

dwidgets.platform.getPosition = function(element) {    
    var wx = 0;
    var wy = 0;
    
    for(var e = element; e; e = e.offsetParent) {
        wx += e.offsetLeft;
        wy += e.offsetTop;
    }
    
    var body = document.body;
    if (!body) {
        body = document.documentElement;
    }
    if (body) {
        if (body.scrollLeft) { wx -= body.scrollLeft; }
        if (body.scrollTop) { wy -= body.scrollTop; }
    }
    return { 'wx':wx, 'wy':wy };
}
        




dwidgets.fetch_url = function(url) {
    try {
        var req = new XMLHttpRequest(); 
        req.open("get",url,false);
        req.send("");
        return req.responseText;
    } catch(e) {
        return null;
    }
}


dwidgets.encode = function(str) {
    var i;
    var encstr = '';
    for(i=0; i<str.length; i++) {
        var hex = Number(str.charCodeAt(i)).toString(16);
        if (hex.length == 1) {
            hex = "0"+hex;
        }    
        encstr += hex;
    }
    return encstr;
}

dwidgets.rgb2colour = function(rgblist) {
    var res = '#';
    for(var i=0; i<rgblist.length;i++) {
        var hex = rgblist[i].toString(16);
        if (hex.length == 1) {
            hex = "0"+hex;
        }
        res += hex;
    }
    return res;
}

dwidgets.decode = function(encstr) {
    var i;
    var str = '';
    for(i=0; i < encstr.length; i+=2) {
        str+=String.fromCharCode(parseInt(encstr.substring(i,i+2),16));    
    }
    return str;
}

dwidgets.get_widget_by_id = function(id) {
    return this.widgets_by_id[id];
}

dwidgets.substituteParameters = function(txt,parameters) {
    var s = txt;
    var result = '';
    var openp = s.search('\\${');
    while(openp != -1) {
        result += s.slice(0,openp);
        s = s.slice(openp+2);
        var closep = s.search('}');
        
        if (closep != -1) {
            var pname = s.slice(0,closep);
            
            if (pname in parameters) {
                result += String(parameters[pname]);
            } else {
                result += '${' + pname + '}';
            }    
            s = s.slice(closep+1);   
            openp = s.search('\\${');
        } else {
            openp = -1;
        }
    }
    result += s; 
        
    return result;
}


dwidgets.htmlbuilder = function() {
    this.html = '';
    this.tagstack = new Array();
}


dwidgets.htmlbuilder.prototype['open'] = function(tag,attributes,closeonexit,content) {
    var insert = '<';
    insert += tag;
    for(key in attributes) {
        if (attributes.hasOwnProperty(key)) {
            var value = attributes[key];
            insert += ' ';
            insert += key;
            insert += '="';
            if (typeof(value)=='string') {
                insert += value;
            } else if (typeof(value)=='object') {
                insert += this.generateCSS(value);
            } else {
                insert += String(value);
            }
            insert += '"';
        }
    }
    
    if (closeonexit) {
        if (content) {
            insert += '>';
            insert += content;
            insert += '</'+tag+'>\n';
        } else {
            insert += ' />\n';
        }
    } else {
        insert += '>';
        if (content) {
            insert += content;
        }
        insert += '\n';
        this.tagstack.push(tag);
    }
    this.html += insert;
    return this;
}

dwidgets.htmlbuilder.prototype['close'] = function(optionaltag) {
    var tag = this.tagstack.pop();
    if (!tag) {
        throw "htmlbuilder error - no open tag to close";
    }
    if (optionaltag && tag !== optionaltag) {
        throw "htmlbuilder error - tag mismatch on close";
    }
    this.html += '</'+tag+'>\n';
    return this;
}

dwidgets.htmlbuilder.prototype['add'] = function(str) {
    this.html += str;
    return this;
}

dwidgets.htmlbuilder.prototype['getHtml'] = function() {
    if (this.tagstack.length > 0) {
        throw "htmlbuilder error - not all tags closed";
    }
    return this.html;
}

dwidgets.htmlbuilder.prototype['generateCSS'] = function(props) {
    var style = '';
    for(key in props) {
        if (props.hasOwnProperty(key)) {
            style += key;
            style += ':';
            var val = props[key];
            if (typeof(val) == 'number') {
                style += String(val)+'px';
            } else {
                style += val;
            }
            style += ';';
        }
    }
    return style;
}



dwidgets.getDirectElementsByTagName = function(element,tag) {
        var sub = [];
        for (var j=0; j<element.childNodes.length; j++) 
        {
           var node = element.childNodes[j];
           
           if (node.nodeType==1 && node.nodeName.toLowerCase() == tag.toLowerCase()) {
                sub.push(node);
           }
        }
        return sub;
}


dwidgets.removeText = function(element) {
        for (var j=0; j<element.childNodes.length; j++) 
        {
           var node = element.childNodes[j];
           if (node.nodeType==3) {
                element.removeChild(node);
           }
        }
}


dwidgets.removeDirectElementsByName = function(element,tag) {
    
    for (var j=element.childNodes.length-1; j>=0; j--) 
    {
       var node = element.childNodes[j];
       
       if (node.nodeType==1 && (tag == '' || node.nodeName.toLowerCase() == tag.toLowerCase())) {
            element.removeChild(node);
       }
    }
}

dwidgets.merge_properties = function(target,toadd) {
    if (!toadd) { return; }       
    for(key in toadd) {
        if (toadd.hasOwnProperty(key)) {
            target[key] = toadd[key];
        }
    } 
}

dwidgets.setFocusHandler = function(element,useborder) {
    if (element) {
        var oldbg = element.style.backgroundColor;
        var focushandler = function(event) {    
            element.style.backgroundColor = 'yellow';
        };
        var blurhandler = function(event) {
            element.style.backgroundColor = oldbg;
        };
        element.addEventListener('focus',focushandler,true);
        element.addEventListener('mouseover',focushandler,true);
        element.addEventListener('blur',blurhandler,true);
        element.addEventListener('mouseout',blurhandler,true);
        element.addEventListener('click',blurhandler,true);
    }
}    
     
dwidgets.configureTooltip = function(id) {
    var btn = document.getElementById(id);
    var tooltip = document.getElementById(this.getTooltipId(id));
    if (btn && tooltip) {
        btn.ariaLabelledby = this.getTooltipId(id);
        btn.addEventListener('mouseover', function(event) { 
            btn.timer = window.setTimeout(function() {
                    tooltip.style.top=event.clientY+10;
                    tooltip.style.left = event.clientX+10;
                    tooltip.style.display="block";
                }, 1000);
        }, true);
        var clear_tooltip = function(event) {
            dwidgets.clearTooltip(id);
        };
        btn.addEventListener('mouseout', clear_tooltip, true);
        btn.addEventListener('click', clear_tooltip, true);
    }
}

dwidgets.clearTooltip = function(id) {
    var btn = document.getElementById(id);
    var tooltip = document.getElementById(this.getTooltipId(id));
    if (btn && tooltip) {
        if (btn.timer) {
            window.clearTimeout(btn.timer); 
            delete btn.timer;
        }
        tooltip.style.display="none";
    }
}    

dwidgets.getTooltipId = function(id) {
    return id+'_tooltip';
}

dwidgets.getParameter = function(pname,parameters,default_value,valid_values) {
    var val = null;
    var params = [parameters,this.parameters];
    for(var pidx in params) {
        if (pname in params[pidx]) {
            val = params[pidx][pname];
            if (default_value && val == default_value) {
                return val;
            }
            if (valid_values) {
                for(idx in valid_values) {
                    if (val == valid_values[idx]) {
                        return val;
                    }
                }
                return null;
            } else {
                return val;
            }
        }
    }
    if (default_value != undefined) {
        return default_value;
    } 
    return null;
}

dwidgets.wrapFunction = function(fname) {
    return function() {
        for(var i=0; i<this.length; i++) {
            if (fname in this[i]) {
                this[i][fname].apply(this[i],arguments);
            }
        }
    }
}

dwidgets.transferFunctions = function(arr) {
    var obj = null;
    for(var i=0; i<arr.length; i++) {
        obj = arr[i];
        if (obj) {
            break;
        }
    } 
    if (obj) {   
        for(var n in obj) {
            if (n in arr) {
                continue;
            }
            var m = obj[n];
            if (m instanceof Function) {
                arr[n] = dwidgets.wrapFunction(n);                         
            }
        }
    }
}

dwidgets.arrayWrap = function(arr) {
    
    dwidgets.transferFunctions(arr);
    
    arr.$map = function(f) {
        for(var i=0; i<this.length; i++) {
            result = f(this[i]);
            if (result) {
                this[i] = result;
            }
        }
    }

    arr.$filter = function(f) {
        var filtered = [];
        for(var i=0; i<this.length; i++) {
            if (f(this[i])) {
                filtered.append(this[i]);
            }
        }
        dwidgets.arrayWrap(filtered);
        return filtered;
    }

    arr.$reduce = function(f,acc) {
        var state = acc;
        for(var i=0; i<this.length;i++) {
            state = f(this[i],state);
        }
        return state;
    }

    return arr;
}


dwidgets.widgetLoadListeners = [];

dwidgets.addWidgetLoadListener = function(listener) {
    dwidgets.widgetLoadListeners.push(listener);
}

dwidgets.removeWidgetLoadListener = function(listener) {
    var oldlist = this.widgetLoadListeners;
    this.widgetLoadListeners = [];
    for(var i=0; i<oldlist.length; i++) {
        if (oldlist[i] != listener) {
            this.widgetLoadListeners.push(oldlist[i]);
        }
    }
}

dwidgets.fireWidgetLoadEvent = function(widget) {
    for(var i=0;i<this.widgetLoadListeners.length;i++) {
        this.widgetLoadListeners[i].apply(null,[widget]);
    }
}    

dwidgets.setEventHandlers = function(widget) {

    widget.tabChangeListeners = [];

    widget.addTabChangeListener = function(listener) {
        this.tabChangeListeners.push(listener);
    }

    widget.fireTabChangeEvent = function(newTab) {
        for(var i=0;i<this.tabChangeListeners.length;i++) {
            this.tabChangeListeners[i].apply(widget.obj,[newTab]);
        }
    }

}



dwidgets.base_css = 
".dwidgets_frame { border-color:lightblue; -moz-border-radius:5px; border-radius:5px; -webkit-border-radius:5px; }\n"+
".dwidgets_header { background-color:lightblue; }\n"+
".dwidgets_title { background-color:lightblue; }\n"+
".dwidgets_footer { background-color:lightblue; }\n"+
".dwidgets_tabs { background-color:lightblue; }\n"+
".dwidgets_selected_tab { background-color:white; }\n"+
".dwidgets_deselected_tab { background-color:lightgrey; }\n"+    
".dwidgets_tab { padding:0px 2px 0px 2px; -moz-border-radius:5px 5px 0px 0px; -webkit-border-radius:5px 5px 0px 0px; border-radius:5px 5px 0px 0px; }\n"+
".dwidgets_alert { background-color:yellow; }\n"+
".dwidgets_content { background-color:white; }\n"+
".dwidgets_tabcontent {}\n";

dwidgets.addStyle= function(css) {
    var sty = document.createElement('style');
    sty.innerHTML = css;
    var head = document.head;
    if (!head) {
        head = document.getElementsByTagName('head')[0];
    }
    head.appendChild(sty);
}    



dwidgets.setupTabs = function(widget,htmlinsert,contentstyle) {

    var widget_id = widget.settings.widget_id;

    var tabs_outerstyle= { 'position':'relative' };
    var tabs_middlestyle= { 'position':'relative', 'overflow':'hidden' };
    var tabs_innerstyle = { 'display':'inline-block', 'position':'relative', 'top':1, 'margin-bottom':0 };

    if (widget.settings.maincontent) { 
        tabs_outerstyle['background-color'] = 'white';
        tabs_innerstyle['background-color'] = 'white';
    }

    var width = widget.dimensions['width'];
    
    var frame_width = widget.dimensions['frame_width'];
    var frame_margin = widget.dimensions['frame_margin'];

    if (width) {
        tabs_outerstyle['min-height'] = 16;
    }
       
    var spacing = frame_width;
    
    if (width) {
        // tabs_middlestyle['width'] = width - (2*spacing) - (2*frame_width) - (2*frame_margin);
        tabs_middlestyle['width'] = width - (2*frame_width) - (4*frame_margin);
        tabs_middlestyle['left'] = 0; // spacing
    } else {
        tabs_middlestyle['left'] = 0; // spacing
    }
            
    if (width) {
        tabs_innerstyle['width'] = 2000;
        // tabs_innerstyle['overflow'] = 'hidden';
    }
    
    var tabs_scrollstyle = { 'display':'none', 'position':'absolute', 'left':frame_margin, 'top':0 };

    // open tabs div
    htmlinsert.open('div', {'id':widget.ids.tabs_id, 'style': { 'display':'none'} });
    
    // add the tab headings area
    
    htmlinsert.open('div', {'id':widget.ids.tabs_outer_id, 'style':tabs_outerstyle, 'class':'dwidgets_tabs' });
    if (width) {
        htmlinsert.open('img', { 'id':widget.ids.tabs_left_id, 'src':this.previous_img, 'style':tabs_scrollstyle, 'tabindex':'0' }, true);
        var tooltip_id = this.getTooltipId(widget.ids.tabs_left_id);
        htmlinsert.open('span', {'id':tooltip_id, 'style':dwidgets.tooltip_css }, true, dwidgets.catalogue['tableft']);
    } 

    htmlinsert.open('div', { 'id':widget.ids.tabs_middle_id, 'style':tabs_middlestyle } );
    htmlinsert.open('div', { 'id':widget.ids.tabs_inner_id, 'style':tabs_innerstyle, 'role':'tablist', 'class':'dwidgets_tabs' } );

    htmlinsert.open('span', { 'id':this.getPanelTabKey(widget_id,'_marker_'), 'style': { 'width':0 }},true,'&nbsp;');
    
    htmlinsert.close('div').close('div');
    if (width) {
        delete tabs_scrollstyle['left'];
        tabs_scrollstyle['right'] = frame_margin;
        htmlinsert.open('img', { 'id':widget.ids.tabs_right_id, 'src':this.next_img, 'style':tabs_scrollstyle, 'tabindex':'0' },true);
        var tooltip_id = this.getTooltipId(widget.ids.tabs_right_id);
        htmlinsert.open('span', {'id':tooltip_id, 'style':dwidgets.tooltip_css }, true, dwidgets.catalogue['tabright']);
    }
     
    htmlinsert.close('div');

	// add the tab contents area
	htmlinsert.open('div', { 'id':widget.ids.tabcontent_id, 'style':contentstyle });
    htmlinsert.open('div', { 'id':this.getPanelTabKey(widget_id,'_contentmarker_'), 'style': { 'width':0 }},true,'&nbsp;');
    htmlinsert.close('div');

    // close tabs div
    htmlinsert.close('div');

    widget.tabs = [];
    widget.state.tab_counter = 0;
    widget.getNextTabKey = function() {
        return "tab"+String(widget.state.tab_counter++);
    }

    dwidgets.addTabCallbacks(widget);
}	  

dwidgets.initTabs = function(widget) {
    var tab_left_btn = document.getElementById(widget.ids.tabs_left_id);
    var tab_right_btn = document.getElementById(widget.ids.tabs_right_id);
    if (tab_left_btn) {
        this.configureTooltip(widget.ids.tabs_left_id);
        dwidgets.platform.setHandler(tab_left_btn, function(event) { 
            widget.scrollTabs(false);
            dwidgets.platform.stopPropagation(event); 
        });
        dwidgets.setFocusHandler(tab_left_btn);
    }
    if (tab_right_btn) {
        this.configureTooltip(widget.ids.tabs_right_id);
        dwidgets.platform.setHandler(tab_right_btn, function(event) { 
            widget.scrollTabs(true);
            dwidgets.platform.stopPropagation(event); 
        });
        dwidgets.setFocusHandler(tab_right_btn);
    }
} 

dwidgets.enableTabs = function(widget,enable) {
    document.getElementById(widget.ids.tabs_id).style.display = enable ? 'block' : 'none';
}

dwidgets.addTab = function(widget,ptitle,pcontent) {

    if (pcontent == '') {
        pcontent = '&nbsp;';
    }
          
    var tabhstyle = {};

    var key = widget.getNextTabKey();

    var widget_id = widget.settings.widget_id;
    
    if (!widget.settings.showframe || widget.settings.maincontent) {
        // add a black border around tabs if the background is white
        this.merge_properties(tabhstyle, { 
            'border-left-width':'1px', 'border-left-style':'solid', 'border-left-color':'black', 
            'border-right-width':'1px', 'border-right-style':'solid', 'border-right-color':'black', 
            'border-top-width':'1px', 'border-top-style':'solid', 'border-top-color':'black' } );
    }
    
    var tabhattrs = { 'role':'tab', 'id':this.getPanelTabKey(widget_id,key), 
            'style':tabhstyle, 'class':'dwidgets_tab dwidgets_deselected_tab' };            

    var headinginsert = new dwidgets.htmlbuilder();
    var openkey = this.getPanelTabOpenKey(widget_id,key);
    var closekey = this.getPanelTabCloseKey(widget_id,key);
    headinginsert.open('span', tabhattrs, false, '');
    headinginsert.open('span', { 'tabindex':0, 'id':openkey, 'aria-selected':false }, true, ptitle );
    if (widget.settings.closable_tabs) {
        headinginsert.open('img', { 'tabindex':0, 'id':closekey, 'src':this.closetab_img }, true);
    }
    headinginsert.close('span');
    headinghtml = headinginsert.getHtml();

    var e1 = document.createElement('span');
    var marker1_id = this.getPanelTabKey(widget_id,'_marker_')
    var marker1 = document.getElementById(marker1_id);
    
    marker1.parentNode.insertBefore(e1,marker1);
    e1.innerHTML = headinghtml;

    var that = this;
    var opener = document.getElementById(openkey);
    dwidgets.setFocusHandler(opener);
    dwidgets.platform.setHandler(opener, function() { that.openTabFN(widget,key); }); 
    
    if (widget.settings.closable_tabs) {
        var closer = document.getElementById(closekey);
        dwidgets.setFocusHandler(closer);    
        dwidgets.platform.setHandler(closer, function() { that.deleteTabFN(widget,key); }); 
    }
    
    var panel_key = this.getPanelTabKey(widget_id,key);
    var panel_tab = document.getElementById(panel_key);
            
    dwidgets.setFocusHandler(panel_tab);
            
    widget.tabs.push({'title':ptitle, 'key':key});   
   
    var attrs = {   'id':this.getPanelKey(widget_id,key), 
                    'role':'tabpanel', 
                    'aria-labelledby':this.getPanelTabKey(widget_id,key),
                    'class':'dwidgets_tabcontent',
                    'style':{'display':'none'} };
    
    var contentinsert = new dwidgets.htmlbuilder();
    contentinsert.open('div', attrs, true, pcontent );
    contenthtml = contentinsert.getHtml(); 
  
    var e2 = document.createElement('div');
    var marker2_id = this.getPanelTabKey(widget_id,'_contentmarker_')
    var marker2 = document.getElementById(marker2_id);
    marker2.parentNode.insertBefore(e2,marker2);  
    e2.innerHTML = contenthtml;

    dwidgets.enableTabs(widget,true);

    widget.repaint();
    widget.repaint();
    widget.reconfigureTabs(widget.dimensions.width);
    
    return key;
}

dwidgets.getPanelKey = function(wid,key) { 
    return wid+"_panel_"+key; 
}

dwidgets.getPanelTabKey = function(wid,key) { 
    return wid+"_tab_"+key; 
}

dwidgets.getPanelTabOpenKey = function(wid,key) { 
    return wid+"_tabopen_"+key; 
}

dwidgets.getPanelTabCloseKey = function(wid,key) { 
    return wid+"_tabclose_"+key; 
}

dwidgets.openTabFN = function(widget,key) {
    widget.selectPanel(key); 
}

dwidgets.deleteTabFN = function(widget,key) {
    widget.deletePanel(key);
}

dwidgets.addTabCallbacks = function(widget) {

    widget.getTab = function(index) {
        return document.getElementById(dwidgets.getPanelKey(this.getId(),index));
    };

    widget.reconfigureTabs = function(w) {

        var bar_left_offset = this.dimensions['frame_width']; 
	    // var bar_width = w - (4*this.dimensions['frame_width']+2*this.dimensions['frame_margin']);
        var bar_width = w - (2*this.dimensions['frame_width']) - (4*this.dimensions['frame_margin']);
                
        var marker = document.getElementById(dwidgets.getPanelTabKey(this.getId(),'_marker_'));
        
        var next_tabh = null;
        if (this.state.current_panel) {
            for(var p=0; p<this.tabs.length; p++) {
                if (this.tabs[p]['key'] == this.state.current_panel) {
                    if (p < (this.tabs.length-1)) {
                       next_tabh = document.getElementById(dwidgets.getPanelTabKey(
                            this.getId(),this.tabs[p+1]['key']));
                    } else {
                        next_tabh = marker;
                    }    
                }
            }
        }
                    
        var show_left = (this.state.tab_scroll > 0);
        var divl = document.getElementById(this.ids.tabs_left_id);
        var divr = document.getElementById(this.ids.tabs_right_id);
        if (show_left) {
            if (divl && divl.style.display == 'none') divl.style.display = 'block';
            bar_left_offset += 18;
            bar_width -= 18;
        } else {
            if (divl && divl.style.display == 'block') divl.style.display = 'none'; 
        }

        var off_left = marker.offsetLeft;
        if (off_left && off_left > bar_width && this.state.tab_scroll+1 < this.tabs.length) {
            if (divr && divr.style.display == 'none') divr.style.display = 'block';
            bar_width -= 16;      
        } else {
            if (divr && divr.style.display == 'block') divr.style.display = 'none';       
        }
	   
	    if (bar_width < 0) {
	        bar_width = 0;
	    }
        
        var tab_middle = document.getElementById(this.ids.tabs_middle_id);
        tab_middle.style.width = bar_width;
        tab_middle.style.left = bar_left_offset;
        
        if (next_tabh) {
            off_left = next_tabh.offsetLeft;
            if (off_left && off_left > bar_width) {
                return false;
            }
            return true;
        } else {
            return false;
        }
    };

    widget.scrollTabs = function(isScrollRight) {
       
        if (!isScrollRight && this.state.tab_scroll <= 0) {
            return;
        }
        if (isScrollRight && this.state.tab_scroll+1 >= this.tabs.length) {
            return;
        }
       
        this.state.tab_scroll += (isScrollRight ? 1 : -1);
        
        for(var p=0;p<this.tabs.length;p++) {
            var key = this.tabs[p]['key'];
            var panel_key = dwidgets.getPanelTabKey(this.getId(),key);
            var panel_tab = document.getElementById(panel_key);
            if (p < this.state.tab_scroll) {
                panel_tab.style.display = 'none';
            } else {
                panel_tab.style.display = 'inline';
            }
        }
                
        var new_panel_tabkey = dwidgets.getPanelTabKey(this.getId(),this.state.current_panel);
        var new_panel_tab = document.getElementById(new_panel_tabkey);
        if (new_panel_tab) {
            new_panel_tab.setAttribute('class','dwidgets_selected_tab dwidgets_tab');
        }

        return this.reconfigureTabs(this.dimensions.width);
    }
        
    widget.selectPanel = function(new_key) {
        var old_key = this.state.current_panel;
        var old_panel_key = dwidgets.getPanelKey(this.getId(),old_key);
        var old_panel_tabkey = dwidgets.getPanelTabKey(this.getId(),old_key);
        var old_panel = document.getElementById(old_panel_key);
        if (old_panel) {
            old_panel.style.display = 'none';
        }
        var old_panel_tab = document.getElementById(old_panel_tabkey);
        if (old_panel_tab) {
            old_panel_tab.setAttribute('class','dwidgets_deselected_tab dwidgets_tab');
            old_panel_tab.ariaSelected = false;
        }
        var new_panel_key = dwidgets.getPanelKey(this.getId(),new_key);
        var new_panel_tabkey = dwidgets.getPanelTabKey(this.getId(),new_key);
        var new_panel = document.getElementById(new_panel_key);
        if (new_panel) {
            new_panel.style.display = 'block';
        }
        var new_panel_tab = document.getElementById(new_panel_tabkey);
        if (new_panel_tab) {
            new_panel_tab.setAttribute('class','dwidgets_selected_tab dwidgets_tab');
            new_panel_tab.ariaSelected = true;
        }

        var selected_index = 0;
        for(var p=0; p<this.tabs.length; p++) {
            if (this.tabs[p]['key'] == new_key) {            
                selected_index = p;
            }        
        }

        this.state.current_panel = new_key;
        
        if (selected_index < this.state.tab_scroll) {
            while(selected_index < this.state.tab_scroll) {
                this.scrollTabs(false);
            }
        }

        if (selected_index > this.state.tab_scroll) {
            if (!this.reconfigureTabs(this.dimensions.width)) {
                while(selected_index > this.state.tab_scroll) {                
                    if (this.scrollTabs(true)) {
                        break;
                    }
                }
            }
        }    
        
        widget.fireTabChangeEvent(new_key);
    };

    widget.deletePanel = function(key) {
        
        var new_panel_key = dwidgets.getPanelKey(this.getId(),key);
        var new_panel_tabkey = dwidgets.getPanelTabKey(this.getId(),key);

        var new_panel = document.getElementById(new_panel_key);
        var new_panel_tab = document.getElementById(new_panel_tabkey);

        new_panel.parentNode.removeChild(new_panel);
        new_panel_tab.parentNode.removeChild(new_panel_tab);
        
        var selected_index = -1;
        for(var p=0; p<this.tabs.length; p++) {
            if (this.tabs[p]['key'] == key) {            
                selected_index = p;
                break;
            }        
        }
        
        if (selected_index != -1) {
            this.tabs.splice(selected_index,1);
            if (selected_index < this.state.tab_scroll) {
                this.state.tab_scroll--;
            }
        }

        if (this.state.current_panel == key) {            
            if (selected_index == this.tabs.length) {
                selected_index = this.tabs.length-1; 
            }

            if (selected_index >= 0) {
                this.selectPanel(this.tabs[selected_index]['key']);    
            } else {
                this.state.current_panel = '';
                dwidgets.enableTabs(this,false);                
            }
        }
    }
    
    widget.addTab = function(title,content) {
        return dwidgets.addTab(this,title,content);
    }

}    
  
} // !dwidgets
