// ! TODO: Help panel.
// ! TODO: Double-loading problem. (Caused by changing the position or overflow attributes of the chart div.)
// ! TODO: Broken ExternalInterface callbacks (calls into the swf) in IE. Breaks page resizing and drag resizing.
// TODO: Maybe Chart.as should respond to onResize events... or maybe it shouldn't.
// TODO: A chart with internal scrolling hasn't been tested. (Disabled for now, b/c the double-loading problem.)

var ie6;
var ie;
var body;
var pageLayout;
var chartOuter;
var chartInner;
var chartSwfPrototype
var resizeHandle;
var resizeHandleDraggable;
var caption;
var help;
var chartChooser;
var countryChooser;
var header;

var chart = {};
var page = {};

var weightingToolWindow;
var customWeightedChartWindow;

Event.observe(window, 'load', onInitChartPage);
Event.observe(window, 'resize', onResizeChartPage);
window.onbeforeunload = onNavigateAway; // Event.observe(window, 'beforeunload', onNavigateAway) doesn't work in Safari


// Initialize when page is fully loaded

function onInitChartPage() {
	
    log('onInitChartPage');

    ie = $$('html')[0].hasClassName('ie');
    ie6 = $$('html')[0].hasClassName('ie6');
    body = $$('body')[0];
    resizeHandle = $('chart-resize-handle');
    chartOuter = $('chart-column');
    chartInner = $('chart');
    chartSwfPrototype = $('chartSwf');
    caption = $('chart-captions');
    help = $('chart-helps');
    chartChooser = $('chart-chooser');
    countryChooser = $('chart-country-choosers');
    pageLayout = $('page-layout');
    header = $$('.header-module')[0];
    
    var wiki = $('wiki-column');    
    var sidebar = $('sidebar');
    
    page.initDone = true;
    page.chartTop = (pageLayout && chartOuter) ? parseInt(chartOuter.getStyle('top')) : 0;
    page.chartLeft = (pageLayout && chartOuter) ? parseInt(chartOuter.getStyle('left')) : 0;
    page.minWidth = $('page-layout-min-width') ? parseInt($('page-layout-min-width').getStyle('width')) : 0;
    page.chartWidth = $('chart-helps') ? parseInt($('chart-helps').getStyle('left')) : 0;
    page.captionInset = $('chart-captions-inset-width') ? parseInt($('chart-captions-inset-width').getStyle('width')) : 0;
    page.sidebarWidth = sidebar ? sidebar.getDimensions().width : 0;
    page.wikiWidth = wiki ? wiki.getDimensions().width : 0;
    page.resizeHandleWidth = resizeHandle ? resizeHandle.getDimensions().width : 0;
    page.resizeHandleHeight = resizeHandle ? resizeHandle.getDimensions().height : 0;
    page.helpVisible = false;
    page.chartChooserVisible = false;
    page.countryChooserVisible = false;
    
    if (help) {
        Event.observe(help, 'mouseover', onPanelMouseOver);
        Event.observe(help, 'mouseout', onPanelMouseOut);
    }
    if (chartChooser) {
        Event.observe(chartChooser, 'mouseover', onPanelMouseOver);
        Event.observe(chartChooser, 'mouseout', onPanelMouseOut);
    }
    if (countryChooser) {
        Event.observe(countryChooser, 'mouseover', onPanelMouseOver);
        Event.observe(countryChooser, 'mouseout', onPanelMouseOut);
    }
    
}


// This function should be called by the chart controller as soon as it requests a chart load.
// Note: This may be called before onInitChartPage.

function onChartLoadStart(chartNum) {
    
    log('onChartLoadStart ' + chartNum);

    chart.loadDone = false;
    chart.chartNum = chartNum;

    // Delay DOM-altering code until outside of this function, to prevent the Firefox ExternalInterface crash
    delay(function() {
        
            if (!chart.loadDone) {
                
                // Disable the chart's resize handle
                if (resizeHandle) {
                    resizeHandle.setStyle({visibility: 'hidden'});
                    resizeHandleDraggable = null;
                }

                // Disable the chart's scrollbar
                // Problem: This is disabled because due to a Flash bug, it causes the chart and XML to reload
                /* chartOuter.setStyle({overflow: 'hidden', overflowY: 'hidden', overflowX: 'hidden'}); */

                // Hide the caption
                $$('.chart-caption').each(function(chartCaption) { chartCaption.hide(); } );

                // Hide the help text
                $$('.chart-help').each(function(chartHelp) { chartHelp.hide(); } );
                
                // Hide the countries list
                $$('.chart-country-chooser').each(function(countryChooser) { countryChooser.hide(); } );
                
            }
            
    });
    
}

// Set up the chart divs after chart data is loaded; and tell the chart how much space is available to it.

function onChartLoadDone(chartCanExceedPageHeight, chartNeedsScrollbar, userCanResizeChart, chartIsFullSize, showHelpInitially) {
    
    log('onChartLoadDone ' + chartCanExceedPageHeight + ' ' + chartNeedsScrollbar + ' ' + userCanResizeChart + ' ' + chartIsFullSize + ' ' + showHelpInitially);

    if (userCanResizeChart == null) userCanResizeChart = true;
    
    // Store settings in the chart object
    chart.canExceedPageHeight = (chartCanExceedPageHeight ? true : false);
    chart.hasScrollbar = (chartNeedsScrollbar ? true : false);
    chart.userCanResize = (userCanResizeChart ? true : false);
    chart.scrollsWidthPage = false;
    chart.fullSize = (chartIsFullSize ? true : false);
    chart.showHelpInitially = (showHelpInitially ? true : false);
    chart.loadDone = true;

    // Tell the chart how much width and height is available to it
    var chartColumnDimensions = getChartColumnDimensions();
    log('onChartLoadDone returning dimensions ' + chartColumnDimensions.width + ' ' + chartColumnDimensions.height + ' ' + chartColumnDimensions.maxWidth);

    return chartColumnDimensions;
        
}


// Show the chart resize handle and caption, and activate the right help text and countries list

function onChartRevealDone() {
    
    // Delay DOM-altering code until outside of this function, to prevent the Firefox ExternalInterface crash
    setTimeout(function() {
        
            log('onChartRevealDone');
        
            // Enable or disable the chart's resize handle
            if (resizeHandle) {
                if (chart.userCanResize) {
                    resizeHandle.setStyle({visibility: 'visible'});
                    resizeHandleDraggable = new Draggable(resizeHandle, {snap: onDragResizeHandle});
                }
                else {
                    resizeHandle.setStyle({visibility: 'hidden'});
                    resizeHandleDraggable = null;
                }
            }

            // Enable or disable the chart's scrollbar
            // Problem: This is disabled because due to a Flash bug, it causes the chart and XML to reload
            /* if (chartInner && chartOuter) {
                if (chart.hasScrollbar) {
                    chartOuter.setStyle({overflow: 'auto', overflowY: 'scroll', overflowX: 'hidden'});
                }
                else {
                    chartOuter.setStyle({overflow: 'hidden', overflowY: 'hidden', overflowX: 'hidden'});
                }
            } */
            
            // Show the correct caption
            $$('.chart-caption').each(function(chartCaption) { chartCaption.hide(); } );
            var thisCaption = $('chart-caption-' + chart.chartNum);
            if (thisCaption) thisCaption.show();
            
            // Show the correct list of countries (even though the dropdown is hidden)
            $$('.chart-country-chooser').each(function(countryChooser) { countryChooser.hide(); } );
            var thisCountryChooser = $('chart-country-chooser-' + chart.chartNum);
            if (thisCountryChooser) thisCountryChooser.show();
            
            // Show the correct help text (even thow the panel may be hidden)
            $$('.chart-help').each(function(chartHelp) { chartHelp.hide(); } );
            var thisHelp = $('chart-help-' + chart.chartNum);
            if (thisHelp) thisHelp.show();
            
            if ((chart.showHelpInitially) && (!page.helpVisible)) { 
                toggleHelp();
            }
            
    }, 250);
        
}


// On window resize, tell Flash the size of the chart column; Flash will then call setChartDimensions

function onResizeChartPage() {

    log('onResizeChartPage');

    var chartColumnDimensions = getChartColumnDimensions();

    getChartSwf().onResizeChartPage(chartColumnDimensions.width, chart.canExceedPageHeight ? 0 : chartColumnDimensions.height, 
            chartColumnDimensions.maxHeight);
            
}


// Resize the chart in response to user dragging, by passing the requested dimensions to Flash.
// Flash will then call steChartDimensions with the true new dimensions.
// (And Flash will also return the new dimension for this function, so that the resize handle can snap.)

function onDragResizeHandle(x, y) {
    
    chartWidth = x + page.resizeHandleWidth - page.chartLeft;
    var chartHeight = y + page.resizeHandleHeight - page.chartTop;

    // !! TODO: Breaks in IE (fixed?)
    var newDimensions = getChartSwf().onDragResizeHandle(chartWidth, chartHeight);
    
    x = newDimensions.width + page.chartLeft - page.resizeHandleWidth;
    y = newDimensions.height + page.chartTop - page.resizeHandleHeight;

    setChartDimensions(newDimensions.width, newDimensions.height, false, false);
    
    return [x, y];
        
}

// Called by window.onMouseUp-- it's a failsafe that stops stickiness in Firefox when mouse is released over the Flash chart'

function stopAnyDragging() {
    log('stopAnyDragging');
    Draggables.endDrag();
}


// Return the maximum width and height available to the chart (without exceeding the chart column)

function getChartColumnDimensions(setCaptionSize) {

    if (setCaptionSize == null) setCaptionSize = true;

    // Figure out chart column width, in order to figure out the caption width and height
    var pageLayoutDimensions = getPageLayoutDimensions();
    var chartColumnWidth = pageLayoutDimensions.width - page.sidebarWidth - (chart.fullSize ? 0 : page.wikiWidth);
    var maxChartWidth = pageLayoutDimensions.width - page.sidebarWidth;
    
    // Set the caption width in order to get its height
    if (setCaptionSize && caption) {
        caption.setStyle({width: (chartColumnWidth - page.captionInset) + 'px'});
    }
    
    // Figure out the chart column height
    var chartColumnHeight;
    if (chart.canExceedPageHeight || chart.usesScrollbar) {
        chartColumnHeight = 0;
    }
    else {
        chartColumnHeight = pageLayoutDimensions.height - getCaptionDimensions().height - page.chartTop;
    }
    
    // ! TODO: Reduce maxWidth by current help panel width
    
    log('getChartColumnDimensions(' + setCaptionSize + '): ' + chartColumnWidth + ' ' + chartColumnHeight + ' ' + maxChartWidth);
    
    // Tell the chart how much width and height is available to it
    var chartColumnDimensions = {width: chartColumnWidth, height: chartColumnHeight, maxWidth: maxChartWidth};
    return chartColumnDimensions;
    
}


// This will be called exclusively by the Flash chart, which is the only entity that can compute the
// relationship between its width and height. But to do this correctly, the Flash chart first needs to know
// how much space is available to it. That comes from the return value to onChartLoadDone (Flash calls this
// at onChartData) and from the values passed by JavaScript onResizeChartPage to Flash onResizeChartPage.

function setChartDimensions(width, height, moveResizeHandle, doDelay) {
    
    log('setChartDimensions ' + width + ' ' + height + ' ' + moveResizeHandle);
    
    chart.width = width;
    chart.height = height;

    if (moveResizeHandle == null) moveResizeHandle = true;

    var pageDimensions = getPageDimensions();
    var letChartScroll = ((pageDimensions.width < page.minWidth) || 
                    (chart.canExceedPageHeight && (height > pageDimensions.height)));
                
    // Delay DOM-altering code until outside of this function, to prevent the Firefox ExternalInterface crash
    delay(function() {

            // Decide whether the chart should be fixed or absolute position
            if (letChartScroll != chart.scrollsWithPage) {
                chart.scrollsWithPage = letChartScroll;
                setChartPositioning();
            }

            // Set the chart size
            if (chartInner && chart.hasScrollbar) {
                chartInner.setStyle({width: width + 'px', height: height + 'px'});
            }
            else {
                if (chartOuter) {
                    chartOuter.setStyle({width: width + 'px', height: height + 'px'});
                }
            }
            if (chartSwfPrototype) chartSwfPrototype.setStyle({width: width + 'px', height: height + 'px'});

            // Position the resize handle
            if (moveResizeHandle && resizeHandle && chart.userCanResize) {
                var resizeHandleLeft = page.chartLeft + width - page.resizeHandleWidth;
                var resizeHandleTop = page.chartTop + height - page.resizeHandleHeight
                resizeHandle.setStyle({left: resizeHandleLeft + 'px', top: resizeHandleTop + 'px'});
            }

            // Position the caption
            if (caption) {
                var captionTop = page.chartTop + height;
                caption.setStyle({top: captionTop + 'px'});
            }
            
            // Position the help panel
            if (help) {
                if (chart.fullSize) {
                    help.setStyle({left: (getPageLayoutDimensions().width - page.sidebarWidth - 240) + 'px'})
                }
                else {
                    help.setStyle({left: (page.chartLeft + width) + 'px'});
                }
            }
            
        }, doDelay);

}


// Set the chart to fixed or absolute positioning.
// Problem: Due to a Flash bug, this may cause the chart (and XML) to reload.

function setChartPositioning() {
    
    log('setChartPositioning');
    
    if (chartOuter) {
        chartOuter.setStyle({position: (chart.scrollsWithPage || ie6) ? 'absolute' : 'fixed'});
    }
    if (resizeHandle) {
        resizeHandle.setStyle({position: (chart.scrollsWithPage || ie6) ? 'absolute' : 'fixed'});
    }
    if (caption) {
        caption.setStyle({position: (chart.scrollsWithPage || ie6) ? 'absolute' : 'fixed'});
    }
    if (help) {
        help.setStyle({position: (chart.scrollsWithPage || ie6) ? 'absolute' : 'fixed'});
    }
    if (header) {
        header.setStyle({position: (chart.scrollsWithPage || ie6) ? 'absolute' : 'fixed'});
    }

}


// Show a list of charts

function toggleChartChooser(currentChartNum) {
    if (page.chartChooserVisible) hideChartChooser();
    else showChartChooser(currentChartNum);
}
function showChartChooser(currentChartNum) {
    if (chartChooser) {
        delay(function() {
            page.chartChooserVisible = true;
            chartChooser.getElementsBySelector('.row').each(function(row) {
                row.removeClassName('current')
            });
            if (currentChartNum != undefined) {
                chartChooser.down('.row-' + currentChartNum).addClassName('current');
            }
            hideCountryChooser();
            Effect.SlideDown(chartChooser, {duration: 0.25});
        });
    }
}
function hideChartChooser() {
    if (chartChooser && page.chartChooserVisible) {
        delay(function() {
            page.chartChooserVisible = false;
            Effect.SlideUp(chartChooser, {duration: 0.25});
        });
    }
}

// Hide the list of charts and tell Flash to select the new chart

function chooseChart(chartNum) {
    if (chartChooser && page.chartChooserVisible) {
        delay(function() {
            page.chartChooserVisible = false;
            Effect.SlideUp(chartChooser, {duration: 0.25, afterFinish: function() {
                if (help && page.helpVisible) {
                    help.hide();
                }
                getChartSwf().onLoadChart(chartNum);
            }});
        });
    }
    else {
        getChartSwf().onLoadChart(chartNum);
    }
}


// Show a list of countries

function toggleCountryChooser(currentCountryId) {
    if (page.countryChooserVisible) hideCountryChooser();
    else showCountryChooser(currentCountryId);
}
function showCountryChooser(currentCountryId) {
    if (countryChooser) {
        delay(function() {
            page.countryChooserVisible = true;
            countryChooser.getElementsBySelector('.country').each(function(row) {
                row.removeClassName('current')
            });
            if (currentCountryId != undefined) {
                countryChooser.down('.country-' + currentCountryId).addClassName('current');
            }
            hideChartChooser();
            Effect.SlideDown(countryChooser, {duration: 0.25});
        });
    }
}
function hideCountryChooser() {
    if (countryChooser && page.countryChooserVisible) {
        delay(function() {
            page.countryChooserVisible = false;
            Effect.SlideUp(countryChooser, {duration: 0.25});
        });
    }
}

// Hide the list of countries and tell Flash to highlight a country

function chooseCountry(countryId) {
    if (countryChooser && page.countryChooserVisible) {
        delay(function() {
            page.countryChooserVisible = false;
            Effect.SlideUp(countryChooser, {duration: 0.25, afterFinish: function() {
                getChartSwf().onChooseCountry(countryId);
            }});
        });
    }
    else {
        getChartSwf().onChooseCountry(countryId);
    }
}


// Show and hide this chart's help panel

function toggleHelp() {
    if (page.helpVisible) hideHelp();
    else showHelp();
}
function hideHelp() {
    if (help && page.helpVisible) {
        delay(function() {
            page.helpVisible = false;
            if (chart.fullSize) {
                Effect.SlideUp(help, {duration: 0.25});
            }
            else {
                Effect.SlideLeftOut(help, {duration: 0.25});
            }
        });
    }
}
function showHelp() {
    if (help) {
        delay(function() {
            page.helpVisible = true;
            if (chart.fullSize) {
                Effect.SlideDown(help, {duration: 0.25});
            }
            else {
                Effect.SlideRightIn(help, {duration: 0.25});
            }
        });
    }    
}


// Pop up the Weighting Tool

function showWeightingTool(chartId) {
    if (window.name == 'epiCustomWeightedChart') setTimeout(window.close, 250);
    else if (customWeightedChartWindow) customWeightedChartWindow.close();
    weightingToolWindow = null;
    weightingToolWindow = window.open('/chart/new_weighting/' + chartId, 'epiWeightingTool', 
            'height=600,width=600,location=no,status=no,resizable=yes,toolbar=no,directories=no,scrollbars=yes');
    if (weightingToolWindow) {
        weightingToolWindow.focus();
    }
    else {
        alert("You appear to have a popup blocker enabled in your web browser.\n\n" +
            "To use the Custom Weighting feature, you need to disable your popup blocker for this site.\n\n" +
            "Please disable your popup blocker and try again.");
    }
}

function onNavigateAway() {
    if ((weightingToolWindow) && (window.name != 'epiCustomWeightedChart')) weightingToolWindow.close(); // The second clause prevents the weighting tool from immediately closing itself when you do Adjust Weightings on an already-custom-weighted chart, in some browsers
    if (customWeightedChartWindow) customWeightedChartWindow.close();
}

function setCustomWeightedChartWindow(win) {
    customWeightedChartWindow = win;
    customWeightedChartWindow.opener = window;
}

// Convenience functions to return dimensions of DOM elements

function getPageDimensions() {
    var obj;
    if (ie6) {
         obj = {width: document.documentElement.clientWidth, height: document.documentElement.clientHeight};
    }
    else {
         obj = {width: document.body.clientWidth, height: document.body.clientHeight};
    }
    return obj;
}

function getPageLayoutDimensions() {
    return pageLayout ? pageLayout.getDimensions() : getPageDimensions();
}

function getCaptionDimensions() {
    return caption ? caption.getDimensions() : {width: 0, height: 0};
}

function getChartSwf() {
    return document['chartSwf'] || window['chartSwf'] || chartSwfPrototype;
}


// Tell Flash when use rolls over overlapping panels (help, chart chooser, country chooser)
// Used by SatelliteMap to disable the hand cursor and enable the regular cursor

function onPanelMouseOver() {
    getChartSwf().onPanelMouseOver();
}

function onPanelMouseOut() {
    getChartSwf().onPanelMouseOut();
}


// Delay DOM-altering code until outside of functions called by ExternalInterface, to prevent the Firefox crash

function delay(f, doDelay) {
    if (doDelay == null) doDelay = true;
    if (doDelay) setTimeout(f, 100);
    else f();
}


// Display trace messages in Firebug (Firefox), Firebug Lite (IE), or the Error Console (Safari).
// You can also call this function from Flash via ExternalInterface (but that should be disabled for production
//   deployment, since it's a performance hit).
// (This function's body should also be disabled for production deployment.)
// (And, Firebug Lite should be removed for production deployment.)

function log(text) {
    // if (console) console.log(text);
}

function chartExportStatus(text) {
    $('export-chart-progress').update(text);
}


// Additional Scriptaculous effects
// From http://scriptaculous.jakewendt.com/effects.html

Effect.SlideRightIn = function(element) {
    element = $(element).cleanWhitespace();
    var elementDimensions = element.getDimensions();
    return new Effect.Scale(element, 100, 
        Object.extend({ 
            scaleContent: false, 
            scaleY: false, 
            scaleFrom: window.opera ? 0 : 1,
            scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
            restoreAfterFinish: true,
            afterSetup: function(effect) {
                effect.element.makePositioned();
                effect.element.down().makePositioned();
                if(window.opera) effect.element.setStyle({left: ''});
                effect.element.makeClipping().setStyle({width: '0px'}).show(); 
            },
            afterUpdateInternal: function(effect) {
                effect.element.down().setStyle({right: (effect.dims[1] - effect.element.clientWidth) + 'px' }); 
            },
            afterFinishInternal: function(effect) {
                effect.element.undoClipping().undoPositioned();
                effect.element.down().undoPositioned();
            }
        }, arguments[1] || {})
    );
}

Effect.SlideLeftOut = function(element) {
    element = $(element).cleanWhitespace();
    return new Effect.Scale(element, window.opera ? 0 : 1,
        Object.extend({ 
            scaleContent: false, 
            scaleY: false, 
            scaleMode: 'box',
            scaleFrom: 100,
            restoreAfterFinish: true,
            beforeStartInternal: function(effect) {
                effect.element.makePositioned();
                effect.element.down().makePositioned();
                if(window.opera) effect.element.setStyle({left: ''});
                effect.element.makeClipping().show();
            },  
            afterUpdateInternal: function(effect) {
                effect.element.down().setStyle(
                    {right: (effect.dims[1] - effect.element.clientWidth) + 'px' }
                );
            },
            afterFinishInternal: function(effect) {
                effect.element.hide().undoClipping().undoPositioned();
                effect.element.down().undoPositioned();
            }
        }, arguments[1] || {})
    );
}

