/*-------------------------------------------------------------------------------------
       Name: mac_journey_map.js
Description: javascript for NSBPortal map and journey info
         NB: most of this originally appeared in NDF 
         By: MAJW - mayjay@blueyonder.co.uk
  Copyright: (c)2007 - Nomad Digital Ltd All Rights Reserved
             www.nomadrail.co.uk.com
-------------------------------------------------------------------------------------*/


//  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// for the moment, we'll keep the required sizes of the popup panel here
var k_station_info_panel_dims = { width: 400, height: 370 };
    
// ------------------------------------------------------------------------------------
NSB.checkMapAvailability = function()
    {   /* called when we have no map availability - trigger a redraw
            if availability changes */
    doAjaxAdapterCallJS( 'journey', 'hasMapCapabilityChanged', 
                        {}, '',
                        function( iresponse ) {
                            if( iresponse.responseJSON )
                                window.location =  '/view_your_journey';
                            } );
    };

// ------------------------------------------------------------------------------------
NSB.journey_map = null;
NSB.updateJourneyMap = function()
    {
    if( !NSB.journey_map )
        NSB.journey_map = new NSB.JourneyMap( 'journey_map', 'journey_map_box' );
    else
        NSB.journey_map.updateJourneyMap();
    return NSB.journey_map;
    };

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
NSB.JourneyMap = Class.create( NSB.GMapBasic,
    {
    initialize: function( $super, ijelem_id, imap_elem_id )
        {
        $super( ijelem_id, imap_elem_id );
        
        this.map_box = $( imap_elem_id );
        
                                    // be nice to the white-out by supplying
                                    //     a valid nw coord
        var nw = this.gmap.fromDivPixelToLatLng( new GPoint( 0, 0 ) );        
        this.white_out = new NSB.JourneyMapWhiteOut( nw );
        this.gmap.addOverlay( this.white_out );
        
        this.map_anti = new NSB.JourneyMapAnti( new GPoint( 0, 0 ) );
        this.gmap.addOverlay( this.map_anti );
        
                                    // add stations
        this.station_lines = null;
        this.station_overlays = null;
        
        this.vehicle_overlay = null;
        this.vehicle_gps_on_line = null;

        this.calcBestLayout.bind( this ).delay( 0.5 );
        
        if( this.update_secs )
            new PeriodicalExecuter( this.updateStations.bind( this ), this.update_secs );

        GEvent.addDomListener( this.map_box, 'mouseover', this.doStationsMouseOver.bind( this ) ); 
                                    // the map sits under this top strip too which 
                                    //    catches mouse overs 
        GEvent.addDomListener( $( 'top_strip' ), 'mouseover', this.doStationsMouseOver.bind( this ) ); 
        
        // testing
        // GEvent.addDomListener( this.map_box, 'click', this.onMouseClick.bind( this ) ); 
        },
    
    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // onMouseClick: function( event )
    //     {   /* for testing */ 
    //     this.calcBestPosOnUpdate();
    //     },
        
    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    doStationsMouseOver: function( event )
        {    /* because of overlap / transparency issues, its best for us to handle 
                  cursor rollover of stations "by hand". This method is called
                  from several places both JS and html */
        Event.stop( event );
        if( this.vehicle_overlay )
            this.vehicle_overlay.hidePopout();

        if( !this.station_boxes )
            return;
                                // offset based on position of map div in browser window
        var pos_ofst = this.map_box.cumulativeOffset();
                                // offset based on any movement of map after initialization
        var moved_ofst = this.getMovedOffsets();
                                // cursor pos relative to station boxes
        var curs_x = Event.pointerX( event ) - pos_ofst.left + moved_ofst.x;
        var curs_y = Event.pointerY( event ) - pos_ofst.top + moved_ofst.y;

        var stat = this.station_boxes.find( 
                    function( b )
                        {       // aka pointInRect( ( x, y ), b )
                        return( ( curs_x > b.left ) && ( curs_x < b.right ) && 
                                ( curs_y > b.top ) && ( curs_y < b.bot ) );
                        } );

        // console.log( "stat " + stat );
        
        popout = $( 'journey_map_station_popout' );
        if( !stat )
            popout.setStyle( { visibility: 'hidden' } );
        
        else
            {
            var st_overlay = this.station_overlays.get( stat.station_id );
                        // IE not work with id="popout_contents" so we're
                        //   fixing it using class instead
            // var pop_div = st_overlay.div_.selectPart( "#popout_contents" );
            var pop_div = st_overlay.div_.selectPart( ".popout_contents" );
            popout.selectPart( '.contentz' ).update( pop_div.innerHTML );
            
            var left = stat.left + pos_ofst.left - moved_ofst.x + 1;
            var top = stat.top + pos_ofst.top - moved_ofst.y + 1;

            popout.setStyle( { left: left + "px", top: top + "px", visibility: 'visible' } );
            }
        },

    // ----------------------------------------------------------------------------------
    updateJourneyMap: function()
        {
        // not doing much at the moment...
        this.updateStations();
        },

    // ----------------------------------------------------------------------------------
    // layout stuff
    // ----------------------------------------------------------------------------------
    calcBestLayout: function()
        {   /* work out whether the journey is "north<->south" or "east<->west" */
        doAjaxAdapterCallJS( 'journey', 'getJourneyStationsLatLongExtent', 
                                            {}, '',
                                            this.calcBestLayout2.bind( this ) );
        },
        
    calcBestLayout2: function( iresponse )
        {   
        vals = iresponse.responseJSON;
                        // assuming we have either the full width or the full
                        //    height available to display the journey, then 
                        //    getBoundsZoomLevel() should be fine
        var gps_extent = new GLatLngBounds( 
                                    new GLatLng( vals.min_lat, vals.min_long ), 
                                    new GLatLng( vals.max_lat, vals.max_long ) );
        var jgps_cen = gps_extent.getCenter();  // center of journey, gps
        var map_zoom = this.gmap.getBoundsZoomLevel( gps_extent );
        
                        // our calcs below must be done with same zoom
        if( this.gmap.getZoom() != map_zoom )
            this.gmap.setZoom( map_zoom );

                        // min_lat => S, max_lat => N, min_long => W, max_long => E 
        var jpix_lt = this.gmap.fromLatLngToDivPixel( 
                                    new GLatLng( vals.max_lat, vals.min_long ) );
        var jpix_rb = this.gmap.fromLatLngToDivPixel( 
                                    new GLatLng( vals.min_lat, vals.max_long ) );
        
        var jpix_wid = jpix_rb.x - jpix_lt.x;
        var jpix_hgt = jpix_rb.y - jpix_lt.y;
        
        var map_dims = this.map_box.getDimensions();
        var map_ne = this.gmap.fromDivPixelToLatLng( new GPoint( 0, 0 ) );
        
        if( jpix_hgt > jpix_wid )
            {           // N <-> S - vertical at rhs
            var gps_ex = this.gmap.fromDivPixelToLatLng( 
                                    new GPoint( map_dims.width * 0.25, 0 ) );
            var long_diff = gps_ex.lng() - map_ne.lng();
            var mgps_cen = new GLatLng( jgps_cen.lat(), jgps_cen.lng() - long_diff );
            
            var summary_loc = { left: '40px', top: '280px' };
            var active_bnds = { left: '455px', top: '27px', width: '375px', height: '470px' };
            }
        else
            {           // E <-> W - horizontal at bottom
            var gps_ex = this.gmap.fromDivPixelToLatLng( 
                                    new GPoint( 0, map_dims.height * 0.25 ) );
            var lat_diff = map_ne.lat() - gps_ex.lat();
            var mgps_cen = new GLatLng( jgps_cen.lat() + lat_diff, jgps_cen.lng() );

            var summary_loc = { left: '400px', top: '52px' };
            var active_bnds = { left: '0', top: '250px', width: '830px', height: '248px' };
            }
        
        $( 'summary_box' ).setStyle( summary_loc );
        $( 'active_area' ).setStyle( active_bnds );
        
        new Effect.Opacity( 'summary_box', { from:0.0, to:1.0, duration:1.0 } );

        this.gmap.setCenter( mgps_cen, map_zoom );
        // this.onMapViewChange();      // do this if we want to save the position etc        
        this.updateStations();
        this.calcBestPosOnUpdate();
        
        },

    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    calcBestPosOnUpdate: function()
        {
        var vhc_pix = this.gmap.fromLatLngToContainerPixel( this.vehicle_gps_on_line );

                    // vehicle is 100 x 75 px
        var margin = 10;
        var vhc_box_left = vhc_pix.x - 50 - margin;
        var vhc_box_right = vhc_pix.x + 50 + margin;
        var vhc_box_top = vhc_pix.y - 37 + 20;   // no margin needed at top
        var vhc_box_bot = vhc_pix.y + 38 + margin;

                    // div set by calcBestPosLayout2() which determines where its
                    //    ok to show the vehicle
        var active_area = $( 'active_area' );
        var active_loc = active_area.positionedOffset();
        var active_size = active_area.getDimensions();
        
        var adjust_x = 0;
        if( vhc_box_left < active_loc.left )
            adjust_x = active_loc.left - vhc_box_left;
        else if( vhc_box_right > ( active_loc.left + active_size.width ) )
            adjust_x = active_loc.left + active_size.width - vhc_box_right;
            
        var adjust_y = 0;
        if( vhc_box_top < active_loc.top )
            adjust_y = active_loc.top - vhc_box_top;
        else if( vhc_box_bot > ( active_loc.top + active_size.height ) )
            adjust_y = active_loc.top + active_size.height - vhc_box_bot;

        if( adjust_x || adjust_y )
            {
            var orig_cen = this.gmap.getCenter();
            var orig_cen_pix = this.gmap.fromLatLngToDivPixel( orig_cen );
            var new_cen_pix = new GPoint( orig_cen_pix.x - adjust_x, orig_cen_pix.y - adjust_y );
            var new_cen = this.gmap.fromDivPixelToLatLng( new_cen_pix );
            this.gmap.setCenter( new_cen, this.gmap.getZoom() );
            
            if( this.station_overlays )
                this.updateStationBoxes();  
            }
        },

    // ----------------------------------------------------------------------------------
    // station click handling
    // ----------------------------------------------------------------------------------

    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    onStationPopoutClick: function( event )
        {
        var elem = $( getEventElem( event ).parentNode );
        var station_id = elem.readAttribute( 'station_id' );
        var st_overlay = this.station_overlays.get( station_id );
        this.onStationClick( st_overlay ); 
        },
        
    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    onStationClick: function( istation )
        {   /* istation is an NSB.JourneyMapStation */
        this.station_link_id = istation.info_link_id;   // save here rather than using bind

        $( 'popup_overlay' ).setStyle( { display: 'none' } );
                        
        var stloc = istation.div_.cumulativeOffset();
        var bgn_bnds = { left: stloc.left, top: stloc.top, wid: 16, hgt: 16 };
        end_bnds = NSB.calcCenterBounds( k_station_info_panel_dims );

        new NSB.ZoomRect( $( 'popup_overlay_effect_img' ),
                {
                bgn_bnds: bgn_bnds, 
                end_bnds: end_bnds,
                afterFinish: this.onPopupOpened.bind( this, bgn_bnds, end_bnds ) 
                } );
        },

    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    onPopupOpened: function( ibgn_bnds, iend_bnds, ieffect )
        {
        doAjaxAdapterCallJS( 'journey', 'getJourneyMapStationInfoRendered', 
                                            { 
                                            ilink_id: this.station_link_id 
                                            }, '',
                                            this.onPopupRendered.bind( this, ibgn_bnds, iend_bnds ) );
        },

    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     onPopupRendered: function( ibgn_bnds, iend_bnds, iresponse )
        {
        NSB.popup_overlay.setContents( iresponse.responseJSON.html );
        NSB.popup_overlay.setBounds( iend_bnds );
        NSB.popup_overlay.setCloseZoomBounds( ibgn_bnds );
        $( 'popup_overlay_effect_img' ).setStyle( { display: 'none' } );
        },

    // ----------------------------------------------------------------------------------
    // vehicle drawing
    // ----------------------------------------------------------------------------------
    updateVehicle: function()
        {
        doAjaxAdapterCallJS( 'journey', 'getJourneyVehicleRendered', {}, '',
                                            this.onUpdateVehicle.bind( this ) );
        },
    
    onUpdateVehicle: function( iresponse )
        {
        if( this.vehicle_overlay )
            this.vehicle_overlay.removeFromMap();
        
        var vals = iresponse.responseJSON;
        if( !this.vehicle_gps_on_line )     // precaution
            this.vehicle_gps_on_line = new GLatLng( vals.gps_lat, vals.gps_long );

        this.vehicle_overlay = new NSB.JourneyMapVehicle( this.vehicle_gps_on_line, vals.html );
        this.gmap.addOverlay( this.vehicle_overlay );
        },
        
    // ----------------------------------------------------------------------------------
    // station drawing
    // ----------------------------------------------------------------------------------
    updateStations: function()
        {
        doAjaxAdapterCallJS( 'journey', 'getJourneyStationsRendered', {}, '',
                                            this.onUpdateStations.bind( this ) );
        },
        
    onUpdateStations: function( iresponse )
        {
        if( iresponse.responseJSON == -1 )
            {           // the journey has changed
            window.location =  '/view_your_journey';
            return;
            }
            
        if( this.station_lines )     // remove old ones
            this.station_lines.each( function( l ) { this.gmap.removeOverlay( l ); }.bind( this ) );            
        if( this.station_overlays )
            this.station_overlays.values().each( function( s ) { 
                s.removeFromMap(); } );
        
        this.station_lines = $A();
        this.station_overlays = $H();
        this.prev_sl_vals = null;

        $A( iresponse.responseJSON ).each( this.addStationLine.bind( this ) );
        $A( iresponse.responseJSON ).each( this.addStationOverlay.bind( this ) );
        
        this.updateStationBoxes();
        
        this.updateVehicle();               // do after we've drawn the lines
        this.calcBestPosOnUpdate();
        },
        
    addStationOverlay: function( ivals )
        {
        var loc = new GLatLng( ivals.gps_lat, ivals.gps_long );
        var stat = new NSB.JourneyMapStation( loc, ivals.html );
        this.gmap.addOverlay( stat );
        this.station_overlays.set( stat.station_id, stat );
        },
        
    addStationLine: function( ivals )
        {
        if( this.prev_sl_vals )
            {
            if( this.prev_sl_vals.visited && !ivals.visited )
                this.vehicle_gps_on_line = this.addStationVehicleLines( ivals );
            else
                {
                var bgn_gps = new GLatLng( this.prev_sl_vals.gps_lat, this.prev_sl_vals.gps_long );
                var end_gps = new GLatLng( ivals.gps_lat, ivals.gps_long );
                var color = this.prev_sl_vals.visited ? '#E2001A' : '#666666';
                                    // if station in user_journey make lines brighter
                var opacity = this.prev_sl_vals.line_not_user_journey ? 0.2 : 0.8; 
                var line = new GPolyline( [ bgn_gps, end_gps ], color, 3, opacity ); 
                this.gmap.addOverlay( line );
                this.station_lines.push( line );
                }
            }
        this.prev_sl_vals = ivals;
        },
        
    addStationVehicleLines: function( ivals )
        {   /* this adds 2 lines - from the previous visited station to 
                the vehicle, and from the vehicle to the next un-visited
                station. It also returns the gps for the point at which
                the vehicle should be positioned.
                NB  we're doing this in pixels and then converting to gps
                    for the line drawing - I'm sure its saner that way */
        var bgn_gps = new GLatLng( this.prev_sl_vals.gps_lat, this.prev_sl_vals.gps_long );
        var bgn_pix = this.gmap.fromLatLngToDivPixel( bgn_gps );
        var end_gps = new GLatLng( ivals.gps_lat, ivals.gps_long );
        var end_pix = this.gmap.fromLatLngToDivPixel( end_gps );

        if( !this.vehicle_overlay )
            var vhc_gps = new GLatLng( this.vehicle_lat, this.vehicle_long );
        else
            var vhc_gps = new GLatLng( this.vehicle_overlay.gps_lat, this.vehicle_overlay.gps_long );

        var vhc_pix = this.gmap.fromLatLngToDivPixel( vhc_gps );
        
        var a_x = bgn_pix.x; var a_y = bgn_pix.y;
        var b_x = end_pix.x; var b_y = end_pix.y;
        var c_x = vhc_pix.x; var c_y = vhc_pix.y;
        
        var on_line_xy = [];    // result  

        if( a_x == b_x )
            {                   // slope is infinite
            on_line_xy[ 0 ] = a_x;  
            on_line_xy[ 1 ] = c_y;  
            }
        else if( a_y == b_y )
            {                   // slope is zero and slope _|r is infinite
            on_line_xy[ 0 ] = c_x;
            on_line_xy[ 1 ] = a_y;
            }    
        else
            {    
            var m1 = ( b_y - a_y) / ( b_x - a_x );  // slope between a and b
            var m2 = - ( 1 / ( m1 ) );              // slope of line _|r to a and b   
            var const1 = b_y - ( m1 * b_x );        // eqn of st.line y=mx+C.. tf => C = y - mx
            var const2 = c_y - ( m2 * c_x );        // eqn of st.line _|r to a and b
            var lhs = c_y - ( m1 * c_x );           // c is not already on the line between a and b ?? 
       
            if( lhs == const2 ) // if point lies (y-mx) = C
                on_line_xy = [ c_x, c_y ];              // c is the point!!   
            else 
                {               // NB simultaneous eqn solver, using 2x2 matrix 
                                //    A ^ -1 * b gives the result. 
                var mat_row1 = [];                  // matrix A
                var mat = [];
                var mat_row2 = [];
                mat_row1 = [ -m1, 1 ];              // 1y -Mx = c
                mat_row2 = [ -m2, 1 ];
       
                mat[ 0 ] = mat_row1;
                mat[ 1 ] = mat_row2; 

                var mat_inv = [];                   // inverse of matrix A ^ -1 
                var mat_inv_row1 = [];
                var mat_inv_row2 = []; 
                                                    // determinant
                var det = 1 / ( ( mat[ 0 ][ 0 ] * mat[ 1 ][ 1 ] ) - ( mat[ 0 ][ 1 ] * mat[ 1 ][ 0 ] ) ); 
       
                                // do the position and sign changes times determinant
                mat_inv_row1[0] = (det * mat_row2[1]);
                mat_inv_row1[1] = (-(mat_row1[1]) * det);

                mat_inv_row2[0] = (-(mat_row2[0]) * det);
                mat_inv_row2[1] = (det * mat_row1[0]);

                mat_inv[0] = mat_inv_row1;
                mat_inv[1] = mat_inv_row2; 

                var b = [];                         // matrix b with constants
                b[0] = const1; 
                b[1] = const2; 

                var result = [];                    // resultant matrix
                result_row1 = ( mat_inv[ 0 ][ 0 ] * b[ 0 ] ) + ( mat_inv[ 0 ][ 1 ] * b[ 1 ] );
                result_row2 = ( mat_inv[ 1 ][ 0 ] * b[ 0 ]) + ( mat_inv[ 1 ][ 1 ] * b[ 1 ] );   

                result[ 0 ] = Math.ceil( result_row1 ); // x  
                result[ 1 ] = Math.ceil( result_row2 ); // y
  
                on_line_xy = result; 
                }
            }

        // draw the lines
        var on_line_gps = this.gmap.fromDivPixelToLatLng( 
                                            new GPoint( on_line_xy[ 0 ], on_line_xy[ 1 ] ) );        
        // already visited 
        var color = this.prev_sl_vals.visited ? '#E2001A' : '#666666';
        var line = new GPolyline( [ bgn_gps, on_line_gps ], color, 3, 0.8 ); 
        this.gmap.addOverlay( line );
        this.station_lines.push( line );

        // not visited
        var color = '#666666';
        var line = new GPolyline( [ on_line_gps, end_gps ], color, 3, 0.8 );  
        this.gmap.addOverlay( line );
        this.station_lines.push( line );   

        return on_line_gps;
        },

    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    updateStationBoxes: function()
        {   /* record the location of all the stations in this.station_boxes
                for use by our "by-hand" mouse over handling */
        this.station_boxes = $A();
        this.station_overlays.values().each( function( istat ) 
                { 
                var stat_gps = new GLatLng( istat.gps_lat, istat.gps_long );
                var stat_pix = this.gmap.fromLatLngToDivPixel( stat_gps );
                var stat_dim = 10;      // half dimension of station        
                var stat_info = {
                                station_id: istat.station_id,
                                station_name: istat.station_name,
                                left: stat_pix.x - stat_dim,
                                right: stat_pix.x + stat_dim,
                                top: stat_pix.y - stat_dim,
                                bot: stat_pix.y + stat_dim
                                };
                this.station_boxes.push( stat_info );
                }.bind( this ) );
                
        },

    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    onMapMoveEnd: function( $super )
        {
        $super();
        this.white_out.redraw( true );
        // this.updateStations();
        // this.updateVehicle();
        }
    } );
    
// ------------------------------------------------------------------------------------
NSB.JourneyMapVehicle = Class.create( NSB.DivOverlay,
    {   /* shows the vehicle on the map */
    initialize: function( $super, inw_loc, ihtml )
        {
        if( $super( inw_loc ) )
            return true;
        this.clickable = true;
        this.div_.update( ihtml );
        readInitVals( this.div_.firstDescendant(), this );

        this.popout = $( 'journey_map_vehicle_popout' );
        },
        
    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    showPopout: function( ievent )
        {   /* here we have to position the popout element which is absolutely
                  positioned wrt to the window exactly over the hot-spot which
                  is in the map overlay layer
               NB this meth is called directly from onmouseover in html */
        var elem = getEventElem( ievent );
        
        if( NSB.journey_map )
            NSB.journey_map.doStationsMouseOver( ievent );

        if( elem.ancestors().include( this.popout ) )
            {
            // pass
            }
            
        else if( elem.hasClassName( 'journeyMapVehicleIcon' ) || 
                                            elem.hasClassName( 'journeyMapVehicleLabel' ) )
            {
            var pop_id = elem.readAttribute( 'id' );
            var pop_div = this.div_.selectPart( "#pop_" + pop_id );

                                // IE not work with id="popout_contents" so we're
                                //   fixing it using class instead
            // this.popout.selectPart( '#contents' ).update( pop_div.innerHTML );
            this.popout.selectPart( '.contents' ).update( pop_div.innerHTML );
                        
            var pos_ofst = $( 'journey_map_box' ).cumulativeOffset();
                               // blech - can't get our NSB.GMap... instance
            var moved_ofst = NSB.journey_map.getMovedOffsets();

            var veh_loc = this.div_.positionedOffset();
            var pop_loc = elem.positionedOffset();

                    /* setting our position and width to auto here ensures getWidth() 
                         returns desired value. Otherwise it accounts for the right edge 
                         of the window which is exactly what we don't want. */
            this.popout.setStyle( { left: "0px", top: "-100px", width: 'auto' } );
            extra_wid = 5;      // FF seems to need at least 1px extra to avoid wrapping
            var pop_wid = this.popout.getWidth() + extra_wid;
            
            var top = pop_loc.top + veh_loc.top + pos_ofst.top - moved_ofst.y;
            var left = pop_loc.left + veh_loc.left + pos_ofst.left - moved_ofst.x + 2;  // +2 is nessary hack
            
                    // for left popouts, we line up on the rhs of the hot spot
            if( $w( 'altitude velocity connection' ).include( pop_id ) )
                left += 21 + extra_wid - pop_wid;   

            this.popout.setStyle( { left: left + "px", top: top + "px", 
                                            width: pop_wid + "px", visibility: 'visible' } );
            }
        else
            {
            this.hidePopout();
            }    
        },
        
    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    hidePopout: function( ievent )
        {
        this.popout.setStyle( { visibility: 'hidden' } );
        
        },
    
    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    redraw: function( force )
        {
        if (!force) 
            return;
        var nw_pix = this.gmap.fromLatLngToDivPixel( this.nw_loc_ );        
        var hofst = 50;        // FIXME - hard-coded but it won't change (again :-))
        var vofst = 37;
        this.div_.style.left = nw_pix.x - hofst + "px";
        this.div_.style.top = nw_pix.y - vofst + "px";
        }
    } );


// ------------------------------------------------------------------------------------
NSB.JourneyMapStation = Class.create( NSB.DivOverlay,
    {   /* shows a station on the map */
    initialize: function( $super, inw_loc, ihtml )
        {
        if( $super( inw_loc ) )
            return true;
        this.clickable = true;
        this.div_.update( ihtml );
        readInitVals( this.div_.firstDescendant(), this );
        
        // this.ev_click = GEvent.addDomListener( this.div_, 'click', this.onStationClick.bind( this ) );
        },
        
    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    onStationClick: function( ievent )
        {
        // alert( this.info_link_id );
        NSB.journey_map.onStationClick( this );
        },
        
    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    removeFromMap: function( $super ) 
        {   /* was called remove() in NDF */
        if( this.ev_click )
            GEvent.removeListener( this.ev_click );
        $super();
        },

    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    redraw: function( force )
        {
        if (!force) 
            return;
        var nw_pix = this.gmap.fromLatLngToDivPixel( this.nw_loc_ );        
        var bofst = 6;      // this is half the size of the marker blob
        this.div_.style.left = nw_pix.x - bofst + "px";
        this.div_.style.top = nw_pix.y - bofst + "px";
        
        this.div_.style.width = "100px";
        this.div_.style.height = "14px";
        }
    } );
    
// ------------------------------------------------------------------------------------
NSB.JourneyMapWhiteOut = Class.create( NSB.DivOverlay,
    {   /* to make the map look less intense */
    initialize: function( $super, inw_loc )
        {
        if( $super( inw_loc, null, 'journeyMapWhiteOut', 0.60 ) )
            return true;
        },
        
    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    redraw: function( force )
        {
        if (!force) 
            return;
        var extra_pix = 1000;       // make us this much bigger at every edge
        
        var map_dims = this.gmap.getContainer().getDimensions();
        
        var lt = this.gmap.fromLatLngToDivPixel( this.gmap.fromContainerPixelToLatLng( 
                                            new GPoint( 0, 0 ) ) );
        var rb = this.gmap.fromLatLngToDivPixel( this.gmap.fromContainerPixelToLatLng( 
                                            new GPoint( map_dims.width, map_dims.height ) ) );
                                            
        this.div_.style.left = ( lt.x - extra_pix ) + "px";
        this.div_.style.top = ( lt.y - extra_pix ) + "px";
        
        this.div_.style.width = 2 * extra_pix + ( rb.x - lt.x ) + "px";
        this.div_.style.height = 2 * extra_pix + ( rb.y - lt.y ) + "px";
        }
               
    } );
    

// ------------------------------------------------------------------------------------
NSB.JourneyMapAnti = Class.create( NSB.DivOverlay,
    {   /* do the "coastline" */
    initialize: function( $super, inw_loc )
        {
        if( $super( inw_loc, null, 'journeyMapAnt', 0 ) )
            return true;
        
        this.div_.setStyle( { 
                background: "url(images/body3_anti.png)",
                'float': "left",
                width: "834px",
                height: "600px",
                backgroundPosition: "0px 0px" } );
        },
        
    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    addToMap: function( imap )
        {   
        this.gmap = imap;
        this.gmap.getPane( G_MAP_OVERLAY_LAYER_PANE + 1 ).appendChild( this.div_ );
        },
        
    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    redraw: function( force )
        {
        // if (!force) 
        //     return;

        this.div_.style.left = "0px";
        this.div_.style.top = "0px";
        }

    } );
    
// ------------------------------------------------------------------------------------
NSB.journey_map = null;
NSB.updateJourneyMapSimple = function()
    {
    if( !NSB.journey_map )
        NSB.journey_map = new NSB.JourneyMapSimple( 'journey_map', 'journey_map_box' );
    else
        NSB.journey_map.updateJourneyMap();
    return NSB.journey_map;
    };

// ------------------------------------------------------------------------------------
NSB.JourneyMapSimple = Class.create( NSB.GMapBasic,
    {
    initialize: function( $super, ijelem_id, imap_elem_id )
        {
        $super( ijelem_id, imap_elem_id );
        
        this.map_box = $( imap_elem_id );
        
                                    // be nice to the white-out by supplying
                                    //     a valid nw coord
        var nw = this.gmap.fromDivPixelToLatLng( new GPoint( 0, 0 ) );        
        this.white_out = new NSB.JourneyMapWhiteOut( nw );
        this.gmap.addOverlay( this.white_out );
            
                                    // display map as per "vertical" N <-> S route
        var active_bnds = { left: '455px', top: '27px', width: '375px', height: '470px' };
        $( 'active_area' ).setStyle( active_bnds );
        
        this.updateVehicle();
        if( this.update_secs )
            new PeriodicalExecuter( this.updateVehicle.bind( this ), this.update_secs );
        },
        
    updateVehicle: function()
        {
        doAjaxAdapterCallJS( 'journey', 'getJourneyVehicleSimpleRendered', {}, '',
                                            this.onUpdateVehicle.bind( this ) );
        },
    
    onUpdateVehicle: function( iresponse )
        {
        if( iresponse.responseJSON == -1 )
            {           // the journey has changed
            window.location =  '/view_your_journey';
            return;
            }

        var vals = iresponse.responseJSON;

        this.vehicle_gps = new GLatLng( vals.gps_lat, vals.gps_long );

        if( this.vehicle_overlay )
            this.vehicle_overlay.setLatLngPos( this.vehicle_gps );
        else
            {
            this.vehicle_overlay = new NSB.JourneyMapVehicleSimple( this.vehicle_gps, vals.html );
            this.gmap.addOverlay( this.vehicle_overlay );
            }
        }
    } );
    
// ------------------------------------------------------------------------------------
NSB.JourneyMapVehicleSimple = Class.create( NSB.DivOverlay,
    {   /* shows the simplified vehicle on the map */
    initialize: function( $super, inw_loc, ihtml )
        {
        if( $super( inw_loc ) )
            return true;
        this.clickable = false;
        this.div_.update( ihtml );
        // readInitVals( this.div_.firstDescendant(), this );
        },
        
    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    setLatLngPos: function( iloc )
        {   /* realised that the base-class version of this method is a
                    bit crap - this is probably more like it should be */
        this.nw_loc_ = iloc;
        this.redraw( true );    // this does what we want
        },

    //  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    redraw: function( force )
        {
        if (!force) 
            return;
        var nw_pix = this.gmap.fromLatLngToDivPixel( this.nw_loc_ );        
        var bofst = 13;      // this is half the size of the vehicle blob
        this.div_.style.left = nw_pix.x - bofst + "px";
        this.div_.style.top = nw_pix.y - bofst + "px";
        
        this.div_.style.width = "27px";
        this.div_.style.height = "27px";
        }
    } );
    
        

