/*extern BrowserDetect, VEColor, VELatLong, VELatLongRectangle, VEMap, VEPixel, VEShape, VEShapeLayer, VEShapeType, VETileSourceSpecification, VEDashboardSize, VEDistanceUnit, VERouteDistanceUnit, VERouteOptions, GetVEMapInstance, Pmx, RS, lang */

/**
 * Pelmorex Map object
 *
 * @fileoverview
 * This is the source file for the Dynamic Mapping object. This object is used for
 * generating dynamic maps.
 *
 * @author Jim Ing (jing@pelmorex.com)
 * @Modified for Jean-Pierre's new server Bby Bala Gopalakrishnan (bgopalakrishnan@pelmorex.com)
 * @Modified for Dynamic Mapping project by Daniel Fu (dfu@pelmorex.com) Apr 2008
 */

/**
 * Pelmorex Dynamic Mapping Project
 * @static
 *
 * @property {string}  mapStyle             Virtual Earth map style: [r | a | h | s] = [Road | Aerial | Hybrid | Shaded Hills]
 * @property {object}  elemId               Element ID mapping
 * @property {string}  cookieStateId        Cookie ID/name for map state
 * @property {string}  cookiePrefsId        Cookie ID/name for user preferences
 * @property {string}  tileId               Tile layer ID
 * @property {string}  tileUrl              Tile server URL
 * @property {string}  jsonReqSep           JSON argument request separator
 * @property {string}  jsonUrl              JSON server URL
 * @property {string}  camCallback          JSON callback function for camera
 * @property {string}  obsCallback          JSON callback function for weather
 * @property {string}  evtCallback          JSON callback function for incident
 * @property {string}  flwCallback          JSON callback function for flow
 * @property {string}  imgRoot              Image root path
 * @property {float}   latitude             Latitude (map center)
 * @property {float}   longitude            Longitude (map center)
 * @property {array}   zoomRatios           Zoom ratios used for calculating the extended bounding box for over-fetching
 * @property {integer} zoomLevel            Zoom level of the map
 * @property {integer} vectorLevel          Threshold level for showing vector-based roads (less than = tiles)
 * @property {boolean} shieldFilter         Setting to toggle filtering of shields
 * @property {integer} smallShieldLevel     Threshold level for showing small shields
 * @property {integer} mediumShieldLevel    Threshold level for showing medium shields
 * @property {integer} largeShieldLevel     Threshold level for showing large shields
 * @property {integer} maxTimeout           Maximum time (ms) to show loading indicator
 * @property {integer} updateMapTimerDelay  Delay time (ms) before firing update map event
 * @property {integer} endPanTimerDelay     Delay time (ms) before firing pan event
 * @property {integer} endZoomTimerDelay    Delay time (ms) before firing zoom event
 */

Pmx.Map =
{
    mapStyle                : 's',
    elemId                  :
    {
        map                 : 'map',
        map_container       : 'map_container',
        map_controls        : 'map_controls',
        map_error           : 'map_error',
        map_popup           : 'map_popup',

        tabbed_section      : 'tabbed_section',
        tab_bar             : 'tab_bar',

        hwycond_section     : 'hwycond_section',
        hwycond_selector    : 'hwycond_selector',
        hwycond_table       : 'hwycond_table',

        mto_cam_section     : 'mto_cam_section',
        mto_cam_selector    : 'mto_cam_selector',
        mto_cam_table       : 'mto_cam_table',
        mto_cam_strip       : 'mto_cam_strip',

        spinner             : 'spinner',
        spinner_txt         : 'spinner_txt',

        opt_debug           : 'opt_debug',
        opt_road_conditions : 'opt_road_conditions',
        opt_shield          : 'opt_shield',
        //opt_traffic         : 'opt_traffic',
        opt_traffic_cams    : 'opt_traffic_cams',
        opt_vector_level    : 'opt_vector_level',

        prefs_section       : 'prefs_section',

        prefs_map_dash      : 'prefs_map_dash',
        prefs_map_full      : 'prefs_map_full',
        prefs_map_mini      : 'prefs_map_mini',
        prefs_map_style     : 'prefs_map_style',
        prefs_lat           : 'prefs_lat',
        prefs_lon           : 'prefs_lon',
        prefs_zoom_level    : 'prefs_zoom_level',
        prefs_zoom_wheel    : 'prefs_zoom_wheel',

        zone_section        : 'zone_section',

        locations_div       : 'locations_div',
        provinces_div       : 'provinces_div',

        stat_zoom           : 'stat_zoom',
        stat_shield_cnt     : 'stat_shield_cnt',
        stat_segment_cnt    : 'stat_segment_cnt',
        stat_vertice_cnt    : 'stat_vertice_cnt',
        stat_density        : 'stat_density',
        stat_browser_size   : 'stat_browser_size',
        stat_map_size       : 'stat_map_size',
        stat_cursor_xy      : 'stat_cursor_xy',
        stat_fetch          : 'stat_fetch',
        stat_time           : 'stat_time',
        stat_rdw            : 'stat_rdw',
        stat_tile           : 'stat_tile'
    },

    cookieStateId           : 'hwycond_state',
    cookiePrefsId           : 'hwycond_prefs',

    tileId                  : 'road_tiles',
    tileUrl                 : 'http://webmaptiles.weather.ca/cache/current',     // tiles-map-dev.testdev.pelmorex.com = 72.14.162.214 = 10.10.202.16

    jsonReqSep              : '&',
    jsonUrl                 : 'http://webmapvector.weather.ca/RDW',              // web-map-dev.testdev.pelmorex.com   = 72.14.162.213 = 10.10.202.15

    //PRODUCT
    CAMERA                  : 'CAMERA',
    WEATHER                 : 'WEATHER',
    INCIDENT                : 'INCIDENT',
    FLOW                    : 'FLOW',

    //JSON SERVER WEB-TESTING
    //camSever                : 'http://72.14.162.213/',
    obsSever                : 'http://72.14.162.213/',
    evtSever                : 'http://72.14.162.213/',
    flwSever                : 'http://72.14.162.214/',

    //JSON SERVER PRODUCTION
    camSever                : 'http://trafficcameras.weather.ca/',
/*
    obsSever                : 'http://72.14.162.213/',
    evtSever                : 'http://trafficincidents.weather.ca/',
    flwSever                : 'http://trafficflow.weather.ca/',
*/

    //JSON CALL BACK FUNCTION    
    camCallback             : 'Pmx.Map.drawTrafficCamera',
    obsCallback             : 'Pmx.Map.drawWeather',
    evtCallback             : 'Pmx.Map.drawTrafficIncident',
    flwCallback             : 'Pmx.Map.drawTrafficFlow',

    imgRoot                 : 'traffic_cameras/images/',

    latitude                : 43.51164670862528,
    longitude               : -79.6893310546875,

    //zoomRatios              : [ 1.0, 1.0, 1.0, 1.0, 1.0, 1.25, 1.25, 1.5, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.25, 3.5, 3.75, 4.0, 4.0, 5.0, 4.0, 4.0, 4.0 ],
    zoomRatios              : [ 1.0, 1.0, 1.0, 1.2, 1.2, 1.3, 1.3, 1.4, 1.4, 1.5, 1.5, 1.6, 1.6, 1.7, 1.7, 1.8, 1.8, 1.9, 1.9, 2.0, 2.0, 2.0, 2.0 ],

    zoomLevel               : 10,
    updated                 : true,    //check this value to decide if to update the map
    vectorLevel             : 3,

    shieldFilter            : true,

    smallShieldLevel        : 5,
    mediumShieldLevel       : 8,
    largeShieldLevel        : 11,

    //maxTimeout              : 12000,
    maxTimeout              : 6000,

    updateMapTimerDelay     : 50,
    endPanTimerDelay        : 1000,
    endZoomTimerDelay       : 500,

    //---[ "private" properties ]---

    _boundsExt              :
    {
        x1                  : 0,
        y1                  : 0,
        x2                  : 0,
        y2                  : 0
    },

    _boundsView             :
    {
        x1                  : 0,
        y1                  : 0,
        x2                  : 0,
        y2                  : 0
    },

    _rsView                 : null,

    _screen                 :
    {
        w                   : 0,
        h                   : 0
    },

    _clientWidth            : 0,
    _clientHeight           : 0,

    _elems                  : {},

    _VE                     : null,
    _tileSource             : null,

    _cursor                 : '',
    _mapType                : '',
    _timeout                : '',

    _updateMapTimer         : null,
    _endPanZoomTimer        : null,
    _zoomed                 : false,

    _mapFullScreen          : true,
    _zoomWheel              : false,

    _zoneFillColor          : '',
    _zonePoints             : [],

    _roadShadowShapeLayer   : null,
    _roadShapeLayer         : null,     //for drawing winter road condition
    _shieldLayer            : null,
    _trafficCameraLayer     : null,     //for drawing traffic camera
    _trafficFlowLayer       : null,     //for drawing traffic flow
    _weatherLayer           : null,
    _zoneLayer              : null,
    _trafficIncidentLayer   : null,	//for drawing traffic incident

    control                 : null,
    //an array to store the active layers to display
    //one of the selections: CAMERA, INCIDENT, FLOW, DIRECTION, WEATHER
    _currentLayer           :
    {
        CAMERA              : false,
        WEATHER             : false,
        INCIDENT            : false,
        FLOW                : false
    },

    _hwyTally               : [],
    _hwyTallyCnt            : [],
    _poorVisPos             : [] // TODO: remove this?
};

/**
 * @description
 * Calculate the line width based on zoom level.
 */
Pmx.Map.calculateLineWidth = function()
{
    var lineSize = 1;

    if( Pmx.Map.zoomLevel >= 14 )
    {
        lineSize = 10;
    }
    else if( Pmx.Map.zoomLevel >= 12 )
    {
        lineSize = 8;
    }
    else if( Pmx.Map.zoomLevel >= 10 )
    {
        lineSize = 6;
    }
    else if( Pmx.Map.zoomLevel >= 7 )
    {
        lineSize = 4;
    }
    else if( Pmx.Map.zoomLevel >= 4 )
    {
        lineSize = 2;
    }

    return lineSize;
};

/**
 * @description
 * Add a delay to the pan event.
 */
Pmx.Map.checkContinuousPan = function()
{
    // if the timer is set, clear it and reset it
    if( Pmx.Map._endPanZoomTimer !== null )
    {
        window.clearTimeout( Pmx.Map._endPanZoomTimer );
    }

    // clear fetch
    Pmx.Map.updateElemInnerHTML( Pmx.Map.elemId.stat_fetch, 'false' );

    Pmx.Map._endPanZoomTimer = window.setTimeout( Pmx.Map.handleEndPan, Pmx.Map.endPanTimerDelay );
};

/**
 * @description
 * Add a delay to the zoom event.
 */
Pmx.Map.checkContinuousZoom = function()
{
    if( Pmx.Map._zoomed === false )
    {
        Pmx.Map._zoomed = true;
    }

    // if the timer is set, clear it and reset it
    if( Pmx.Map._endPanZoomTimer !== null )
    {
        window.clearTimeout( Pmx.Map._endPanZoomTimer );
    }

    // clear fetch
    Pmx.Map.updateElemInnerHTML( Pmx.Map.elemId.stat_fetch, 'false' );

    Pmx.Map._endPanZoomTimer = window.setTimeout( Pmx.Map.handleEndZoom, Pmx.Map.endZoomTimerDelay );
};

/**
 * @description
 * Draw the traffic incident  map. This is a callback function for a JSR response.
 */
/*
Pmx.Map.drawTrafficIncident = function()
{
    var timer = new Pmx.Timer( 'drawTrafficIncident' );
    timer.start();
   alert("callback");
    try
    {
        //console.debug( RS.L.length );
		 Pmx.Map._trafficIncidentLayer.DeleteAllShapes();

            // add weather layer
            Pmx.Map._trafficIncidentLayer = new VEShapeLayer();
            Pmx.Map._trafficIncidentLayer.ZIndex = 6;

            var numLocs = RS.M.length;
           // var html, icn, loc, obs, pr, tmp, wnd;
           alert(numLocs);
            for( var i = 0; i < numLocs; i++ )
            {

                loc = RS.M[ i ];
                obs = new VEShape( VEShapeType.Pushpin, new VELatLong( loc.Y, loc.X ) );
                html  = '<div>';
                html += '<tr><td class="weather-label">T:</td><td>' + loc.T  + '</td></tr>';
                html += '<tr><td class="weather-label">C:</td><td>' + loc.C  + '</td></tr>';
                html += '</table>';
                html += '</div>';
                obs.SetTitle( '<div class="map_popup_bar">' + 'Traffic Incident' + '</div>' );
                obs.SetDescription( html );
		}
    }
    catch( e )
    {
	alert("error");
     }
}
*/

/**
 * @description
 * Converts the VirtualEarth tile path structure to OpenLayers.
 */
Pmx.Map.getCacheTilePath = function( tileContext )
{
    var timer = new Pmx.Timer( 'getCacheTilePath' );
    timer.start();

    var tileX = tileContext.XPos;
    var tileY = Math.pow( 2, tileContext.ZoomLevel ) - tileContext.YPos - 1;
    var tileZ = tileContext.ZoomLevel;

    // append epoch time to URL to prevent caching of tiles
    var epoch = ( new Date() ).getTime();

    var components = [
        this.layername,
        Pmx.zeroPad( tileZ, 2 ),
        Pmx.zeroPad( parseInt( tileX / 1000000, 10 ), 3 ),
        Pmx.zeroPad( ( parseInt( tileX / 1000, 10 ) % 1000 ), 3 ),
        Pmx.zeroPad( ( parseInt( tileX, 10 ) % 1000 ), 3 ),
        Pmx.zeroPad( parseInt( tileY / 1000000, 10 ), 3 ),
        Pmx.zeroPad( ( parseInt( tileY / 1000, 10 ) % 1000 ), 3 ),
        Pmx.zeroPad( ( parseInt( tileY, 10 ) % 1000 ), 3 ) + '.' + 'png?s=' + epoch
    ];

    var path = components.join( '/' );
    var url = Pmx.Map.tileUrl + path;

    if( Pmx.debug === true && Pmx.console.debug === true )
    {
        console.debug( 'tileX=' + tileX + ', tileY=' + tileY + ', tileZ=' + tileZ + ', tileSrc=' + url );
    }

    timer.stop();

    return url;
};

/**
 * @description
 * Update the map if the pan delay is reached.
 */
Pmx.Map.handleEndPan = function()
{
    //if(Pmx.Map.updated){
        Pmx.Map._endPanZoomTimer = null;
        Pmx.Map.handleUpdateMap();
    //}
    //else{
    //    Pmx.Map.updated = true;
    //}
};

/**
 * @description
 * Update the map if the zoom delay is reached.
 */
Pmx.Map.handleEndZoom = function()
{
    Pmx.Map._endPanZoomTimer = null;
    Pmx.Map._zoomed = false;
    Pmx.Map.handleUpdateMap();
};

/**
 * @description
 * Add a delay before updating the map.
 */
Pmx.Map.handleUpdateMap = function()
{
    Pmx.Map._updateMapTimer = window.setTimeout( Pmx.Map.updateMap, Pmx.Map.updateMapTimerDelay );
};

/**
 * @description
 * Hide the loading indicators.
 */
Pmx.Map.hideLoading = function()
{
    if( Pmx.Map._elems.spinner.style.display != 'none' )
    {
        window.status = '';
        Pmx.Map._elems.map.style.cursor = Pmx.Map._cursor;
        Pmx.Map._elems.spinner.style.display = 'none';
    }

    if( Pmx.Map._timeout )
    {
        clearTimeout( Pmx.Map._timeout );
/*
        if( Pmx.debug === true && Pmx.console.warn === true )
        {
            console.warn( 'The request timed out!' );
        }
*/
    }
};
/**
 * @description
 * Show the loading indicators.
 */
Pmx.Map.showLoading = function( msg )
{
    if( msg )
    {
        window.status = msg;
    }

    Pmx.Map._elems.map.style.cursor = 'wait';
    Pmx.Map._elems.spinner.style.display = 'inline';
    document.getElementById('spinner_txt').innerHTML = msg;
    Pmx.Map._timeout = setTimeout( "Pmx.Map.hideLoading()", Pmx.Map.maxTimeout );
};

/**
 * @description
 * Hide selected buttons on the Virtual Earth dashboard.
 */
Pmx.Map.hideVEButtons = function()
{
    try
    {
        var ids = [
            'MSVE_navAction_FlatlandMapMode',
            'MSVE_navAction_View3DMapMode',
            'MSVE_navAction_separator0',
            'MSVE_navAction_ObliqueMapView',
            'MSVE_navAction_separator2',
            //'MSVE_navAction_toggleGlyphWrapper'
        ];

        for( var i = 0; i < ids.length; i++ )
        {
            document.getElementById( ids[ i ] ).style.display = 'none';
        }
    }
    catch( e )
    {
        // ignore
    }
};

/**
 * @description
 * Initialize the Virtual Earth base map and our dynamic data.
 */
Pmx.Map.init = function( lat, lon, z )
{
    var timer = new Pmx.Timer( 'init' );
    timer.start();

    Pmx.JSR.scriptCounter = 1;

    Pmx.initQueryString();
    Pmx.initPngFix();

    Pmx.Map.initElems();
    Pmx.Map.initLang();
    Pmx.Map.initLatLonZoom( lat, lon, z );

    //// set the zoom levels for vectors
    //Pmx.Map.setVectorLevel( Pmx.Map._elems.opt_vector_level );

    //// set the debug mode
    //Pmx.toggleDebug( Pmx.Map._elems.opt_debug );
    //
    //// show the browser version
    //var browser = '';
    //if( Pmx.debug === true && Pmx.console.info === true )
    //{
    //    //console.info( 'UserAgent: ' + navigator.userAgent );
    //}

    // initialize shape layers
    //Pmx.Map._zoneLayer = new VEShapeLayer();
    Pmx.Map._roadShadowShapeLayer = new VEShapeLayer();
    Pmx.Map._roadShapeLayer = new VEShapeLayer();
    Pmx.Map._shieldLayer = new VEShapeLayer();
    Pmx.Map._trafficCameraLayer = new VEShapeLayer();
    Pmx.Map._weatherLayer = new VEShapeLayer();

    try
    {
        // create Virtual Earth map
        Pmx.Map._VE = new VEMap( Pmx.Map.elemId.map );
        Pmx.Map._VE.SetDashboardSize( VEDashboardSize.Normal ); // Normal | Small | Tiny

        Pmx.Map._VE.LoadMap( new VELatLong( Pmx.Map.latitude, Pmx.Map.longitude ), Pmx.Map.zoomLevel, Pmx.Map.mapStyle, false );

        // customize map (non-API)
        Pmx.Map.hideVEButtons();
        Pmx.Map.resizeVEButtons( '50px', '90px', '50px' );
        //Pmx.Map.updateLanguageLabels();

        // set map events
        Pmx.Map._VE.AttachEvent( 'onendzoom', Pmx.Map.checkContinuousZoom );
        Pmx.Map._VE.AttachEvent( 'onendpan', Pmx.Map.checkContinuousPan );
        Pmx.Map._VE.AttachEvent( 'onchangemapstyle', Pmx.Map.updateMapStyle );
        //Pmx.Map._VE.AttachEvent( 'onmouseover', Pmx.Map.onMouseOver );
        //Pmx.Map._VE.AttachEvent( 'onclick', Pmx.Map.onClick );
        //Pmx.Map._VE.AttachEvent( 'onmousedown', Pmx.Map.onMouseDown );
        //Pmx.Map._VE.AttachEvent( 'onmousemove', Pmx.Map.onMouseMove );
        if( Pmx.Map._zoomWheel === false )
        {
            Pmx.Map._VE.AttachEvent( 'onmousewheel', Pmx.Map.onMouseWheel );
        }

        // set map options
        Pmx.Map._VE.SetMouseWheelZoomToCenter( false );
        Pmx.Map._VE.SetScaleBarDistanceUnit( VEDistanceUnit.Kilometers );
        Pmx.Map._VE.ClearInfoBoxStyles();
        //Pmx.Map._VE.EnableShapeDisplayThreshold( true );
        //Pmx.Map._VE.ShowFindControl();
        //Pmx.Map._VE.EnableBirdseye = false;
        document.getElementById('MSVE_obliqueNotification').innerHTML = "";

        //// set road tiles
        //Pmx.Map._tileSource = new VETileSourceSpecification( Pmx.Map.tileId, 'Pmx.Map.getCacheTilePath' );
        //Pmx.Map._tileSource.GetTilePath = Pmx.Map.getCacheTilePath;
        //Pmx.Map._tileSource.NumServers = 1;
        //Pmx.Map._tileSource.MinZoomLevel = 1;
        //Pmx.Map._tileSource.MaxZoomLevel = Pmx.Map.vectorLevel;
        //Pmx.Map._tileSource.Opacity = 1.0;
        //Pmx.Map._tileSource.ZIndex = 100;

        // enable/disable map features
        Pmx.Map.toggleDashboard( Pmx.Map._elems.prefs_map_dash );
        Pmx.Map.toggleMiniMap( Pmx.Map._elems.prefs_map_mini );
        //// update the road conditions
        //Pmx.Map._updateMapTimer = window.setTimeout( Pmx.Map.updateMap, Pmx.Map.updateMapTimerDelay ); // add a delay so the base map is shown

        //make camera as a default dispay
        Pmx.Map.showTabSection( 'mto_cam_section' );
        Pmx.Map._currentLayer[Pmx.Map.CAMERA] = true;
        Pmx.Map.updateTrafficCamera();
    }
    catch( e )
    {
        //Pmx.Map.hideLoading();
        if( Pmx.debug === true && Pmx.console.error === true )
        {
            console( 'init: ' + e );
            //console.error( 'init: ' + e );
        }
    }
    timer.stop();
};
/**
 * @description
 * Handle onmousewheel event.
 */
Pmx.Map.onMouseWheel = function( e )
{
    // disable zooming in and out with the scroll wheel
    return true;
};

/**
 * @description
 * Initialize elements so we don't have to do document.getElementById() every
 * time we want to access an element's properties.
 */
Pmx.Map.initElems = function()
{
    for( var i in Pmx.Map.elemId )
    {
        Pmx.Map._elems[ i ] = document.getElementById( Pmx.Map.elemId[ i ] );
    }
};

/**
 * @description
 * Initialize language.
 */
Pmx.Map.initLang = function()
{
    if( window.lang )
    {
        if( lang == 'en' || lang == 'fr' || lang == 'EN' || lang == 'FR' )
        {
            Pmx.lang = lang.toLowerCase();
        }
    }
};

/**
 * @description
 * Initialize latitude, longitude and zoom level.
 */
Pmx.Map.initLatLonZoom = function( lat, lon, z )
{
    // function arguments
    if( lat && lon && z )
    {
        if( lat ) { Pmx.Map.latitude = parseFloat( lat, 10 ); }
        if( lon ) { Pmx.Map.longitude = parseFloat( lon, 10 ); }
        if( z ) { Pmx.Map.zoomLevel = parseFloat( z, 10 ); }
    }
    // query string arguments
    else if( Pmx._qsArgs.lat && Pmx._qsArgs.lon && Pmx._qsArgs.zoom && Pmx._qsArgs.mapStyle )
    {
        Pmx.Map.latitude = Pmx._qsArgs.lat;
        Pmx.Map.longitude = Pmx._qsArgs.lon;
        Pmx.Map.zoomLevel = Pmx._qsArgs.zoom;
        Pmx.Map.mapStyle = Pmx._qsArgs.mapStyle;
    }
    // cookies
    else
    {
        var cookieObj = new Pmx.Cookie();
        var cookieStr = cookieObj.read( Pmx.Map.cookieStateId );
        if( cookieStr )
        {
            if( Pmx.debug === true && Pmx.console.debug === true )
            {
                console.debug( cookieStr );
            }

            var pairs = cookieStr.split( '|' );
            var keyval;
            var settings = [];
            for( var i = 0; i < pairs.length; i++ )
            {
                keyval = pairs[ i ].split( '=' );
                settings[ keyval[ 0 ] ] = keyval[ 1 ];
            }

            Pmx.Map.latitude = settings.lat;
            Pmx.Map.longitude = settings.lon;
            Pmx.Map.zoomLevel = settings.zoom_level;
            Pmx.Map.mapStyle = settings.map_style;
        }
    }
};

/**
 * @description
 * Load user's preferences into the tab.
 */
Pmx.Map.loadPreferences = function()
{
    var cookieObj = new Pmx.Cookie();
    var cookieStr = cookieObj.read( Pmx.Map.cookiePrefsId );
    if( cookieStr )
    {
        if( Pmx.debug === true && Pmx.console.debug === true )
        {
            console.debug( cookieStr );
        }

        var pairs = cookieStr.split( '|' );
        var keyval;
        var settings = [];
        for( var i = 0; i < pairs.length; i++ )
        {
            keyval = pairs[ i ].split( '=' );
            settings[ keyval[ 0 ] ] = keyval[ 1 ];
        }

        Pmx.Map._elems.prefs_map_dash.checked = ( settings.map_dash == 'true' ) ? true : false;
        Pmx.Map._elems.prefs_map_full.checked = ( settings.map_full == 'true' ) ? true : false;
        Pmx.Map._elems.prefs_map_style.value = ( settings.map_style ) ? settings.map_style : '';
        Pmx.Map._elems.prefs_map_mini.checked = ( settings.map_mini == 'true' ) ? true : false;
        //Pmx.lang
        Pmx.Map._elems.prefs_lat.value = ( settings.lat ) ? settings.lat : '';
        Pmx.Map._elems.prefs_lon.value = ( settings.lon ) ? settings.lon : '';
        Pmx.Map._elems.prefs_zoom_level.value = ( settings.zoom_level ) ? settings.zoom_level : '';
        Pmx.Map._elems.prefs_zoom_wheel.checked = ( settings.zoom_wheel == 'true' ) ? true : false;
    }
};

/**
 * @description
 * Resize the width of selected Virtual Earth buttons to support longer French text.
 */
Pmx.Map.resizeVEButtons = function( w1, w2, w3 )
{
    try
    {
        if( w1 )
        {
            document.getElementById( 'MSVE_navAction_RoadMapStyle' ).style.width = w1;
        }
        if( w2 )
        {
            document.getElementById( 'MSVE_navAction_AerialMapStyle' ).style.width = w2;
        }
        if( w3 )
        {
            document.getElementById( 'MSVE_navAction_HybridMapStyle' ).style.width = w3;
        }
    }
    catch( e )
    {
        // ignore
    }
};

/**
 * @description
 * Save map preferences to a cookie.
 */
Pmx.Map.savePreferences = function()
{
    var cookieStr = '';

    cookieStr += 'map_dash=' + Pmx.Map._elems.prefs_map_dash.checked + '|';
    cookieStr += 'map_full=' + Pmx.Map._elems.prefs_map_full.checked + '|';
    cookieStr += 'map_style=' + Pmx.Map._elems.prefs_map_style.value + '|';
    cookieStr += 'map_mini=' + Pmx.Map._elems.prefs_map_mini.checked + '|';
    cookieStr += 'lang=' + Pmx.lang + '|';
    cookieStr += 'lat=' + Pmx.Map._elems.prefs_lat.value + '|';
    cookieStr += 'lon=' + Pmx.Map._elems.prefs_lon.value + '|';
    cookieStr += 'zoom_level=' + Pmx.Map._elems.prefs_zoom_level.value + '|';
    cookieStr += 'zoom_wheel=' + Pmx.Map._elems.prefs_zoom_wheel.checked;

    var cookieObj = new Pmx.Cookie();
    cookieObj.create( Pmx.Map.cookiePrefsId, cookieStr, 90 );

    if( Pmx.debug === true && Pmx.console.debug === true )
    {
        console.debug( 'Saved "' + cookieStr + '" to "' + Pmx.Map.cookiePrefsId + '" cookie.' );
    }
};

/**
 * @description
 * Save map state to a cookie.
 */
Pmx.Map.saveMapState = function()
{
    var center = Pmx.Map._VE.GetCenter();

    var cookieObj = new Pmx.Cookie();
    var cookieStr = '';

    cookieStr += 'lat=' + center.Latitude + '|';
    cookieStr += 'lon=' + center.Longitude + '|';
    cookieStr += 'zoom_level=' + Pmx.Map.zoomLevel + '|';
    cookieStr += 'map_style=' + Pmx.Map.mapStyle;

    cookieObj.create( Pmx.Map.cookieStateId, cookieStr, 1 );

    if( Pmx.debug === true && Pmx.console.debug === true )
    {
        console.debug( 'Saved "' + cookieStr + '" to "' + Pmx.Map.cookieStateId + '" cookie.' );
    }
};

/**
 * @description
 * Search for matching locations.
 */
Pmx.Map.searchLocations = function( srcElem, destElemId )
{
    var timer = new Pmx.Timer( 'searchLocations' );
    timer.start();
    if(srcElem.value.length >2){
        var max_options = 20;
        var cnt = 0;
        var size = 0;
    
        var html = '';
        var html_options = '';
        var city_str = '';
        if( search_ProvLocs && srcElem )
        {
            for( var i in search_ProvLocs )
            {
                for( var j in search_ProvLocs[ i ].locations )
                {
                    //city_str = ( search_ProvLocs[ i ].locations[ j ][ Pmx.lang ] !== '' ) ? search_ProvLocs[ i ].locations[ j ][ Pmx.lang ] : search_ProvLocs[ i ].locations[ j ].en;
                    //city_str = ( search_ProvLocs[ i ].locations[ j ][lang] != '' ) ? search_ProvLocs[ i ].locations[ j ][lang] : search_ProvLocs[ i ].locations[ j ][Pmx.lang];
                    city_str = search_ProvLocs[ i ].locations[ j ][lang];
                    //if(j=='CAQC0363'){alert(srcElem.value.toLowerCase()+':'+city_str.substr( 0, srcElem.value.length ).toLowerCase());}
                    if( srcElem.value.toLowerCase() == city_str.substr( 0, srcElem.value.length ).toLowerCase() )
                    {
                        cnt++;
                        html_options += '<option value="' + search_ProvLocs[ i ].locations[ j ].lat + ',' + search_ProvLocs[ i ].locations[ j ].lon + ',' + city_str + '">' + city_str + ', ' + i + '</option>';
                        //alert(city_str);
                    }
                }
            }
    
            if( cnt == 1 ) { size = 2; }
            else if( cnt < max_options ) { size = cnt; }
            else { size = max_options; }
    
            if( cnt > 0 )
            {
                //html += '<span>Found <b>' + cnt + '</b> matches:</span><br />';
                //html += '<select id="search_location" name="search_location" onchange="Pmx.Map.setLocation( this.value );" size="' + size + '">';
                html += '<select id="search_location" style="border: 1px #7f9db9 solid; background-color:#FFFFFF; color: #003876; font-family:Arial, Helvetica, sans-serif; font-size:11px; line-height:13px; margin-top:-10px;" name="search_location" onChange="Pmx.Map.setLocation( this.value,\'search_results\');" size="'+size+'">';
                html += html_options;
                html += '</select>';
            }
            else
            {
                var noFound;
                switch(lang){
                    case 'fr':
                        noFound = '--Aucun endroit trouvé--';
                        break;
                    case 'en':
                    default:
                        noFound = '--No match found--';
                }
                html += '<span style="border: 1px #7f9db9 solid; background-color:#FFFFFF; color: #003876; font-family:Arial, Helvetica, sans-serif; font-size:11px; line-height:13px; margin-top:-10px;">'+ noFound +'</span>';
            }
        }
        if( document.getElementById( destElemId ) )
        {
            document.getElementById( destElemId ).innerHTML = html;
            document.getElementById( destElemId ).style.display = 'block';
        }
    }
    else{
        if( document.getElementById( destElemId ) )
        {
            document.getElementById( destElemId ).style.display = 'none';
        }
    }
    timer.stop();
};

/**
 * @description
 * Send a JSON Script Request.
 */
Pmx.Map.sendJSR = function( url )
{
    var timer = new Pmx.Timer( 'sendJSR' );
    timer.start();

    try
    {
        Pmx._jsr = new Pmx.JSR( url );

        Pmx._jsr.buildScriptTag();
        Pmx._jsr.addScriptTag();
        if( Pmx.debug === true && Pmx.console.debug === true )
        {
            var headElem = document.getElementsByTagName( 'head' ).item( 0 );
            //console.debug( headElem.innerHTML );
        }
    }
    catch( e )
    {
        if( Pmx.debug === true && Pmx.console.error === true )
        {
            console.error( 'sendJSR: ' + e );
        }
    }

    timer.stop();
};

/**
 * @description
 * Sets the viewable and extended bounding boxes for the current map view.
 */
Pmx.Map.setBounds = function()
{
    var timer = new Pmx.Timer( 'setBounds' );
    timer.start();

    var updated = false;
    var ratio;

    try
    {
        var x1 = Pmx.Map._VE.GetMapView().TopLeftLatLong.Latitude;
        var y1 = Pmx.Map._VE.GetMapView().TopLeftLatLong.Longitude;
        var x2 = Pmx.Map._VE.GetMapView().BottomRightLatLong.Latitude;
        var y2 = Pmx.Map._VE.GetMapView().BottomRightLatLong.Longitude;

        // update viewable bounds
        Pmx.Map._boundsView.x1 = x1;
        Pmx.Map._boundsView.y1 = y1;
        Pmx.Map._boundsView.x2 = x2;
        Pmx.Map._boundsView.y2 = y2;

        // check if the current view is within the bounds
        if( x1 > Pmx.Map._boundsExt.x1 || y1 < Pmx.Map._boundsExt.y1 || x2 < Pmx.Map._boundsExt.x2 || y2 > Pmx.Map._boundsExt.y2 )
        {
            updated = true;
            ratio = Pmx.Map.zoomRatios[ Pmx.Map.zoomLevel ];

            var center = Pmx.Map._VE.GetCenter();

            // calculate offsets
            var xoffset = ( ( y2 - y1 ) * ratio ) / 2;
            var yoffset = ( ( x1 - x2 ) * ratio ) / 2;

            // scale bounds
            var xs1 = center.Latitude + yoffset;
            var ys1 = center.Longitude - xoffset;
            var xs2 = center.Latitude - yoffset;
            var ys2 = center.Longitude + xoffset;

            // update extended bounds
            Pmx.Map._boundsExt.x1 = xs1;
            Pmx.Map._boundsExt.y1 = ys1;
            Pmx.Map._boundsExt.x2 = xs2;
            Pmx.Map._boundsExt.y2 = ys2;

            Pmx.Map.saveMapState();

            if( Pmx.debug === true && Pmx.console.debug === true )
            {
                console.debug( 'setBounds: [updated=' + updated + '], [x1=' + x1 + ', y1=' + y1 + ', x2=' + x2 + ', y2=' + y2 + '], [ratio=' + ratio + '], [zoom=' + Pmx.Map.zoomLevel + '], [xs1=' + xs1 + ', ys1=' + ys1 + ', xs2=' + xs2 + ', ys2=' + ys2 + ']' );
            }
        }
        else
        {
            if( Pmx.debug === true && Pmx.console.debug === true )
            {
                console.debug( 'setBounds: [updated=' + updated + '], [Pmx.Map._boundsExt.x1=' + Pmx.Map._boundsExt.x1 + ', Pmx.Map._boundsExt.y1=' + Pmx.Map._boundsExt.y1 + ', Pmx.Map._boundsExt.x2=' + Pmx.Map._boundsExt.x2 + ', Pmx.Map._boundsExt.y2=' + Pmx.Map._boundsExt.y2 + '], [x1=' + x1 + ', y1=' + y1 + ', x2=' + x2 + ', y2=' + y2 + ']' );
            }
        }

        return updated;
    }
    catch( e )
    {
        if( Pmx.debug === true && Pmx.console.warn === true )
        {
            console.warn( 'setBounds: ' + e.description );
        }
    }

    timer.stop();
};

/**
 * @description
 * Sets the fill colour for the zone polygon.
 */
Pmx.Map.setFillColor = function( elem )
{
    Pmx.Map._zoneFillColor = Pmx.rgb2hex( elem.style.backgroundColor );
    console.debug( Pmx.Map._zoneFillColor );
};

/**
 * @description
 * Sets the language to 'en' or 'fr'.
 *
 * @param {string} val [en | fr]
 */
Pmx.Map.setLang = function( val )
{
    if( val == 'fr' || val == 'FR' ){
        Pmx.lang = 'fr';
    }
    else{
        Pmx.lang = 'en';
    }
    Pmx.Map.updateLanguageLabels();
    Pmx.Map.updateMap();
};

/**
 * @description
 * Center the map over a location based on lat/lon pair.
 */
Pmx.Map.setLatLon = function( lat, lon )
{
    if( lat ) { Pmx.Map.latitude = parseFloat( lat, 10 ); }
    if( lon ) { Pmx.Map.longitude = parseFloat( lon, 10 ); }

    var latlon = new VELatLong( Pmx.Map.latitude, Pmx.Map.longitude );

    Pmx.Map._VE.SetCenter( latlon );
    Pmx.Map.handleUpdateMap();
};

/**
 * @description
 * Center the map over a location based on lat/lon string.
 */
Pmx.Map.setLocation = function( val,destElemId )
{
    
    if( document.getElementById( destElemId ) )
    {
        document.getElementById( destElemId ).style.display = 'none';
    }
    
    var coords = val.split( ',' );
    if( coords[2]!=='' )
    {
        document.getElementById( 'city_search' ).value = coords[2];
    }    

    Pmx.Map.latitude = parseFloat( coords[ 0 ], 10 );
    Pmx.Map.longitude = parseFloat( coords[ 1 ], 10 );

    var latlon = new VELatLong( Pmx.Map.latitude, Pmx.Map.longitude );

    //Pmx.Map._VE.SetCenter( latlon );
    Pmx.Map._VE.SetCenterAndZoom(latlon,9); //set the zoom level to 9 for city search 18 Aug 2008
    Pmx.Map.handleUpdateMap();
};

/**
 * @description
 * Show the selected tab section and hide the others.
 */
Pmx.Map.showTabSection = function( selectedTabId )
{
    var selectedTabPrefix = selectedTabId.replace( /_section/, '' ); // TODO: suffix should not be hard-coded
    if( document.getElementById( Pmx.Map.elemId.tab_bar ) )
    {
        // get the tabbed elements
        var tabElems = document.getElementById( Pmx.Map.elemId.tab_bar ).getElementsByTagName( 'li' );
        // highlight the selected tab and unhighlight the others
        var tabElemPrefix;
        for( var h = 0; h < tabElems.length; h++ )
        {
            tabElemPrefix = tabElems[ h ].id.replace( /_tab/, '' ); // TODO: suffix should not be hard-coded
            if( tabElemPrefix == selectedTabPrefix )
            {
                tabElems[ h ].className = 'tab-selected'; // TODO: style should not be hard-coded
            }
            else
            {
                tabElems[ h ].className = 'tab-unselected'; // TODO: style should not be hard-coded
            }
        }
        // find the tabbed sections
        var tabDivElems = document.getElementById( Pmx.Map.elemId.tabbed_section ).getElementsByTagName( 'div' );
        var tabSectionElems = [];
        for( var i = 0; i < tabDivElems.length; i++ )
        {
            if( tabDivElems[ i ].id.match( '_section' ) )
            {
                tabSectionElems.push( tabDivElems[ i ] );
            }
        }
        // enable the selected tab section and disable the others
        for( var j = 0; j < tabSectionElems.length; j++ )
        {
            if( tabSectionElems[ j ].id == selectedTabId ){
                tabSectionElems[ j ].style.display = 'block';
            }
            else{
                tabSectionElems[ j ].style.display = 'none';
            }
        }
    }
};

/**
 * @description
 * Toggle the Virtual Earth dashboard.
 */
Pmx.Map.toggleDashboard = function( elem )
{
    if( elem )
    {
        if( elem.checked )
        {
            Pmx.Map._VE.ShowDashboard();
        }
        else
        {
            Pmx.Map._VE.HideDashboard();
        }
    }
};

/**
 * @description
 * Toggle the Virtual Earth mini map.
 */
Pmx.Map.toggleMiniMap = function( elem )
{
    if( elem )
    {
        if( elem.checked )
        {
            var xoffset = parseInt( Pmx.Map._elems.map.style.width, 10 ) - 160;
            var yoffset = parseInt( Pmx.Map._elems.map.style.height, 10 ) - 180;

            Pmx.Map._VE.ShowMiniMap( xoffset, yoffset );
        }
        else
        {
            Pmx.Map._VE.HideMiniMap();
        }
    }
};

/**
 * @description
 * Toggle the mouse wheel setting to enable/disable zooming with the wheel.
 */
Pmx.Map.toggleMouseWheel = function( elem )
{
    if( elem )
    {
        if( elem.checked )
        {
            Pmx.Map._zoomWheel = true;
            Pmx.Map._VE.DetachEvent( 'onmousewheel', Pmx.Map.onMouseWheel );
        }
        else
        {
            Pmx.Map._zoomWheel = false;
            Pmx.Map._VE.AttachEvent( 'onmousewheel', Pmx.Map.onMouseWheel );
        }
    }
};

/**
 * @description
 * Update the inner HTML of an element
 */
Pmx.Map.updateElemInnerHTML = function( elemId, html )
{
    if( document.getElementById( elemId ) && html )
    {
        document.getElementById( elemId ).innerHTML = html;
    }
};

/**
 * @description
 * Update the value of an element
 */
Pmx.Map.updateElemVal = function( elemId, val )
{
    if( document.getElementById( elemId ) && val )
    {
        document.getElementById( elemId ).value = val;
    }
};

/**
 * @description
 * Update the language of the labels.
 */
Pmx.Map.updateLanguageLabels = function()
{
    var timer = new Pmx.Timer( 'updateLanguageLabels' );
    timer.start();

    try
    {
        var elem;

        // update text in loading dialog
        Pmx.Map.updateElemInnerHTML( Pmx.Map.elemId.spinner_txt, Pmx.LU.Map.roads_lbl.ld[ Pmx.lang ] );
        // update text in Virtual Earth
        for( var e in Pmx.LU.Map.roads_ve_lbl )
        {
            elem = document.getElementById( e );

            if( elem.innerHTML && Pmx.LU.Map.roads_ve_lbl[ e ].label[ Pmx.lang ] )
            {
                elem.innerHTML = Pmx.LU.Map.roads_ve_lbl[ e ].label[ Pmx.lang ];
            }

            if( elem.title && Pmx.LU.Map.roads_ve_lbl[ e ].title[ Pmx.lang ] )
            {
                elem.title = Pmx.LU.Map.roads_ve_lbl[ e ].title[ Pmx.lang ];
            }
        }

    }
    catch( err )
    {
        if( Pmx.debug === true && Pmx.console.warn === true )
        {
            console.warn( 'updateLanguageLabels: ' + err );
        }
    }

    timer.stop();
};

/**
 * @description
 * Update the map on a pan or zoom event.
 */
Pmx.Map.updateMap = function( )
{
    var timer = new Pmx.Timer( 'updateMap' );
    timer.start();

    window.clearTimeout( Pmx.Map._updateMapTimer );

    Pmx.Map._screen.w = parseInt( Pmx.Map._elems.map.style.width, 10 );
    Pmx.Map._screen.h = parseInt( Pmx.Map._elems.map.style.height, 10 );

    // check if the zoom level changed
    var zoomed = false;
    if( Pmx.Map._VE.GetZoomLevel() != Pmx.Map.zoomLevel )
    {
        zoomed = true;
        Pmx.Map.zoomLevel = Pmx.Map._VE.GetZoomLevel();

        // reset bounds
        Pmx.Map._boundsExt.x1 = 0;
        Pmx.Map._boundsExt.y1 = 0;
        Pmx.Map._boundsExt.x2 = 0;
        Pmx.Map._boundsExt.y2 = 0;

        Pmx.Map._boundsView.x1 = 0;
        Pmx.Map._boundsView.y1 = 0;
        Pmx.Map._boundsView.x2 = 0;
        Pmx.Map._boundsView.y2 = 0;
    }

    if( Pmx.Map._elems.stat_zoom ) { Pmx.Map._elems.stat_zoom.innerHTML = Pmx.Map.zoomLevel; }

    if( !Pmx.Map._elems.opt_road_conditions || Pmx.Map._elems.opt_road_conditions.checked === true )
    {
        try
        {
            var updated = Pmx.Map.setBounds();

            if( zoomed === true || updated === true )
            {
                // clear map table
                Pmx.Map.updateElemInnerHTML( Pmx.Map.elemId.hwycond_table, '' );

                // clear stats
                Pmx.Map.updateElemInnerHTML( Pmx.Map.elemId.stat_shield_cnt, '' );
                Pmx.Map.updateElemInnerHTML( Pmx.Map.elemId.stat_segment_cnt, '' );
                Pmx.Map.updateElemInnerHTML( Pmx.Map.elemId.stat_vertice_cnt, '' );
                Pmx.Map.updateElemInnerHTML( Pmx.Map.elemId.stat_density, '' );
                Pmx.Map.updateElemInnerHTML( Pmx.Map.elemId.stat_time, '' );

                Pmx.Map.updateElemInnerHTML( Pmx.Map.elemId.stat_fetch, 'true' );

                if(Pmx.Map._currentLayer[Pmx.Map.CAMERA] == true){
                    Pmx.Map.updateTrafficCamera();
                }
                if(Pmx.Map._currentLayer[Pmx.Map.INCIDENT] == true){
                    Pmx.Map.updateTrafficIncident();
                }
                if(Pmx.Map._currentLayer[Pmx.Map.FLOW] == true){
                    //if(Pmx.Map._trafficFlowLayer){
                    //    Pmx.Map._trafficFlowLayer.DeleteAllShapes();
                    //}
                    //Pmx.Map._trafficFlowLayer.DeleteAllShapes();
                    Pmx.Map._trafficFlowLayer.Hide();
                    Pmx.Map.updateTrafficFlow();
                }
                if(Pmx.Map._currentLayer[Pmx.Map.WEATHER] == true){
                    Pmx.Map.updateWeather();
                }
            }
        }
        catch( e )
        {
            //Pmx.Map.hideLoading();

            if( Pmx.debug === true && Pmx.console.error === true )
            {
                //console.error( 'updateMap: ' + e );
                console.debug( 'updateMap: ' + e );
            }
        }
    }

    timer.stop();
};

/**
 * @description
 * Update the map style for switching the road colours.
 */
Pmx.Map.updateMapStyle = function()
{
    Pmx.Map.mapStyle = Pmx.Map._VE.GetMapStyle();

    if( Pmx.Map.mapStyle == 'r' )
    {
        Pmx.Map.mapStyle = 's';
    }

    Pmx.Map.saveMapState();

    //Pmx.Map.drawRoads();
};
//==========================IMPLEMENTATION BY DANIEL=========================BEGIN//
/**
 *Function Name: updateWeather
 * @description
 * Update the weather map.
 * Implement 29 May 2008
 * author: Daniel
 */
Pmx.Map.updateWeather = function()
{
    var timer = new Pmx.Timer( 'updateWeather' );
    timer.start();

    Pmx.Map._currentLayer[Pmx.Map.WEATHER] = true;
    
    var url = Pmx.Map.getJsonUrl(Pmx.Map.WEATHER);
    if( Pmx.debug === true && Pmx.console.warn === true ){
        console.debug( 'JSR: ' + url );
    }
    Pmx.Map.sendJSR( url );

    timer.stop();
};
/**
 *Function Name: drawWeather
 * @description
 * Draw the weather map. This is a callback function for a JSR response.
 * Implement 29 May 2008
 * author: Daniel
 */
Pmx.Map.drawWeather = function()
{
    var timer = new Pmx.Timer( 'drawWeather' );
    timer.start();

    var numLocs = RS.M.length;

    try
    {
        if( numLocs > 0 )
        {
            //remove all other layers
            //Pmx.Map.ClearAll();
            //Pmx.Map._weatherLayer.DeleteAllShapes();
            //document.getElementById('counter').innerHTML = numLocs;
            // add weather layer
            Pmx.Map._weatherLayer = new VEShapeLayer();
            Pmx.Map._weatherLayer.ZIndex = 6;

           var html;
           //alert('Number of weather station: '+numLocs);
            for( var i = 0; i < numLocs; i++ )
            {
                loc = RS.M[ i ];
                obs = new VEShape( VEShapeType.Pushpin, new VELatLong( loc.Y, loc.X ) );

                html  = '<div>';
                html += '<table border="0" cellpadding="2" cellspacing="0">';
                html += '<tr><td colspan="2">===========</td></tr>';
                html += '<tr><td class="weather-label">I:</td><td>' + loc.I + '</td></tr>';
                html += '<tr><td class="weather-label">X:</td><td>' + loc.X + '</td></tr>';
                html += '<tr><td class="weather-label">Y:</td><td>' + loc.Y + '</td></tr>';
                html += '<tr><td class="weather-label">CF:</td><td>' + loc.CF + '</td></tr>';
                html += '<tr><td class="weather-label">TC:</td><td>' + loc.TC + '</td></tr>';
                html += '<tr><td class="weather-label">HX:</td><td>' + loc.HX + '</td></tr>';
                html += '<tr><td class="weather-label">HY:</td><td>' + loc.HY + '</td></tr>';
                html += '<tr><td class="weather-label">TS:</td><td>' + Pmx.Map.EpochToDate(loc.TS) + '</td></tr>';
                html += '<tr><td class="weather-label">VY:</td><td>' + loc.VY + '</td></tr>';
                html += '<tr><td class="weather-label">WC:</td><td>' + loc.WC + '</td></tr>';
                html += '<tr><td class="weather-label">WM:</td><td>' + loc.WM + '</td></tr>';
                html += '<tr><td class="weather-label">WD:</td><td>' + loc.WD + '</td></tr>';
                html += '<tr><td class="weather-label">IC:</td><td>' + loc.IC + '</td></tr>';
                html += '<tr><td class="weather-label">DS:</td><td>' + loc.DS + '</td></tr>';
                html += '<tr><td colspan="2">===========</td></tr>';
                html += '</table>';
                html += '</div>';
                obs.SetTitle( '<div class="map_popup_bar">' + 'Observation' + '</div>' );
                obs.SetDescription( html );
                obs.SetCustomIcon( '<div id="' + i + '"><img src="' + Pmx.Map.imgRoot + 'obs.png" /></div>' );

                Pmx.Map._weatherLayer.AddShape( obs );
            }

            Pmx.Map._VE.AddShapeLayer( Pmx.Map._weatherLayer );
        }
        else
        {
            if( Pmx.debug === true && Pmx.console.warn === true )
            {
                console.warn( 'No weather data found!' );
            }
        }
    }
    catch( e )
    {
        if( Pmx.debug === true && Pmx.console.error === true )
        {
            console.error( 'drawWeather: ' + e.description );
        }
    }

    Pmx._jsr.removeScriptTag();

    timer.stop();
};
//==============================================================================
/**
 *Function Name: updateTrafficCamera
 * @description
 * Update the traffic camera map.
 * Implement 21 Apr 2008
 * author: Daniel
 */
Pmx.Map.updateTrafficCamera = function()
{
    //Pmx.Map.RemoveMyControl();
    var timer = new Pmx.Timer( 'updateTrafficCamera' );
    timer.start();

    nd();   //remove the mouse over pop up

    var zoomInDetail ='';
    //display the loading icon
    switch(lang){
        case 'fr':
            Pmx.Map.showLoading( 'Chargement en cours...' );
            //zoomInDetail = 'Cliquez pour voir les caméras de circulation dans cette zone';
            zoomInDetail = 'Cliquez pour voir les caméras de circulation ';
            break;
        case 'en':
        default:
            Pmx.Map.showLoading( 'Loading...' );
            //zoomInDetail = 'Click to see traffic cameras in this area';
            zoomInDetail = 'Click to see traffic cameras in ';
    }

    var zoomLevel = Pmx.Map._VE.GetZoomLevel();
    
    if(zoomLevel < 5){
        //remove the msg window if it shows on the map
        Pmx.Map.RemoveMyControl();
 
        // add traffic camera layer
        if(Pmx.Map._trafficCameraLayer){Pmx.Map._trafficCameraLayer.Hide();}
        Pmx.Map._trafficCameraLayer = new VEShapeLayer();
        Pmx.Map._trafficCameraLayer.ZIndex = 5;

        var camRS = TC_National.M;
        var numCameras = camRS.length;

        if(camRS != ''){
            for( var j =0 ;j < numCameras; j++ ){
                var superCamera = new VEShape( VEShapeType.Pushpin, new VELatLong( camRS[j].Y, camRS[j].X ) );
                superCamera.SetCustomIcon( '<div id="superIcon" onmouseover="overlib(\''+ zoomInDetail + camRS[j][lang] +'\');" onclick="Pmx.Map.hidePopup(); Pmx.Map.superIconZoomin(\''+ camRS[j].X + '\',\'' + camRS[j].Y + '\',\'0\',\'' + camRS[j].Z +'\');" onmouseout="return nd();" ><img src="' + Pmx.Map.imgRoot + 'camera-supericon.png" /></div>' );
                Pmx.Map._trafficCameraLayer.AddShape( superCamera );
            }
    
            Pmx.Map._VE.AddShapeLayer( Pmx.Map._trafficCameraLayer );
            //if show the camera on the map
            if(document.getElementById('traffic_camera').checked == true){
             Pmx.Map._trafficCameraLayer.Show();
            }
            else{
             Pmx.Map._trafficCameraLayer.Hide();
            }
        }
        //hide the loading icon
        Pmx.Map.hideLoading();
    }
    else{
        //set the curret shape layer to camera
        Pmx.Map._currentLayer[Pmx.Map.CAMERA] = true;
        var url = Pmx.Map.getJsonUrl(Pmx.Map.CAMERA);
        if( Pmx.debug === true && Pmx.console.error === true ){
            console.debug( 'JSR: ' + url );
        }
        Pmx.Map.sendJSR( url );
    }

    //if( Pmx.debug === true && Pmx.console.error === true ){
    //    console.debug( 'error: ' + e );
    //}
    
    timer.stop();
};
/**
 *Function Name: drawTrafficCamera
 * @description
 * Draw traffic camera on the map
 * Implement 21 Apr 2008
 * author: Daniel
 */
Pmx.Map.drawTrafficCamera = function()
{
    Pmx.Map.RemoveMyControl();
    var timer = new Pmx.Timer( 'drawTrafficCamera' );
    timer.start();

    var camRS = RS.M;
    var numCameras = camRS.length;
    //alert(numCameras);
    try
    {
        if( numCameras > 0 )
        {
            ////TESTING --SHOULD BE REMOVED
            //document.getElementById('counter').innerHTML = numCameras +':'+ Pmx.Map.zoomLevel;

            // add traffic camera layer
            if(Pmx.Map._trafficCameraLayer){Pmx.Map._trafficCameraLayer.Hide();}
            Pmx.Map._trafficCameraLayer = new VEShapeLayer();
            Pmx.Map._trafficCameraLayer.ZIndex = 5;
            //var camera,html,camId,camX,canY,camD,camT,camP,camS,camU,camC,camL,camO,camR,camV,camPV;
            var camera,html,camId,camX,canY,camD;
            var camTitle ='';

            // loop through all the cameras
            var overLap = false;
            var superIconFlag = false;
            var superIconBeginPosX = '',superIconBeginPosY = '';
            var superIconEndPosX = '',superIconEndPosY = '';
            var superIconCount = 1;
            var superIconPos = '';
            for( var j = 0; j < numCameras; j++ )
            {
                if(j<(numCameras-1)){
                    if(overLap == false){
                        superIconBeginPosX = camRS[j].X;
                        superIconBeginPosY = camRS[j].Y;
                    }
                    overLap = Pmx.Map.checkOverlap(camRS[j].X, camRS[j].Y, camRS[j+1].X, camRS[j+1].Y);
                }
                else if (j==(numCameras-1)){
                    overLap = false;
                }
                    if(overLap === true){
                        superIconFlag = true;
                        superIconCount++;
                        camRS[j+1].X = (superIconBeginPosX + camRS[j+1].X)/2;
                        camRS[j+1].Y = (superIconBeginPosY + camRS[j+1].Y)/2;
                        superIconPos = j + 1;
                    }
                    else if(superIconFlag === true && Pmx.Map._VE.GetZoomLevel() < 16){
                        Pmx.Map.zoomLevel++;
                        switch(lang){
                            case 'fr':
                                Pmx.Map.showLoading( 'Chargement en cours...' );
                                zoomInMoreCamera = 'Faites un zoom pour voir '+superIconCount+' caméras supplémentaires';
                                break;
                            case 'en':
                            default:
                                Pmx.Map.showLoading( 'Loading...' );
                                zoomInMoreCamera = 'Zoom in to see '+superIconCount+' more cameras';
                        }

                        //zoomInMoreCamera = '<div class=\"rollover\"><div class=\"rollover-top\"></div><div class=\"rollovercamera\">'+ zoomInMoreCamera +'</div><div class=\"rollover-bottom\"></div></div>';

                        var superCamera = new VEShape( VEShapeType.Pushpin, new VELatLong( camRS[superIconPos].Y, camRS[superIconPos].X ) );
                        superCamera.SetCustomIcon( '<div id="superIcon" onmouseover="overlib(\''+ zoomInMoreCamera + '\');" onclick="Pmx.Map.hidePopup(); Pmx.Map.superIconZoomin(\''+ camRS[superIconPos].X + '\',\'' + camRS[superIconPos].Y + '\',\'' + superIconCount + '\',\''+ Pmx.Map._VE.GetZoomLevel() +'\');" onmouseout="return nd();" ><img src="' + Pmx.Map.imgRoot + 'camera-supericon.png" /></div>' );
                        
                        Pmx.Map._trafficCameraLayer.AddShape( superCamera );
                        superIconFlag = false;
                        overLap = false;
                        superIconCount = 1;
                        superIconPos = '';
                    }
                    else {
                        camId = camRS[ j ].I;
                        camX = camRS[ j ].X;
                        camY = camRS[ j ].Y;
                        camD = camRS[ j ].D;
                        camD = camD.replace(/'/g, "&rsquo;");   //replace the single quote for French.
                        //camT = camRS[ j ].T;
                        //camP = camRS[ j ].P;
                        //camR = camRS[ j ].R;
                        //camS = camRS[ j ].S;
                        //camU = camRS[ j ].U;
                        //camC = camRS[ j ].C;
                        //camL = camRS[ j ].L;
                        //camO = camRS[ j ].O;
                        //camV = camRS[ j ].V;
                        //camV = camV.replace(/'/g, "&rsquo;");   //replace the single quote for French.
                        //camPV = camRS[ j ].PV;
                        //camTitle = '<div><b>'+ camD +'</b></div>';
                        //camTitle = '<div><b>'+ camD+':'+camId +'</b></div>';
                        //camTitle = '<div class=\"rollover\"><div class=\"rollovercamera\">'+ camD +'</div></div>';
/*
                        //all the data displayed for verifying
                        camTitle = 'Number: '+ j +'<br />';
                        camTitle += 'ID: '+ camId +'<br />';
                        camTitle += 'D: '+ camD +'<br />';
                        camTitle += '===========================<br />';
                        camTitle += 'Number: '+ j +'<br />';
                        camTitle += 'ID: '+ camId +'<br />';
                        camTitle += 'D: '+ camD +'<br />';
                        camTitle += 'C: '+ camC +'<br />';
                        camTitle += 'P: '+ camP +'<br />';
                        camTitle += 'X: '+ camX +'<br />';
                        camTitle += 'Y: '+ camY +'<br />';
                        camTitle += 'T: '+ camT +'<br />';
                        camTitle += 'R: '+ camR +'<br />';
                        camTitle += 's: '+ camS +'<br />';
                        camTitle += 'U: '+ camU +'<br />';
                        camTitle += 'L: '+ camL +'<br />';
                        camTitle += 'O: '+ camO +'<br />';
                        camTitle += 'V: '+ camV +'<br />';
                        camTitle += 'UP: '+ camRS[ j ].UP +'<br />';
                        camTitle += 'A: '+ camRS[ j ].A +'<br />';
                        camTitle += 'B: '+ camRS[ j ].B +'<br />';
                        camTitle += 'PV: '+ camPV +'<br />';
                        camTitle += '===========================';
*/
                        camera = new VEShape( VEShapeType.Pushpin, new VELatLong( camY, camX ) );
                        camera.SetCustomIcon( '<div id="' + camId + '" onmouseover="overlib(\''+ camD +'\'); return true;" onmouseout="return nd();"  onclick="nd(); Pmx.Map.updateTrafficCameraDetail( \'' + camId + '\' );"><img src="' + Pmx.Map.imgRoot + 'camera.png" /></div>' );
                        Pmx.Map._trafficCameraLayer.AddShape( camera );
                    }
            }
            Pmx.Map._VE.AddShapeLayer( Pmx.Map._trafficCameraLayer );
            //if show the camera on the map
            if(document.getElementById('traffic_camera').checked == true){
             Pmx.Map._trafficCameraLayer.Show();
            }
            else{
             Pmx.Map._trafficCameraLayer.Hide();
            }
        }
    }
    catch( e )
    {
        if( Pmx.debug === true && Pmx.console.error === true )
        {
            console.error( 'drawTrafficCamera: ' + e );
        }
    }
    //hide the loading icon
    Pmx.Map.hideLoading();
    //Pmx.Map._timeout = setTimeout( "Pmx.Map.hideLoading()", 1500 );
    timer.stop();
};
/**
 *Function Name: superIconZoomin
 * @description
 * zoom in one zoom level when a super icon is clicked
 * Implement 09 Jul 2008
 * author: Daniel
 * @param X {integer} the super icon long
 * @param Y {integer} the super icon lat
 * @param count {integer} the number of cameras in super icon
 */
Pmx.Map.superIconZoomin = function(X,Y,count,cityZoomLevel){
    try{
        cityZoomLevel = parseInt(cityZoomLevel,10);
        //alert(count+':'+cityZoomLevel+':'+Pmx.Map._VE.GetZoomLevel());
        var superLatLong = new VELatLong(Y,X);
        if(count > 100){
            Pmx.Map.zoomLevel = cityZoomLevel+6;
        }
        else if(count > 20){
            Pmx.Map.zoomLevel = cityZoomLevel+5;
        }
        else if(count >10){
            Pmx.Map.zoomLevel = cityZoomLevel+4;
        }
/*
        if(count > 1){
            Pmx.Map.zoomLevel = cityZoomLevel+4;
        }
                                          */
        else if(count == 0){
            //Pmx.Map.zoomLevel = cityZoomLevel+2;
            Pmx.Map.zoomLevel = cityZoomLevel;
        }
        else{
            //alert('me');
            Pmx.Map.zoomLevel = cityZoomLevel+3;
        }
        //alert(Pmx.Map.zoomLevel);
        Pmx.Map._VE.SetCenterAndZoom(superLatLong, Pmx.Map.zoomLevel);
        Pmx.Map.updateTrafficCamera();
    }
    catch(e)
    {
        if( Pmx.debug === true && Pmx.console.error === true )
        {
            console.error( 'super icon zoom in: ' + e );
        }
    }
};
/**
 *Function Name: updateTrafficCameraDetail
 * @description
 * Update traffic camera detail.
 * Implement 21 Apr 2008
 * author: Daniel
 */
//Pmx.Map.updateTrafficCameraDetail = function( cameraId, cameraX, cameraY, cameraDesc, cameraLink, cameraV, camPV )
Pmx.Map.updateTrafficCameraDetail = function( cameraId )
{
    var timer = new Pmx.Timer( 'updateTrafficCameraDetail' );
    timer.start();
    try
    {
        //alert(RS.M.length);
        // loop through cameras
        var cameraX, cameraY, cameraDesc, cameraLink, cameraV,cameraA,cameraB,cameraS, cameraPV;
        for( var j = 0; j < RS.M.length; j++ )
        {
            if( cameraId === RS.M[ j ].I )
            {
                cameraX = RS.M[ j ].X;
                cameraY = RS.M[ j ].Y;
                cameraLink = RS.M[ j ].U;
                cameraDesc = RS.M[ j ].D;
                cameraDesc = cameraDesc.replace(/'/g, "&rsquo;");   //replace the single quote for French.
                cameraV = RS.M[ j ].V;
                cameraV = cameraV.replace(/'/g, "&rsquo;");   //replace the single quote for French.
                cameraS = RS.M[ j ].S;      //'N' = static image; 'Y' = streaming video
                cameraA = RS.M[ j ].A;
                cameraB = RS.M[ j ].B;
                cameraPV = RS.M[ j ].PV;
                break;
            }
        }
//alert(cameraS);
        //move the map to show the popup windown falls within the map area
        //and then move the map back to the previous position
        var cur_x=0,cur_y=0,new_x = 0,new_y = 0,cur_latLong,pixel;
        var moveDistanceX = 0;
        var moveDistanceY = 0;
        cur_latLong = new VELatLong(cameraY,cameraX);
        pixel = Pmx.Map._VE.LatLongToPixel(cur_latLong, Pmx.Map._VE.GetZoomLevel());
        cur_x = pixel.x;
        cur_y = pixel.y;

        if(cur_x<295){
            moveDistanceX = parseInt(cur_x - 295);
            new_x = 10;
            moveDistanceY = parseInt(cur_y - 57);
        }
        else if(cur_x>560){
            moveDistanceX = parseInt(cur_x - 550);
            new_x = 265;
            moveDistanceY = parseInt(cur_y - 57);
        }
        else{
            moveDistanceX = 0;
            new_x = parseInt(cur_x - 285);
            moveDistanceY = parseInt(cur_y - 57);
        }
        new_y = 5;
        Pmx.Map.updated = false;
        Pmx.Map._VE.Pan(moveDistanceX,moveDistanceY);

        var courtesyOf,thumbnailLink;
        var prevCam ='',nextCam='';
        var prev='',next='',prev_greyedout='',next_greyedout='';
        switch(lang){
            case 'fr':
                courtesyOf = 'Source: ';
                thumbnailLink = '<a href="" onclick="Pmx.Map.showTrafficCameraThumbnail( \'' + cameraId + '\',\'' + cameraLink + '\',\'' + cameraPV + '\' ); return false;">Vous n&rsquo;&ecirc;tes pas certain dans quelle direction pointe la cam&eacute;ra ? Cliquez ici <img src="' + Pmx.Map.imgRoot + 'downarrow.png" border="0" /></a>';
                prev = 'prev_fr.gif';
                next = 'next_fr.gif';
                prev_greyedout = 'prev-greyedout_fr.gif';
                next_greyedout = 'next-greyedout_fr.gif';
                break;
            case 'en':
            default:
                courtesyOf = 'Image courtesy of: ';
                thumbnailLink = '<a href="" onclick="Pmx.Map.showTrafficCameraThumbnail( \'' + cameraId + '\',\'' + cameraLink + '\',\'' + cameraPV + '\' ); return false;">Not sure which way the camera is pointing? <br />Click here <img src="' + Pmx.Map.imgRoot + 'downarrow.png" border="0" /></a>';
                prev = 'prev.gif';
                next = 'next.gif';
                prev_greyedout = 'prev-greyedout.gif';
                next_greyedout = 'next-greyedout.gif';
                break;
        }

        if (Pmx.Map.inArray(cameraA,true)) {
            if(cameraA.replace(/^\s+|\s+$/g,"") !='' && cameraA.replace(/^\s+|\s+$/g,"") !=null){
                prevCam = '<img src="' + Pmx.Map.imgRoot + prev +'" onclick="Pmx.Map.updateTrafficCameraDetail( \'' + cameraA + '\' );" />';
            }
        }
        else{
            prevCam = '<img src="' + Pmx.Map.imgRoot + prev_greyedout +'" style:"cursor: none;"/>';
        }
        if (Pmx.Map.inArray(cameraB,true)) {
            if(cameraB.replace(/^\s+|\s+$/g,"") !='' && cameraB.replace(/^\s+|\s+$/g,"") !=null){
                nextCam = '<img src="' + Pmx.Map.imgRoot + next +'" onclick="Pmx.Map.updateTrafficCameraDetail( \'' + cameraB + '\' );" />';
            }
        }
        else{
            nextCam = '<img src="' + Pmx.Map.imgRoot + next_greyedout +'" style:"cursor: none;"/>';
        }

        var html = '';
        html = '<div class="camerapopuptop"></div>';
        html += '<div class="camerapopuptitle">';
        html += '<div class="close"><img src="' + Pmx.Map.imgRoot + 'close.png" onmouseover="this.src=\'' + Pmx.Map.imgRoot + 'close-mouseover.png\';" onmouseout="this.src=\'' + Pmx.Map.imgRoot + 'close.png\';" onclick="Pmx.Map.hidePopup(\''+moveDistanceX+'\',\''+moveDistanceY+'\');" alt="" title="" /></div>';
        html += cameraDesc;
        html += '<div class="prevarrow">'+prevCam+'</div>';
        
        html += '<div class="nextarrow">'+nextCam+'</div>';
        html += '</div>';
        
        html += '<div class="camerapopupbottom">';
        if(cameraS =='Y'){  //
            html += '<div class="liveimage">';
            html += Pmx.Map.getVideoHTML(cameraLink);
            /*
            html += '<OBJECT ID="MediaPlayer" WIDTH="192" HEIGHT="180" CLASSID="CLSID:22D6F312-B0F6-11D0-94AB-0080C74C7E95" STANDBY="Loading Windows Media Player components..." TYPE="application/x-oleobject">';
            html += '<PARAM NAME="URL" VALUE="http://boss.streamos.com/wmedia-live/coe/16547/46_coe-camerafourteen_070201.asx?endtime=86400000">';
            html += '<PARAM name="autostart" VALUE="true">';
            html += '<PARAM name="ShowControls" VALUE="true">';
            html += '<param name="ShowStatusBar" value="true">';
            html += '<PARAM name="ShowDisplay" VALUE="false">';
            html += '<EMBED TYPE="application/x-mplayer2" SRC="' + cameraLink + '" NAME="MediaPlayer" WIDTH="192" HEIGHT="180" ShowControls="1" ShowStatusBar="0" ShowDisplay="0" autostart="0"> </EMBED>';
            //html += '<EMBED TYPE="application/x-mplayer2" SRC="http://boss.streamos.com/wmedia-live/coe/16547/46_coe-camerafourteen_070201.asx?endtime=86400000" NAME="MediaPlayer" WIDTH="240" HEIGHT="180" ShowControls="1" ShowStatusBar="0" ShowDisplay="0" autostart="0"> </EMBED>';            
            html += '</OBJECT>';
       */
            //html += '<embed type="application/x-mplayer2" pluginspage="http://www.microsoft.com/Windows/MediaPlayer/" name="mediaplayer1" ShowStatusBar="true" EnableContextMenu="true" uiMode="full" autostart="true" width="240" height="190" loop="false" src="' + cameraLink + '" />';
            html += '</div>';
        }
        else{
            html += '<div class="liveimage"><img src="' + cameraLink + '" width="240px" height="190px" border="0" onclick="Pmx.Map.hidePopup(\''+moveDistanceX+'\',\''+moveDistanceY+'\');" /></div>';
        }
        
        html += '<div id="imageDesc">';
        html += '<div class="courtesy">'+courtesyOf+'<strong>'+cameraV+'</strong></div>';
            html += '<div id="thumbnailLink" class="question">';
            html += thumbnailLink;
            html += '</div>';
        html += '</div>';
        html += '<div id="thumbnailImage" class="thumbs"></div>';
        html += '</div>';

        document.getElementById( Pmx.Map.elemId.map_popup ).style.display = 'block';
        document.getElementById( Pmx.Map.elemId.map_popup ).style.left = new_x + 'px';
        document.getElementById( Pmx.Map.elemId.map_popup ).style.top = new_y + 'px';
        Pmx.Map.updateElemInnerHTML( Pmx.Map.elemId.map_popup, html );
        //alert(RS.M.length);
        //Pmx.Map.updateTrafficCamera();
/*
        var obj = document.getElementById("MediaPlayer");
        obj.URL = cameraLink;
        obj.Settings.autoStart = true;
                                     */      
    }
    catch( e )
    {
        if( Pmx.debug === true && Pmx.console.error === true )
        {
            console.error( 'updateTrafficCameraDetail: ' + e );
        }
    }

    timer.stop();
};
/**
 *Function Name: showTrafficCameraThumbnail
 * @description
 * Show traffic camera thumbnails
 * Implement 21 Jun 2008
 * author: Daniel
 */
Pmx.Map.showTrafficCameraThumbnail = function(cameraId,cameraLink,cameraPV)
{
/*
    //http://72.14.162.214:8080/thumbnails/TCAB0430001_E.jpg
    //http://72.14.162.214:8080/thumbnails/TCONGTA4010028_W.jpg
    //http://72.14.162.214:8080/thumbnails/TCOQCMTL0400017_E.jpg
    //http://72.14.162.214:8080/thumbnails/TCONGDR006_W.jpg
    //var fileNmae = cameraLink.substr(67);
    //var fileLink = cameraLink.substr(0,67);
    //alert(fileLink);
*/

    //var cameraThumbnailUrl = 'http://72.14.162.214:8080/thumbnails/';
    var cameraThumbnailUrl = 'common/images/traffic_cams/thumbnails/';
    var thumbnailName_N  = '';
    var thumbnailName_NE = '';
    var thumbnailName_E  = '';
    var thumbnailName_SE = '';
    var thumbnailName_S  = '';
    var thumbnailName_SW = '';
    var thumbnailName_W  = '';
    var thumbnailName_NW = '';
    var thumbnailName_TB = '';
    var thumbnailName_NB = '';

    var lookingN,lookingNE,lookingE,lookingSE,lookingS,lookingSW,lookingW,lookingNW,lookingTB,lookingNB,noThumbnail;
    var thumbnailClose;
    switch(lang){
        case 'fr':
            lookingN = 'Vers Nord';
            lookingNE = 'Vers Nord-Est';
            lookingE = 'Vers Est';
            lookingSE = 'Vers Sud-Est';
            lookingS = 'Vers Sud';
            lookingSW = 'Vers Sud-Ouest';
            lookingW = 'Vers Ouest';
            lookingNW = 'Vers Nord-Ouest';
            lookingTB = 'Vers Toronto';
            lookingNB  = 'Vers Niagara';
            noThumbnail = 'Pas d&rsquo;aperçu disponible';
            thumbnailClose = ' onclick="Pmx.Map.hideTrafficCameraThumbnail();" ';
            break;
        case 'en':
        default:
            lookingN = 'Looking North';
            lookingNE = 'Looking North East';
            lookingE = 'Looking East';
            lookingSE = 'Looking South East';
            lookingS = 'Looking South';
            lookingSW = 'Looking South West';
            lookingW = 'Looking West';
            lookingNW = 'Looking North West';
            lookingTB = 'Toronto Bound';
            lookingNB  = 'Niagara Bound';
            noThumbnail = 'No thumbnails available. ';
            thumbnailClose = 'onclick="Pmx.Map.hideTrafficCameraThumbnail();"';
            break;
    }

    var counter = 0;    //count and limit it to max 4
    var thumbnailImages = '';
    for(var i=0; i<cameraPV.length;i++){
        if(cameraPV.substring(i,i+1)==1){
            switch (i+1){
                case 1:
                    thumbnailName_N = cameraThumbnailUrl + cameraId.toLowerCase()+'_n.jpg';
                    //thumbnailImages += '<td>'+lookingN+'<br /><img src="' + thumbnailName_N + '" width="60px" height="45px" border="0"/></td>';
                    thumbnailImages += '<div class="thumb"><img src="' + thumbnailName_N +'" '+thumbnailClose +'/><br />'+lookingN+'</div>';
                    break;
                case 2:
                    thumbnailName_NE = cameraThumbnailUrl + cameraId.toLowerCase()+'_ne.jpg';
                    //thumbnailImages += '<td>'+lookingNE+'<br /><img src="' + thumbnailName_NE + '" width="60px" height="45px" border="0"/></td>';
                    thumbnailImages += '<div class="thumb"><img src="' + thumbnailName_NE +'" '+thumbnailClose +'/><br />'+lookingNE+'</div>';
                    break;
                case 3:
                    thumbnailName_E = cameraThumbnailUrl + cameraId.toLowerCase()+'_e.jpg';
                    //thumbnailImages += '<td>'+lookingE+'<br /><img src="' + thumbnailName_E + '" width="60px" height="45px" border="0"/></td>';
                    thumbnailImages += '<div class="thumb"><img src="' + thumbnailName_E +'" '+thumbnailClose +'/><br />'+lookingE+'</div>';
                    break;
                case 4:
                    thumbnailName_SE = cameraThumbnailUrl + cameraId.toLowerCase()+'_se.jpg';
                    //thumbnailImages += '<td>'+lookingSE+'<br /><img src="' + thumbnailName_SE + '" width="60px" height="45px" border="0"/></td>';
                    thumbnailImages += '<div class="thumb"><img src="' + thumbnailName_SE +'" '+thumbnailClose +'/><br />'+lookingSE+'</div>';
                    break;
                case 5:
                    thumbnailName_S = cameraThumbnailUrl + cameraId.toLowerCase()+'_s.jpg';
                    //thumbnailImages += '<td>'+lookingS+'<br /><img src="' + thumbnailName_S + '" width="60px" height="45px" border="0"/></td>';
                    thumbnailImages += '<div class="thumb"><img src="' + thumbnailName_S +'" '+thumbnailClose +'/><br />'+lookingS+'</div>';
                    break;
                case 6:
                    thumbnailName_SW = cameraThumbnailUrl + cameraId.toLowerCase()+'_sw.jpg';
                    //thumbnailImages += '<td>'+lookingSW+'<br /><img src="' + thumbnailName_SW + '" width="60px" height="45px" border="0"/></td>';
                    thumbnailImages += '<div class="thumb"><img src="' + thumbnailName_SW +'" '+thumbnailClose +'/><br />'+lookingSW+'</div>';
                    break;
                case 7:
                    thumbnailName_W = cameraThumbnailUrl + cameraId.toLowerCase()+'_w.jpg';
                    //thumbnailImages += '<td>'+lookingW+'<br /><img src="' + thumbnailName_W + '" width="60px" height="45px" border="0"/></td>';
                    thumbnailImages += '<div class="thumb"><img src="' + thumbnailName_W +'" '+thumbnailClose +'/><br />'+lookingW+'</div>';
                    break;
                case 8:
                    thumbnailName_NW = cameraThumbnailUrl + cameraId.toLowerCase()+'_nw.jpg';
                    //thumbnailImages += '<td>'+lookingNW+'<br /><img src="' + thumbnailName_NW + '" width="60px" height="45px" border="0"/></td>';
                    thumbnailImages += '<div class="thumb"><img src="' + thumbnailName_NW +'" '+thumbnailClose +'/><br />'+lookingNW+'</div>';
                    break;
                case 9:
                    thumbnailName_TB = cameraThumbnailUrl + cameraId.toLowerCase()+'_tb.jpg';
                    //thumbnailImages += '<td>'+lookingTB+'<br /><img src="' + thumbnailName_TB + '" width="60px" height="45px" border="0"/></td>';
                    thumbnailImages += '<div class="thumb"><img src="' + thumbnailName_TB +'" '+thumbnailClose +'/><br />'+lookingTB+'</div>';
                    break;
                case 10:
                    thumbnailName_NB = cameraThumbnailUrl + cameraId.toLowerCase()+'_nb.jpg';
                    //thumbnailImages += '<td>'+lookingNB+'<br /><img src="' + thumbnailName_NB + '" width="60px" height="45px" border="0"/></td>';
                    thumbnailImages += '<div class="thumb"><img src="' + thumbnailName_NB + thumbnailClose +'" /><br />'+lookingNB+'</div>';
                    break;
                default:
                    break;
            }
            counter++;
        }
        if(counter>=4){
            break;
        }
    }
    if(counter==0){
        thumbnailImages = '<div class="question">'+noThumbnail+'<img src="' + Pmx.Map.imgRoot + 'close.png" onmouseover="this.src=\'' + Pmx.Map.imgRoot + 'close-mouseover.png\';" onmouseout="this.src=\'' + Pmx.Map.imgRoot + 'close.png\';"'+thumbnailClose+' /></div>';
    }
/*    
    html = '<table><tr>';
    html += thumbnailImages;
    html += '<td align="right" valign="top"><img src="' + Pmx.Map.imgRoot + 'close_aero_off.gif" onmouseover="this.src=\'' + Pmx.Map.imgRoot + 'close_aero_on.gif\';" onmouseout="this.src=\'' + Pmx.Map.imgRoot + 'close_aero_off.gif\';" onclick="Pmx.Map.hideTrafficCameraThumbnail();" alt="Close" title="Close" /></td></tr></table>';
     */  
    document.getElementById( 'imageDesc' ).style.display = 'none';
    //document.getElementById( 'imageCourtesy' ).style.display = 'none';
    document.getElementById( 'thumbnailImage' ).style.display = 'block';
    document.getElementById( 'thumbnailImage' ).innerHTML = thumbnailImages;
}
/**
 *Function Name: hideTrafficCameraThumbnail
 * @description
 * Hide traffic camera thumbnails
 * Implement 21 Jun 2008
 * author: Daniel
 */
Pmx.Map.hideTrafficCameraThumbnail = function()
{
    document.getElementById( 'thumbnailImage' ).style.display = 'none';
    document.getElementById( 'imageDesc' ).style.display = 'block';
}
//==============================================================================
/**
 *Function Name: updateTrafficIncident
* @description
* Update the traffic incident map
 * Implement 01 May 2008
 * author: Daniel
*/
Pmx.Map.updateTrafficIncident = function()
{
    var timer = new Pmx.Timer( 'updateTrafficIncident' );
    timer.start();

    //set the curret selected tab to INCIDENT
    Pmx.Map._currentLayer[Pmx.Map.INCIDENT] = true;
    var url = Pmx.Map.getJsonUrl(Pmx.Map.INCIDENT);
    if( Pmx.debug === true && Pmx.console.error === true ){
        console.debug( 'JSR: ' + url );
    }
    try{
        Pmx.Map.sendJSR( url );
    }
    catch( e ){
        if( Pmx.debug === true && Pmx.console.error === true )
        {
            console.error( 'updateTrafficIncident: ' + e);
        }
    }
    
    timer.stop();
};
/**
 * Function Name: drawTrafficIncident
 * @description
 * Draw the traffic incident  map. This is a callback function for a JSR response.
 * Implement 05 May 2008
 * author: Daniel
 */
Pmx.Map.drawTrafficIncident = function()
{
    var timer = new Pmx.Timer( 'drawTrafficIncident' );
    timer.start();

    var numIncidents = RS.M.length;
    //alert( 'Number of Traffic Incidents: '+numIncidents );
    try
    {
        if( numIncidents > 0 )
        {
            ////TESTING 
            //document.getElementById('counter').innerHTML = numIncidents + '&' +Pmx.Map.zoomLevel;

            var pm_title = '';      //rollover display
            var pm_htm = '';
            var title = 'Traffic Incident';
            
            //array to store the incident severity description associate with the integer value
            var severity_incident = new Array();
            severity_incident[1] = "minimal ";
            severity_incident[2] = "moderate ";
            severity_incident[3] = "serious ";
            severity_incident[4] = "severe ";

            // add traffic camera layer
            Pmx.Map._trafficIncidentLayer = new VEShapeLayer();
            Pmx.Map._trafficIncidentLayer.ZIndex = 5;

            // loop through all the cameras
            for( var i = 0; i < numIncidents; i++ )
            {
                var evt_desc = RS.M[i].DSC; //DEC: incident description
                evt_desc = evt_desc.replace(/&#xA;/gi, '&');
                //=check incident status & transportation index:
                //=1. incident status(STA):
                //only display it if STA = 'A' ->Actiove
                //other values STA ='C' ->Cleared
                //             STA ='O' -> for Other 
                //=2. transportation index(CCL): only display it if CCL = 'F'    //TO ASK ?other values?
                if((RS.M[i].STA == 'A') && (RS.M[i].CCL == 'F')){
                    var pin = new VEShape(VEShapeType.Pushpin, new VELatLong(RS.M[i].Y, RS.M[i].X));
                    pm_title = 'Incident No: '+ i +'<br />CNM: '+RS.M[i].CNM+ '<br />EID: ' + RS.M[i].EID +'<br />CTG: '+ RS.M[i].CTG;
                    
                    //ONLY added for verifying the returning data
                    pm_title += '<br />==========================';
                    pm_title += '<br />X: ' + RS.M[i].X;
                    pm_title += '<br />Y: ' + RS.M[i].Y;
                    pm_title += '<br />CCL: ' + RS.M[i].CCL;
                    pm_title += '<br />CNM: ' + RS.M[i].CNM;
                    pm_title += '<br />CTG: ' + RS.M[i].CTG;
                    pm_title += '<br />DSC: ' + evt_desc;
                    pm_title += '<br />EID: ' + RS.M[i].EID;
                    pm_title += '<br />LLC: ' + RS.M[i].LLC;
                    pm_title += '<br />LLQ: ' + RS.M[i].LLQ;
                    pm_title += '<br />LCC: ' + RS.M[i].LCC;
                    pm_title += '<br />LCQ: ' + RS.M[i].LCQ;
                    pm_title += '<br />LRC: ' + RS.M[i].LRC;
                    pm_title += '<br />LRQ: ' + RS.M[i].LRQ;
                    pm_title += '<br />LAC: ' + RS.M[i].LAC;
                    pm_title += '<br />ETP: ' + RS.M[i].ETP;
                    pm_title += '<br />LSC: ' + RS.M[i].LSC;
                    pm_title += '<br />RSC: ' + RS.M[i].RSC;
                    pm_title += '<br />RD: ' + RS.M[i].RD;
                    pm_title += '<br />RDI: ' + RS.M[i].RDI;
                    pm_title += '<br />RS: ' + RS.M[i].RS;
                    pm_title += '<br />RSI: ' + RS.M[i].RSI;
                    pm_title += '<br />STA: ' + RS.M[i].STA;
                    pm_title += '<br />SVR: ' + RS.M[i].SVR;
                    pm_title += '<br />TCS: ' + Pmx.Map.EpochToDate(RS.M[i].TCS);
                    pm_title += '<br />TOP: ' + Pmx.Map.EpochToDate(RS.M[i].TOP);
                    pm_title += '<br />TSI: ' + Pmx.Map.EpochToDate(RS.M[i].TSI);
                    pm_title += '<br />TSX: ' + Pmx.Map.EpochToDate(RS.M[i].TSX);
                    pm_title += '<br />==========================';

                    pm_htm += '<html><ul><li>Incident number: ' + i + '</li>';
                    pm_htm += '<li>Category(CTG): ' + RS.M[i].CTG + '</li>';
                    pm_htm += '<li>CNM: ' + RS.M[i].CNM + '</li>';
                    pm_htm += '<li>EID: ' + RS.M[i].EID + '</li>';
                    pm_htm += '<li>Description(DSC): ' + evt_desc + '</li>';
                    pm_htm += '<li>Severity(int): ' + RS.M[i].SVR + '</li>';
                    pm_htm += '<li>Severity(desc): ' + severity_incident[RS.M[i].SVR] + '</li>';

                    //if((RS.M[i].LDC =="F") && (RS.M[i].LAC =="F")){
                    if((RS.M[i].LAC =="F")){
                        //pm_htm += '<li>Road Closure: ' + RS.M[i].LDC + '</li>';
                        //pm_htm += '<li>Road All Closed: ' + RS.M[i].LAC + '</li>';
                        if(RS.M[i].LSC !='F'){
                            pm_htm += '<li>Left Shoulder Closed</li>';    
                        }
                        if(RS.M[i].RSC !='F'){
                            pm_htm += '<li>Right Shoulder Closed</li>';
                        }
                        if(RS.M[i].LLQ > 0){
                            pm_htm += '<li>Left Lane Number Affected: ' + RS.M[i].LLQ + '</li>';
                        }
                        if(RS.M[i].LLC !='F'){
                            pm_htm += '<li>Left Lane Closed</li>';    
                        }
                        if(RS.M[i].LCQ > 0){
                            pm_htm += '<li>Center Lane Number Affected: ' + RS.M[i].LLQ + '</li>';
                        }
                        if(RS.M[i].LCC !='F'){
                            pm_htm += '<li>Center Lane Closed</li>';
                        }
                        if(RS.M[i].LRQ > 0){
                            pm_htm += '<li>Right Lane Number Affected: ' + RS.M[i].LLQ + '</li>';
                        }
                        if(RS.M[i].LRC !='F'){
                            pm_htm += '<li>Right Lane Closed</li>';
                        }
                    }

                    //check incident type(ETP) to display different icons:
                    //1. schedule -   ETP = 'S' (SCHEDULE)--> display incident_schedule.gif
                    //2. unschedule - ETP = 'U' (UNSCHEDULE)(accident) --> display incident_unschedule.gif
                    if(RS.M[i].ETP == 'S'){
                        var trafficIcon = 'incident_schedule.png';
                        if(RS.M[i].TOP){
                            pm_htm += '<li>Opend time: ' + Pmx.Map.EpochToDate(RS.M[i].TOP) + '</li>';    
                        }
                        if(RS.M[i].TCS){
                            pm_htm += '<li>Closed time: ' + Pmx.Map.EpochToDate(RS.M[i].TCS) + '</li>';
                        }
                    }
                    else{
                        var trafficIcon = 'incident_unschedule.png';
                        if(RS.M[i].TSI){
                            pm_htm += '<li>Issued time: ' + Pmx.Map.EpochToDate(RS.M[i].TSI) + '</li>';
                        }
                        if(RS.M[i].TSX){
                            pm_htm += '<li>Expires time: ' + Pmx.Map.EpochToDate(RS.M[i].TSX) + '</li>';
                        }
                    }

                    //pm_htm += '<li>Direction: ' + RS.M[i].RD + '</li>';
                    pm_htm += '<li>Road Section(RS): ' + RS.M[i].RS + '</li>';
                    pm_htm += '</ul></html>';
                    //alert (pm_htm);
                    //pin.SetCustomIcon( '<a href="#" onmouseover="return overlib(\'' + pm_title +'\');" onclick="return overlib(\'' + pm_htm + '\', STICKY, CAPTION, \''+title+'\');return false;" onmouseout="return nd();"><img src=\'' + Pmx.Map.imgRoot + 'traffic_flow1.JPG\' /></a>');
                    //pin.SetCustomIcon( '<a href="#"' + 'onmouseover="return overlib(\'' + pm_title +'\');"' + 'onclick="return overlib(\'' + pm_htm + '\', STICKY, CAPTION, \''+title+'\');return false;"' + 'onmouseout="return nd();">' + '<img src=\'' + Pmx.Map.imgRoot + trafficIcon +'\'/></span>' );

                    pin.SetCustomIcon( '<img src="' + Pmx.Map.imgRoot + trafficIcon +'" onmouseover="return overlib(\'' + pm_title +'\');" onclick="return overlib(\'' + pm_htm + '\', STICKY, CAPTION, \''+title+'\');" onmouseout="return nd();" />');

                //flow.SetCustomIcon( '<img src="' + Pmx.Map.imgRoot + 'marker_red_alpha_sm.png" onmouseover="return overlib(\'' + flow_title +'\');" onclick="return overlib(\'' + pm_htm + '\', STICKY, CAPTION, \''+title+'\');" onmouseout="return nd();" />');

                    //pin.SetCustomIcon( '<img src=\'img/traffic_flow1.JPG\' />');
                    Pmx.Map._trafficIncidentLayer.AddShape(pin);
                    pm_htm = '';
                    //window.status = "Record " + i + " of " + (RS.M.length - 1);
                }
            }
            Pmx.Map._VE.AddShapeLayer( Pmx.Map._trafficIncidentLayer );
        }
        else
        {
            if( Pmx.debug === true && Pmx.console.warn === true )
            {
                console.warn( 'No incident data found!' );
            }
        }
    }
    catch( e )
    {
        if( Pmx.debug === true && Pmx.console.error === true )
        {
            console.error( 'drawTrafficIncident: ' + e);
        }
    }
    timer.stop();
};
//==============================================================================
/**
 * @description
 * Function Name: updateTrafficFlow
 * Update the traffic camera map.
 * Implement 29 Apr 2008
 * author: Daniel
 */
Pmx.Map.updateTrafficFlow = function()
{
    var timer = new Pmx.Timer( 'updateTrafficFlow' );
    timer.start();

    //set the curret selected tab to FLOW
    Pmx.Map._currentLayer[Pmx.Map.FLOW] = true;
    var url = Pmx.Map.getJsonUrl(Pmx.Map.FLOW);
    if( Pmx.debug === true && Pmx.console.warn === true ){
        console.debug( 'JSR: ' + url );
    }
    Pmx.Map.sendJSR( url );

    timer.stop();
};
/**
 * Function Name: drawTrafficFlow
 * @description
 * Draw vector-based Traffic Flow. This is a callback function for a JSR response of updateTrafficFlow.
 * Implement 29 Apr 2008
 * author: Daniel
 */
Pmx.Map.drawTrafficFlow = function()
{
    var timer = new Pmx.Timer( 'drawTrafficFlow' );
    timer.start();

    var points;
    var flow;
    var numSegments = RS.L.length;
    //alert( 'Number of Traffic Flows: '+numSegments );
    try
    {
        if( numSegments > 0 )
        {
            var zoomLevel = Pmx.Map._VE.GetZoomLevel();
            
            ////TESTING
            //document.getElementById('counter').innerHTML = numSegments + '&' +zoomLevel ;

            Pmx.Map._trafficFlowLayer = new VEShapeLayer();
            Pmx.Map._VE.AddShapeLayer(Pmx.Map._trafficFlowLayer);
            
            for( var i = 0; i < numSegments; i++ )
            {
                points = [];
                for( var j = 0; j < RS.L[ i ].P.length; j++ )
                {
                    //alert(RS.L[i].P[j].T);
                    points[ j ] = new VELatLong( RS.L[ i ].P[ j ].T, RS.L[ i ].P[ j ].G );
                }

                var flow_title = Pmx.LU.Map.RoadSegs[RS.L[i].ID].hwy;   //get the hwy name from file: TF_Segment.js
                //all the data displayed for data verifying
                flow_title += '<br />==============================';
                flow_title += '<br />DTC: '+RS.L[i].DTC;
                flow_title += '<br />ID: '+RS.L[i].ID;
                flow_title += '<br />NO: '+RS.L[i].NO;
                flow_title += '<br />ESP: '+RS.L[i].ESP;
                flow_title += '<br />ESU: '+RS.L[i].ESU;
                flow_title += '<br />EDS: '+RS.L[i].EDS;
                flow_title += '<br />CSP: '+RS.L[i].CSP;
                flow_title += '<br />CSU: '+RS.L[i].CSU;
                flow_title += '<br />CDS: '+RS.L[i].CDS;
                flow_title += '<br />PRV: '+RS.L[i].PRV;
                //flow_title += '<br />P.T: '+RS.L[i].P[j].T;
                //flow_title += '<br />P.G: '+RS.L[i].P[j].G;
                flow_title += '<br />==============================';
                
                // set info box
                //var flow_title = "ID:" + RS.L[i].ID;
                var pm_htm = '<html>';
                var title = 'Traffic Flow';
                var ESP_speed = RS.L[i].ESP;
                var CSP_speed = RS.L[i].CSP;     
                var speedLimit = Pmx.LU.Map.RoadSegs[RS.L[i].ID].limit;
                var speedFactor = '-1';     //-1 presents undetermined
                
                pm_htm += '<ul><li>' + Pmx.LU.Map.RoadSegs[RS.L[i].ID].hwy + '</li>';
                
                if(RS.L[i].DTC){
                    pm_htm += '<li>' + Pmx.Map.setISO8601(RS.L[i].DTC) + '</li>';    
                }
                //pm_htm += '<li>Time: ' + RS.L[i].DTC + '</li>';
                pm_htm += '<li>Speed limit: ' + speedLimit +' '+ RS.L[i].ESU +'</li>';
                //pm_htm += '<li>Express speed: ' + ESP_speed + RS.L[i].ESU +'</li>';
                if(ESP_speed > 0){
                    pm_htm += '<li>Express speed: ' + ESP_speed + RS.L[i].ESU +'</li>';
                    if(speedLimit>0 && (ESP_speed <= CSP_speed)){
                        speedFactor = ESP_speed/speedLimit;    
                    }
                }
                else{
                    pm_htm += '<li>Express speed: N/A</li>';
                }
                if(RS.L[i].EDS !='N/A' && RS.L[i].EDS!=''){pm_htm += '<li>Express Description: ' + RS.L[i].EDS + '</li>';}
                //pm_htm += '<li>Collector Speed: ' + CSP_speed + RS.L[i].CSU +'</li>';
                if(CSP_speed > 0){
                    pm_htm += '<li>Collector Speed: ' + CSP_speed + RS.L[i].CSU +'</li>';
                    if(speedLimit>0 && (CSP_speed <= ESP_speed)){
                        speedFactor = CSP_speed/speedLimit;
                    }
                }
                else{
                    pm_htm += '<li>Collector Speed: N/A</li>';
                }
                if(RS.L[i].CDS!='N/A' && RS.L[i].CDS!=''){pm_htm += '<li>Collector Description: ' + RS.L[i].CDS + '</li>';}
                pm_htm += '<li>Province: ' + RS.L[i].PRV + '</li></ul>';
                pm_htm += '</html>';

                flow = new VEShape( VEShapeType.Polyline, points );
                flow.SetLineWidth( 4 );
                flow.HideIcon();
                //SET THE TRAFFIC FLOW LINE COLOR ACCORDING TO THE SPEED/LIMIT
                //1. If the current speed/speed limit is 0.75 or more – color green
                //2. If the current speed/speed limit is 0.4 to 0.75 color yellow
                //3. If the current speed/speed limit is < 0.4 color red
                //4. If the data not available - color grey
                //GREEN = 7,233,23 YELLOW = 218,220,9 RED = 211,0,0 GREY = 153,153,153
                if(speedFactor>=0.75){
                    flow.SetLineColor(new VEColor(7,233,23,1.0));
                    flow.SetFillColor(new VEColor(7,233,23,0.5));            
                }
                else if(speedFactor<0.75 && speedFactor>0.4){
                    flow.SetLineColor(new VEColor(218,220,9,1.0));
                    flow.SetFillColor(new VEColor(218,220,9,0.5));            
                }
                else if(speedFactor<=0.4 && speedFactor>0){
                    flow.SetLineColor(new VEColor(211,0,0,1.0));
                    flow.SetFillColor(new VEColor(211,0,0,0.5));            
                }
                else{
                    flow.SetLineColor(new VEColor(153,153,153,1.0));
                    flow.SetFillColor(new VEColor(153,153,153,0.5));            
                }
                //flow.SetTitle(title);
                //flow.SetDescription(pm_htm);
                //flow.SetCustomIcon( '<img src="' + Pmx.Map.imgRoot + 'marker_red_alpha_sm.png" />' );
                //flow.SetCustomIcon( '<a href="#" onmouseover="return overlib(\'' + flow_title +'\');" onclick="return overlib(\'' + pm_htm + '\', STICKY, CAPTION, \''+title+'\');return false;" onmouseout="return nd();"><img src="' + Pmx.Map.imgRoot + 'marker_red_alpha_sm.png" /></a>');

                if(zoomLevel > 12){ //show icons only when the zoom level greater then 11
                    flow.SetCustomIcon( '<img src="' + Pmx.Map.imgRoot + 'marker_red_alpha_sm.png" onmouseover="return overlib(\'' + flow_title +   '\');" onclick="return overlib(\'' + pm_htm + '\', STICKY, CAPTION, \''+title+'\');" onmouseout="return nd();" />');
                    flow.ShowIcon();
                }
                else{
                    flow.HideIcon();
                }
                Pmx.Map._trafficFlowLayer.AddShape(flow);
                pm_htm = '';
            }
            Pmx.Map._trafficFlowLayer.Show();
        }
        else
        {
            if( Pmx.debug === true && Pmx.console.warn === true )
            {
                console.warn( 'No traffic flow data found!' );
            }
        }
    }
    catch( e )
    {
        if( Pmx.debug === true && Pmx.console.error === true )
        {
            console.error( 'drawTrafficFlow: ' + e );
        }
    }
    // clean up
    Pmx._jsr.removeScriptTag();
    //Pmx.Map.hideLoading();
    timer.stop();
};

/**
 * Function Name: getJsonUrl
 * @description
 * get the JSON request url for each of the products:cam, obs, evt, flw
 * Implement 29 Apr 2008
 * author: Daniel
 */
Pmx.Map.getJsonUrl = function(productName)
{
    //get the map area
    var Y2 = Pmx.Map._VE.GetMapView().TopLeftLatLong.Latitude;
    var X1 = Pmx.Map._VE.GetMapView().TopLeftLatLong.Longitude;
    var Y1 = Pmx.Map._VE.GetMapView().BottomRightLatLong.Latitude;
    var X2 = Pmx.Map._VE.GetMapView().BottomRightLatLong.Longitude;
    //over fetch more cameras for next & prev
    //0.05 distance =6.885km
    //0.075 distance =10.33km
    //0.1 distance =13.77km
    //alert(X1+':'+Y1+':'+X2+':'+Y2);
    X1 = X1-0.075;
    Y1 = Y1-0.075;
    X2 = X2+0.075;
    Y2 = Y2+0.075;
    //alert(X1+':'+Y1+':'+X2+':'+Y2);
    var url ='';
    var zoomLevel = Pmx.Map._VE.GetZoomLevel();

    switch(lang){
        case 'fr':
            WB_lang = 'WBF';
            FLW_lang = 'FR';
            break;
        case 'en':
        default:
            WB_lang = 'WBE';
            FLW_lang = 'EN';
    }

    //1.camera, 2.incident, 3.flow, 4.weather
    switch(productName)
    {
        case Pmx.Map.CAMERA:
            url = Pmx.Map.camSever+'CAM?K='+WB_lang+'.JSO.BOX.CAN.TRF&BBOX=['+X1+','+Y1+','+X2+','+Y2+']HTTp/1.1&CB='+Pmx.Map.camCallback;
            break;
        case Pmx.Map.INCIDENT:
            url = Pmx.Map.evtSever+'EVT?K='+WB_lang+'.JSO.BOX.CAN.EVT&BBOX=['+X1+','+Y1+','+X2+','+Y2+']HTTp/1.1&CB='+Pmx.Map.evtCallback;
            break;
        case Pmx.Map.WEATHER:
            url = Pmx.Map.obsSever+'OBS?K='+WB_lang+'.JSO.BOX&BBOX=['+X1+','+Y1+','+X2+','+Y2+']HTTp/1.1&CB='+Pmx.Map.obsCallback;
            break;
        case Pmx.Map.FLOW:
            url = Pmx.Map.flwSever+'FLW?'+'X1='+X1+'&Y1='+Y1+'&X2='+X2+'&Y2='+Y2+'&ZL='+zoomLevel+'&AT=5&LA='+FLW_lang+'&CB='+Pmx.Map.flwCallback;
            break;
        default:
            url = '';
    }
    return url;
};
//==============================================================================
/**
 * Function Name: getDirections
 * @description
 * Get driving directions from Virtual Earth.
 * Implement 29 May 2008
 * author: Daniel
 */
Pmx.Map.getDirections = function( startId, endId )
{
    if( startId !== '' && endId !== '' )
    {
        var start = document.getElementById( startId ).value;
        var end = document.getElementById( endId ).value;

        try
        {
            var opts = new VERouteOptions;
            opts.DistanceUnit = VERouteDistanceUnit.Kilometer;
            //opts.DistanceUnit   = VERouteDistanceUnit.Mile;
            opts.DrawRoute = true;

            // So the map doesn't change: false
            //opts.SetBestMapView = false;
            opts.SetBestMapView = true;

            // Call this function when map route is determined:
            opts.RouteCallback  = Pmx.Map.ShowTurns;

            // Show the disambiguation dialog
            opts.ShowDisambiguation = true;

            Pmx.Map._VE.GetDirections( [ start, end ], opts );
        }
        catch( e )
        {
            alert(e);
        }
        //Pmx.Map.hideLoading();
    }
};
/**
 * Function Name: ShowTurns
 * @description
 * displaying the direction discription
 * Implement 29 May 2008
 * author: Daniel
 */
Pmx.Map.ShowTurns = function(route)
{
   var turns = "<h4>Turn-by-Turn Directions</h4>";
   turns += "<p><b>Distance:</b> " + route.Distance.toFixed(1) + " km";
   turns += "<br/><b>Time:</b> " + Pmx.Map.GetTime(route.Time) + "</p>";

   //if (dirsForm.dirsType[0].checked)
   //{
       //Unroll route and populate DIV
      var legs          = route.RouteLegs;
      var leg           = null;
      var turnNum       = 0;  // The turn #
      var legsNum       = legs.length;
       //Get intermediate legs
      for(var i = 0; i < legsNum; i++)
      {
        //alert('legsNum= '+legsNum);
         // Get this leg so we don't have to derefernce multiple times
         leg = legs[i];  // Leg is a VERouteLeg object
         var legLength = leg.Itinerary.Items.length;
         var legNum = i + 1;
         //if(legsNum > 1){
         //    turns += "<br/><b>Distance for leg " + legNum + ":</b> " + leg.Distance.toFixed(1) + " km" +
         //         "<br/><b>Time for leg "     + legNum + ":</b> " + Pmx.Map.GetTime(leg.Time) + "<br/><br/>";
         //}

         // Unroll each intermediate leg
         var turn        = null;  // The itinerary leg
         var legDistance = null;  // The distance for this leg
         
         for(var j=1; j<=legLength; j++)
         {
            //alert(j);
            turnNum++;
            turn = leg.Itinerary.Items[j-1];  // turn is a VERouteItineraryItem object
            turns += "<b>" + j + ".</b> " + turn.Text;
            legDistance = turn.Distance;
            // So we don't show 0.0 for the arrival
            if(legDistance > 0)
            {
               // Round distances to 1/10ths
               turns += " (" + legDistance.toFixed(1) + " km";
               // Append time if found
               if(turn.Time != null)
               {
                  turns += "; " + Pmx.Map.GetTime(turn.Time);
               }
               turns += ")<br/>";
            }
         }
         turns += "<br/>";
      }
       //alert(turns);
       //Populate DIV with directions
      //Pmx.Map.SetDirections(turns);
      document.getElementById('directions_desc').innerHTML = turns;
   //}
}
/**
 * Function Name: GetTime
 * time is an integer representing seconds
 * returns a formatted string
 */
Pmx.Map.GetTime = function(time)
{
   if(time == null){
      return("");
   }
   if(time > 60){
    // if time == 100
      var seconds = time % 60;       // seconds == 40
      var minutes = time - seconds;  // minutes == 60
      minutes     = minutes / 60;    // minutes == 1

      if(minutes > 60){
        // if minutes == 100
         var minLeft = minutes % 60;        // minLeft    == 40
         var hours   = minutes - minLeft;   // hours      == 60
         hours       = hours / 60;          // hours      == 1
         return(hours + " hour(s), " + minLeft + " minute(s), " + seconds + " second(s)");
      }
      else{
         return(minutes + " minutes, " + seconds + " seconds");
      }
   }
   else{
      return(time + " seconds");
   }
};
/**
 * Function Name: showAllLayers
 * testing to show all the layers at once
 * show all the layers on the map
 */
Pmx.Map.showAllLayers = function()
{
   //Pmx.Map._VE.ShowAllShapeLayers();
    Pmx.Map._currentLayer[Pmx.Map.CAMERA] = true;
    Pmx.Map._currentLayer[Pmx.Map.INCIDENT] = true;
    Pmx.Map._currentLayer[Pmx.Map.FLOW] = true;
    Pmx.Map._currentLayer[Pmx.Map.WEATHER] = true;

    Pmx.Map.updateTrafficCamera();
    Pmx.Map.updateTrafficIncident();
    Pmx.Map.updateTrafficFlow();
    Pmx.Map.updateWeather();
};
/**
 * Function Name: showAllLayers
 * testing to delete all the layers
 * remove all the layers on the map
 */
Pmx.Map.ClearAll = function()
{
    //document.getElementById('counter').innerHTML = 0;
    
    Pmx.Map._VE.HideAllShapeLayers();
    Pmx.Map._VE.DeleteAllShapeLayers();
    Pmx.Map._VE.DeleteRoute();
    document.getElementById('directions_desc').innerHTML = '';
    Pmx.Map.RemoveMyControl();

    Pmx.Map._currentLayer[Pmx.Map.CAMERA] = false;
    Pmx.Map._currentLayer[Pmx.Map.INCIDENT] = false;
    Pmx.Map._currentLayer[Pmx.Map.FLOW] = false;
    Pmx.Map._currentLayer[Pmx.Map.WEATHER] = false;
};
/**
 * Function Name: setISO8601
 * convert the ISO8601 time format to a standard format
 * return the standard time format
 */
Pmx.Map.setISO8601 = function (string) {
    var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
        "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
        "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
    var d = string.match(new RegExp(regexp));

    var offset = 0;
    var date = new Date(d[1], 0, 1);

    if (d[3]) { date.setMonth(d[3] - 1); }
    if (d[5]) { date.setDate(d[5]); }
    if (d[7]) { date.setHours(d[7]); }
    if (d[8]) { date.setMinutes(d[8]); }
    if (d[10]) { date.setSeconds(d[10]); }
    if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
    if (d[14]) {
        offset = (Number(d[16]) * 60) + Number(d[17]);
        offset *= ((d[15] == '-') ? 1 : -1);
    }
    offset -= date.getTimezoneOffset();
    time = (Number(date) + (offset * 60 * 1000));
    date.setTime(Number(time));
    return date;
};
/**
 * Function Name: getCheckedValue
 * return the value of the radio button that is checked
 * return an empty string if none are checked, or
 * there are no radio buttons
 */
Pmx.Map.getCheckedValue =function (radioObj) {
    radioObj = document.getElementById('dm_lang');
	if(!radioObj)
		return "ERROR";
	var radioLength = radioObj.length;
	if(radioLength == undefined)
		if(radioObj.checked)
			return radioObj.value;
		else
			return "NO LENGTH";
	for(var i = 0; i < radioLength; i++) {
		if(radioObj[i].checked) {
			return radioObj[i].value;
		}
	}
	return "NO RADIO";
};
/**
 * Function Name: EpochToDate
 * convert the Epoch time format to a standard format
 * return the standard time format
 */
Pmx.Map.EpochToDate = function(eObj){
    var mEpoch = parseInt(eObj);
    if(mEpoch<10000000000){
        mEpoch *= 1000; // convert to milliseconds (Epoch is usually expressed in seconds, but Javascript uses Milliseconds)
    }
    var dDate = new Date();
    dDate.setTime(mEpoch);
    return dDate;
};
/**
 * Function Name: AddMyControl
 * display a text message on the map
 * ask user to zoom in to see the cameras
 */
Pmx.Map.AddMyControl = function (msg)
{
   if (Pmx.Map.control == null)
   {
      Pmx.Map.control = document.createElement("div"); 
      Pmx.Map.control.id = "myControl";
      Pmx.Map.control.style.top ="3px"; 
      Pmx.Map.control.style.left = "400px"; 
      //Pmx.Map.control.style.border = "1px solid black";
      //Pmx.Map.control.style.background = "Yellow";
      Pmx.Map.control.innerHTML = msg;

      Pmx.Map._VE.AddControl(Pmx.Map.control);
      Pmx.Map.addShim(Pmx.Map.control);
   }
};
/**
 * Function Name: addShim
 * display the div tag on the fly
 */
Pmx.Map.addShim = function (el)
{
   var shim = document.createElement("iframe");
   shim.id = "myShim";
   shim.frameBorder = "0";
   shim.style.position = "absolute";
   shim.style.zIndex = "1";
   shim.style.top  = el.offsetTop;
   shim.style.left = el.offsetLeft;
   shim.width  = el.offsetWidth;
   shim.height = el.offsetHeight;
   el.shimElement = shim;
   el.parentNode.insertBefore(shim, el);
};
/**
 * Function Name: RemoveMyControl
 * remove the div tag
 */
Pmx.Map.RemoveMyControl = function ()
{
   if (Pmx.Map.control != null)
   {
      Pmx.Map._VE.DeleteControl(Pmx.Map.control);
      Pmx.Map.control = null;
   }
};
/**
 * Function Name: checkOverlap
 * check the distance of two cameras to see if to group
 * these two cameras as a super icon
 * return true to make the super icon, false not
 */
Pmx.Map.checkOverlap = function(latX1, longY1, latX2, longY2){
    var latLongPoint1 = new VELatLong(longY1,latX1);
    var latLongPoint2 = new VELatLong(longY2,latX2);
    var pixelPoint1 = Pmx.Map._VE.LatLongToPixel(latLongPoint1, Pmx.Map._VE.GetZoomLevel());
    var pixelPoint2 = Pmx.Map._VE.LatLongToPixel(latLongPoint2, Pmx.Map._VE.GetZoomLevel());
    //alert(pixelPoint1.x-pixelPoint2.x);
    //alert(pixelPoint1.y-pixelPoint2.y);
    var controlDistance = 200/Pmx.Map._VE.GetZoomLevel();
    if(Math.abs(pixelPoint1.x-pixelPoint2.x)<controlDistance && Math.abs(pixelPoint1.y-pixelPoint2.y)<controlDistance){
        return true;
    }
    else return false;
};
/**
 * Function Name: hidePopup
 * @description
 * Hide the map popup window.
 * and move the map back if it's moved
 */
Pmx.Map.hidePopup = function(X,Y)
{
    var popupDivElem = document.getElementById( Pmx.Map.elemId.map_popup );
    popupDivElem.style.display = "none";
/*
    X = (typeof(X) != 'undefined' ? X : 0);
    Y = (typeof(Y) != 'undefined' ? Y : 0);
    if(X!=0 || Y!=0){
        Pmx.Map._VE.Pan(-X,-Y);
    }
    Pmx.Map.updated = false;
    //Pmx.Map.handleEndPan();
    Pmx.Map.updateMap();

    //Pmx.Map.updated = true;
*/
};

Pmx.Map.inArray = function (value,caseSensitive)
// Returns true if the passed value is found in the
// array. Returns false if it is not.
{
    var i;
    var l = RS.M.length;
    for (i=0; i < l; i++) {
        // use === to check for Matches. ie., identical (===),
        if(caseSensitive){ //performs match even the string is case sensitive
            if ((RS.M[i].I).toLowerCase() === value.toLowerCase()) {
                return true;
            }
        }else{
            if (RS.M[i].I === value) {
                return true;
            }
        }
    }
    return false;
};
/**
 * Function Name: showhideCameraLayer
 * to hide or show a layer
 */
Pmx.Map.showhideCameraLayer = function(cam_checkbox) {
	if(document.getElementById('traffic_camera').checked == true){
	 Pmx.Map._trafficCameraLayer.Show();
	}
	else{
	 Pmx.Map._trafficCameraLayer.Hide();
	}
};

/**
 * @description
 */
Pmx.Map.addEvent = function( oElement, strEvent, fncHandler )
{
    var fncEvent = function( e )
    {
        return fncHandler( e || window.event );
    }
 
    if( oElement.addEventListener )
    {
        oElement.addEventListener( strEvent, fncEvent, false );
    }
    else if( oElement.attachEvent )
    {
        oElement.attachEvent( "on" + strEvent, fncEvent );
    }
}
// 
//window.onload = function()
//{
//    alert(lang);
//   // Pmx.Map.init();
//}

//Pmx.Map.latitude = 46.50856929780;
//Pmx.Map.longitude = -84.18947237220;
//Pmx.Map.addEvent( window, "load", Pmx.Map.init );


Pmx.Map.getVideoHTML = function (videoLink) {
 var url = videoLink;
 //var html = '<div id="videoTitle">'+titles[idx]+'</div>';
 var html = '';
 //html += '<div id="videoFeed">'+"\n";
 html += '<object>'+"\n";
 html += ' <param name="AudioStream" value="-1">'+"\n";
 html += ' <param name="AutoSize" value="-1">'+"\n";
 html += ' <param name="AutoStart" value="-1">'+"\n";
 html += ' <param name="AnimationAtStart" value="-1">'+"\n";
 html += ' <param name="AllowScan" value="-1">'+"\n";
 html += ' <param name="AllowChangeDisplaySize" value="-1">'+"\n";
 html += ' <param name="AutoRewind" value="0">'+"\n";
 html += ' <param name="Balance" value="0">'+"\n";
 html += ' <param name="BaseURL" value>'+"\n";
 html += ' <param name="BufferingTime" value="1">'+"\n";
 html += ' <param name="CaptioningID" value>'+"\n";
 html += ' <param name="ClickToPlay" value="-1">'+"\n";
 html += ' <param name="CursorType" value="0">'+"\n";
 html += ' <param name="CurrentPosition" value="-1">'+"\n";
 html += ' <param name="CurrentMarker" value="0">'+"\n";
 html += ' <param name="DefaultFrame" value>'+"\n";
 html += ' <param name="DisplayBackColor" value="0">'+"\n";
 html += ' <param name="DisplayForeColor" value="16777215">'+"\n";
 html += ' <param name="DisplayMode" value="0">'+"\n";
 html += ' <param name="DisplaySize" value="0">'+"\n";
 html += ' <param name="Enabled" value="-1">'+"\n";
 html += ' <param name="EnableContextMenu" value="-1">'+"\n";
 html += ' <param name="EnablePositionControls" value="-1">'+"\n";
 html += ' <param name="EnableFullScreenControls" value="0">'+"\n";
 html += ' <param name="EnableTracker" value="-1">'+"\n";
 html += ' <param name="Filename" value="'+url+'">'+"\n";
 html += ' <param name="InvokeURLs" value="-1">'+"\n";
 html += ' <param name="Language" value="-1">'+"\n";
 html += ' <param name="Mute" value="0">'+"\n";
 html += ' <param name="PlayCount" value="1">'+"\n";
 html += ' <param name="PreviewMode" value="0">'+"\n";
 html += ' <param name="Rate" value="1">'+"\n";
 html += ' <param name="SAMILang" value>'+"\n";
 html += ' <param name="SAMIStyle" value>'+"\n";
 html += ' <param name="SAMIFileName" value>'+"\n";
 html += ' <param name="SelectionStart" value="-1">'+"\n";
 html += ' <param name="SelectionEnd" value="-1">'+"\n";
 html += ' <param name="SendOpenStateChangeEvents" value="-1">'+"\n";
 html += ' <param name="SendWarningEvents" value="-1">'+"\n";
 html += ' <param name="SendErrorEvents" value="-1">'+"\n";
 html += ' <param name="SendKeyboardEvents" value="0">'+"\n";
 html += ' <param name="SendMouseClickEvents" value="0">'+"\n";
 html += ' <param name="SendMouseMoveEvents" value="0">'+"\n";
 html += ' <param name="SendPlayStateChangeEvents" value="-1">'+"\n";
 html += ' <param name="ShowCaptioning" value="0">'+"\n";
 html += ' <param name="ShowControls" value="1">'+"\n";
 html += ' <param name="ShowAudioControls" value="0">'+"\n";
 html += ' <param name="ShowDisplay" value="0">'+"\n";
 html += ' <param name="ShowGotoBar" value="0">'+"\n";
 html += ' <param name="ShowPositionControls" value="1">'+"\n";
 html += ' <param name="ShowStatusBar" value="0">'+"\n";
 html += ' <param name="ShowTracker" value="1">'+"\n";
 html += ' <param name="TransparentAtStart" value="0">'+"\n";
 html += ' <param name="VideoBorderWidth" value="0">'+"\n";
 html += ' <param name="VideoBorderColor" value="0">'+"\n";
 html += ' <param name="VideoBorder3D" value="0">'+"\n";
 html += ' <param name="Volume" value="-230">'+"\n";
 html += ' <param name="WindowlessVideo" value="0">'+"\n";
 /*html += ' <param name="VideoAcceleration" value="-1">'+"\n";
 html += ' <param name="DirectXVideoAcceleration" value="1">'+"\n";
 html += ' <param name="VideoSmoothing" value="1">'+"\n";*/
 html += ' <param name="HighQualityMode" value="1">'+"\n";
 html += ' <embed type="application/x-mplayer2" src="'+url+'" name="MediaPlayer" width="240" height="190" pluginspage="http://www.microsoft.com/isapi/redir.dll?prd=windows&amp;sbp=mediaplayer&amp;ar=media&amp;sba=plugin&amp;" autosize="0" autostart="1" showcontrols="0" showdisplay="0" showstatusbar="1">'+"\n";
 html += ' </embed>'+"\n";
 html += '</object>'+"\n";
 //html += '</div>'+"\n";
 
 return html;
 
}

//==========================IMPLEMENTATION BY DANIEL=========================END//