/**
 * City of Kingston Site Script / Sub app: Transit Trip Planner
 * Created: October 2009      - Web Paving / SRB
 * Last edited: Mar 23, 2010  - Web Paving / SRB {Added Accessible Route detection}
 * v0.9 
 */

// Google API vars outside of WPTripPlanner namespace
var map;
var directions;

document.addEvent('domready', function() {

    var WPTripPlanner = {
        CFG: {
            sAppUrl: '/residents/transportation/transit/trip-planner/',
            sGoogleKey: null,
            sServerSessionID: null
        },
        STAT: {
            iSessionID: null,
            sSessionKey: null,
            iCurrentTab: 1,
            iTabCount: null,
            iCurrentStep: null,
            iStepsCompleted: null,
            ajxResponse: false
        },
           
        /**
         * Set states on initial page load.
         */
        initApp: function() {
            var self = this; // Keep scope of outer 'this'
            // 
            var iStep = document.id('iCurrentStep');
            if (iStep) { 
                self.STAT.iCurrentStep = parseInt(iStep.get('value'));
                self.STAT.iSessionID = parseInt(document.id('pi').get('value'));
                self.STAT.sSessionKey = document.id('k').get('value');
                // Configure a Requester instance              
                var myRequester = new Request({
                    url: self.CFG.sAppUrl,
                    method: 'get',
                    data: {
                        ajax: true,
                        action: 'initapp',
                        pi: self.STAT.iSessionID, 
                        k: self.STAT.sSessionKey            
                    },
                    onSuccess: function(responseTxt) {
                        var config = JSON.decode(responseTxt);
                        self.STAT.iStepsCompleted = config.iStepsCompleted;
                        self.CFG.sGoogleKey = config.sGoogleKey;
                        self.CFG.sServerSessionID = config.sServerSessionID;
                        //
                        if (self.STAT.iCurrentStep < 4 ) {        
                            // Init hoverboxes for search
                            self.popBox(
                                60,          // Offset (from left margin)
                                '_mbox',     // Box suffix
                                'mbox_close' // Close class
                            );
                        }
                        if (1 === self.STAT.iCurrentStep || 2 === self.STAT.iCurrentStep) {        
                            if (config.sLocSearchField) {
                                self.initAddressField(config.sLocSearchField);
                            }
                        }
                        if (3 === self.STAT.iCurrentStep) {
                            if (config.sDateField && config.sTimeField) {
                                var dateField = document.id(config.sDateField);
                                if (typeof(dateField) !== 'undefined') {
                                    var timeField = document.id(config.sTimeField);
                                    self.initDateField(dateField, timeField);
                                }
                            }
                        }
                        if (4 === self.STAT.iCurrentStep){
                            // Init help box
                            self.popBox(
                                60,          // Offset (from left margin)
                                '_mbox',     // Box suffix
                                'mbox_close' // Close class
                            );
                            
                            self.STAT.iTabCount = parseInt(document.id('tc').get('value'));
                            if(self.STAT.iTabCount > 1) {
                                self.setPlanTabs();
                            }
                            self.setInfoLinks();
                            self.initLinkMgr();
                        }
                    },
                    onFailure: function(xhr) {
                        alert('Initialization error: ' + xhr);
                    }
                }); 
                myRequester.send();
            }
        },
        
        /**
         * Set up form input field for auto-complete functionality.
         * Here we are enabling just one field at a time by passing in 
         * element already selected by ID.
         * 
         * Requires: Harald Kirschner's Autocompleter 
         */
        initAddressField: function(addressField) {
            // var self = this; // Keep scope of outer 'this'
            new Autocompleter.Request.HTML(addressField, this.CFG.sAppUrl, {
                indicatorClass: 'autocompleter-loading',
                minLength: 3,
                maxChoices: 12,
                // overflow: true,
                // overflowMargin: 24,
                postData: {
                    action: 'picklist',
                    ajax: true
                },
                injectChoice: function (choice) {
                    // choice is one <li> element
                    var text = choice.getFirst();
                    // the first element in this <li> is the <span> with the text
                    var value = text.innerHTML;
                    // inputValue saves value of the element for later selection
                    choice.inputValue = value;
                    // overrides the html with the marked query value (wrapped in a <span>)
                    text.set('html', this.markQueryValue(value));
                    // add the mouse events to the <li> element
                    this.addChoiceEvents(choice);
                }
            });
        },

        /**
         * Establish behavior for info links (map / stop details) 
         */
        setInfoLinks: function() {
            var self = this; // Keep scope of outer 'this'
            $$('div.step').each(function(el) {
                var mapPanel = el.getElement('div.mapPanel');
                var stopPanel = el.getElement('div.stopPanel');
                // Settings if mapPanel is found in this div
                if (mapPanel) {                
                    var mapFx = new Fx.Slide(mapPanel, {
                        duration: 500,
                        transition: Fx.Transitions.Sine.easeInOut
                    }).hide();
                    mapPanel.setStyle('display', 'block');
                    // Get any anchor for a map panel link
                    var eMlnk = el.getElement('a.mapLnk');
                    if (eMlnk) {
                        eMlnk.addEvent('click', function(e){
                            mapFx.toggle();
                            mapPanel.toggleClass('closed');
                            // Toggle display of the link itself
                            eMlnk.toggleClass('open');
                            if (eMlnk.hasClass('open')) {
                                // Get link link data
                                var myUri = parseURI(eMlnk);
                                // 
                                if (! mapPanel.retrieve('cached')) {
                                    // Map not cached, so get map content
                                    self.showMap(mapPanel, myUri);
                                    mapPanel.store('cached', true);    
                                }
                                eMlnk.set('text', 'Hide Map');
                            } else {
                                eMlnk.set('text', 'Map This Step');
                            }
                            e.stop();
                        });
                       }
                } // end if(mapPanel)
                
                // Settings if stopPanel is found in this div
                if (stopPanel) {
                    var infFx = new Fx.Slide(stopPanel, {
                        duration: 500,
                        transition: Fx.Transitions.Sine.easeInOut
                    }).hide();
                    stopPanel.setStyle('display', 'block');
                    // Get any anchor for a stop-info panel link
                    var eSlnk = el.getElement('a.infLnk');
                    if (eSlnk) {
                        eSlnk.addEvent('click', function(e){
                            infFx.toggle();
                            stopPanel.toggleClass('closed');
                            // Toggle display of the link itself
                            eSlnk.toggleClass('open');
                            if (eSlnk.hasClass('open')) {
                                // Get tab/stop target info
                                var myUri = parseURI(eSlnk); 
                                if (! stopPanel.retrieve('cached')) {
                                    // Stop info not cached, so get map content
                                    self.showStop(stopPanel, myUri);
                                    stopPanel.store('cached', true);
                                } 
                                eSlnk.set('text', 'Hide Details');
                            } else {
                                eSlnk.set('text', 'Route & Stop Details');
                            }
                            
                            
                            e.stop();
                        });
                    }
                } // end if(stopPanel)
            });
        },

        /**
         * Request and display map info panel 
         */
        showMap: function(panel, myUri) {
            var self = this; // Keep scope of outer 'this'
            // Add 'wait' spinner
           var mySpinner = new Spinner(panel);
           mySpinner.toggle();
            
            //  panel.set('html', '<div class="tpPnlAjx"></div>');
            // Assemble div name for Google service
            var theDiv = 'map' + myUri.params.mi;
            
            // Configure the myRequester instance              
            var myRequester = new Request({
                url: self.CFG.sAppUrl,
                method: 'get',
                data: {
                    ajax: true,
                    action: myUri.params.action,
                    tab: myUri.params.tab,
                    mi: myUri.params.mi,
                    pi: self.STAT.iSessionID, 
                    k: self.STAT.sSessionKey            
                },
                onSuccess: function (responseTxt) {
                    var stopIcon = new GIcon(G_DEFAULT_ICON);
                    stopIcon.image = '/img/icons/marker_bus.png';
                    stopIcon.iconSize = new GSize(32, 37);
                    // stopIcon.shadowSize = new GSize(2, 2);
                    stopIcon.iconAnchor = new GPoint(16, 37);
                    var markerOptions = { icon:stopIcon };
                    
                    var mapData;
                    var directionsPanel;
                    var sKmlUrl;
                    var destMarker;
                    //
                    mapData = JSON.decode(responseTxt);
                    if (GBrowserIsCompatible()) {
                        sKmlUrl = self.CFG.sAppUrl + '?action=kml&tab=' + myUri.params.tab + '&pi='  + self.STAT.iSessionID + '&k=' + self.STAT.sSessionKey; 
                        map = new GMap2(document.getElementById(theDiv));
                        if ('stop' == mapData.type) {
                            map.setCenter(new GLatLng(mapData.lat, mapData.long), 16);
                        }
                        if ('walkTo' == mapData.type || 'walkFrom' == mapData.type) {
                            var end = 0;
                            if ('walkFrom' == mapData.type) {
                                var end = 1;
                            }
                            directionsPanel = document.getElementById('dirPanel');
                            directions = new GDirections(map, directionsPanel);
                            GEvent.addListener(directions, "error", handleGoogleErrors);
                            GEvent.addListener(directions, "addoverlay", function() {
                                   onWalkAddOverlay(end);
                            });
                            directions.load(mapData.path, {travelMode:G_TRAVEL_MODE_WALKING});
                        }
                        // map.addOverlay(geoXml);
                        var count = mapData.stops.length;  
                        for (var i = 0; i < count; i++) {
                            var latLng = new GLatLng(mapData.stops[i].lat, mapData.stops[i].long);
                            map.addOverlay(new GMarker(latLng, markerOptions));
                        }                            
                        map.setUIToDefault();
                    }
                    mySpinner.toggle();
                },
                onFailure: function(xhr) {
                    panel.set('html', '<h4>Map Data Unavailable</h4>');
                }
            });
            myRequester.send();
        },

        /**
         * Request and display stop info panel 
         */
        showStop: function(panel, myUri) {
            var self = this; // Keep scope of outer 'this'

            // Add 'wait' spinner
            panel.set('html', '<div class="tpPnlAjx"></div>');
            // Configure the myRequester instance              
            var myRequester = new Request({
                url: self.CFG.sAppUrl,
                method: 'get',
                data: {
                    ajax: true,
                    action: myUri.params.action,
                    tab: myUri.params.tab,
                    si: myUri.params.si,
                    pi: self.STAT.iSessionID, 
                    k: self.STAT.sSessionKey            
                },
                onSuccess: function (responseTXT) {
                    // Insert HTML into tpWrapper
                    panel.set('html', responseTXT);
                    
                    // var divHeight = getSize(panel.getElement('.stopInfo'));
                    // alert(divHeight.y);
                    // panel.set('height', divHeight.y)
                    
                    self.showStopTimes(panel);
                },
                onFailure: function(xhr) {
                    alert('Initialization error: ' + xhr);
                }
            });
               myRequester.send();
        },
        
        /**
         * Request and display stop info panel 
         */
        showStopTimes: function(panel) {
            var self = this; // Keep scope of outer 'this'
            var timesDiv =  panel.getElement('div .stopTimes');
            
            timesDiv.getElements('a').addEvent('click', function (e) {
                var myUri = parseURI(this);
                e.preventDefault();
                // Store current content of times Div (the table)
                var lastHTML = timesDiv.get('html');
                timesDiv.store('content', lastHTML);
                // Add 'wait' spinner
                var mySpinner = new Spinner(timesDiv, {'class': 'alert', 'message': 'Searching...'});
                mySpinner.toggle();
                
                // timesDiv.set('html', '<div class="tpPnlAjx">Searching</div>');
                // Configure the myRequester instance
                var myRequester = new Request({
                    url: self.CFG.sAppUrl,
                    method: 'get',
                    data: {
                        ajax: true,
                        action: myUri.params.action,
                        tab: myUri.params.tab,
                        si: myUri.params.si,
                        sx: myUri.params.sx,
                        pi: self.STAT.iSessionID, 
                        k: self.STAT.sSessionKey            
                    },
                    onSuccess: function (responseTXT) {
                        // Insert HTML into times div
                        mySpinner.toggle();
                        timesDiv.set('html', responseTXT);
                        
                        // Init Close/Hide Button...
                        timesDiv.getElements('a.hide').addEvent('click', function (e) {
                            e.preventDefault();
                            timesDiv.set('html', timesDiv.retrieve('content'));
                            self.initStopTimes(panel);
                        });
                        
                    },
                    onFailure: function(xhr) {
                        alert('Initialization error: ' + xhr);
                    }
                });
                   myRequester.send();
            });
        },
        
        
        
        /**
         * Display Link toolbox 
         */
        initLinkMgr: function () {
            var self = this; // Keep scope of outer 'this'
            var toolBox = document.id('toolBox');
            if (toolBox) {        
                var boxFx = new Fx.Slide(toolBox, {
                    duration: 500,
                    transition: Fx.Transitions.Sine.easeInOut
                }).hide();
                // toolBox.setStyle('display', 'block');
            }
            var makeLnk = document.id('makeLnk');
            if (makeLnk) {
                makeLnk.addEvent('click', function(e){
                    e.stop();
                    if (! toolBox.hasClass('open')) {
                        toolBox.setStyle('display', 'block');
                        boxFx.show();
                        toolBox.toggleClass('open');
                    }
                    if (! toolBox.retrieve('cached')) {
                        var myUri = parseURI(this);
                        if (myUri.params) {
                            var mySpinner = new Spinner(toolBox);
                            mySpinner.toggle();
                            var myQuery = new Request({
                                url: myUri.path,
                                method: 'get',
                                onSuccess: function (responseTXT) {
                                    mySpinner.toggle();
                                    toolBox.set('html', responseTXT);
                                    // 
                                    var closeButton = document.id('LMdiv_close');
                                    closeButton.addEvent('mouseover', function(e){
                                        closeButton.setStyle('cursor', 'pointer');         
                                    });
                                    closeButton.addEvent('click', function(e){
                                        e.stop();
                                        if (toolBox.hasClass('open')) {
                                            toolBox.setStyle('display', 'none');
                                            boxFx.hide();
                                            toolBox.toggleClass('open');
                                        }
                                    });
                                    
                                    var urlIn = document.id('copy2clipboard');
                                    urlIn.select();
                                    urlIn.addEvent('onfocus', function() {
                                        urlIn.select(); 
                                    });
                                    var clip = new ZeroClipboard.Client();
                                    clip.addEventListener('mousedown', function() {
                                        clip.setText(document.getElementById('copy2clipboard').value);
                                    });
                                    clip.addEventListener('complete',function(client,text) {
                                        alert("The link has been copied\nto your computer's clipboard.");
                                     });
                                     //glue it to the button
                                     clip.glue('copy');
                                     //     
                                     self.popBox(
                                            60,            // Offset (from left margin)
                                            '_mboxLM',     // Box suffix
                                            'mboxLM_close' // Close class
                                     );
                                     toolBox.store('cached', true);
                                 }
                            });
                            myQuery.send('ajax=true&action=' + myUri.params.action + '&tab=' + myUri.params.tab + '&pi=' + myUri.params.pi + '&k=' + myUri.params.k);
                         }
                      }
                 });
             }
        },

        /**
         * Establish behavior for plan tabs, 
         * loading new plans where appropriate 
         */
        setPlanTabs: function () {
            var self = this; // Keep scope of outer 'this'
            $$('div.sPTabs a').addEvent('click', function (e) {
                e.stop();
                var myUri = parseURI(this);
                if (myUri.params) {
                    var myWrapper = document.id('tpWrapper');
                    var mySpinner = new Spinner(this);
                    mySpinner.toggle();
                    var myQuery = new Request({
                        url: myUri.path,
                        method: 'get',
                        onSuccess: function (responseTXT) {
                            mySpinner.toggle();
                            // Insert HTML into tpWrapper
                            myWrapper.set('html', responseTXT);

                            // Hot link previously active tab
                            var aTab = document.id('tpTabActive');
                            var aTxt = aTab.get('text');
                            var aCls = aTab.get('class');
                            var tNum = aTxt.split(' ')
                            var nAnc = new Element('a', {
                                id: 'tpTab' + tNum[1],
                                href: myUri.path + '?action=swtab&tab=' + tNum[1] + '&pi=' + myUri.params.pi + '&k=' + myUri.params.k + '&cls=' + aCls,
                                text: aTxt,
                                'class': aCls
                            });
                            nAnc.replaces(aTab);

                            // Set clicked tab to active
                            var oTab = document.id('tpTab' + myUri.params.tab);
                            var nTxt = oTab.get('text');
                            var nSpan = new Element('span', {
                                id: 'tpTabActive',
                                text: nTxt,
                                'class': myUri.params.cls
                            });
                            nSpan.replaces(oTab);

                            // Clean up, then re-init
                            $$('div.sPTabs a').removeEvents('click');
                            self.initPlanTabs();
                            self.initInfoLinks();
                            self.STAT.iCurrentTab = myUri.params.pi;
                            // self.status = [];
                        }
                    });
                    // myWrapper.set('html', '<div id="tpSumAjx"></div>');
                    myQuery.send('ajax=true&action=' + myUri.params.action + '&tab=' + myUri.params.tab + '&pi=' + myUri.params.pi + '&k=' + myUri.params.k);
                }
            });
        },

        /**
         * Set up form input fields and functionality for date/time entry.
         * 
         * Requires: Datepicker from MonkeyPhysics.com 
         */
        initDateField: function (dateField, timeField) {
            // var self = this;
            new DatePicker(dateField, {
                inputOutputFormat: 'D., M. j, Y',
                yearPicker: true,
                timePicker: false,
                startDay: 0,
                positionOffset: {
                    x: 180,
                    y: -210
                },
                toggleElements: document.id('CalendarIcon'),
                format: 'D., M. j, Y',
                minDate: {
                    date: '0',
                    format: 'd'
                },
                onSelect: function (selectedDate) {
                    var today = new Date();
                    if (today.getDay() === selectedDate.getDay()) {
                        timeField.set('value', 'Now');
                    } else {
                        timeField.set('value', '');
                    }
                }
            });
        },

        /**
         * Re-init tab behavior
         */
        initPlanTabs: function() {
            this.setPlanTabs();
        },
        /**
         * Re-init InfoLink behavior
         */
        initInfoLinks: function() {
            this.setInfoLinks();
        },
        /**
         * Re-init next-times links
         */
        initStopTimes: function(panel) {
            this.showStopTimes(panel);
        },
        
        popBox: function(leftIndent, popBoxSuffix, popBoxClose) {
            
            var popBoxes = document.id(document.body).getElements('[id$=' + popBoxSuffix + ']');
            var closeElem = document.id(document.body).getElements('.' + popBoxClose);  
            var closeBoxes = function() {
                popBoxes.setStyle('display', 'none');
            };
            closeElem.addEvent('click', function(){
                closeBoxes();
            }).setStyle('cursor', 'pointer');
            
            popBoxes.each(function(item){ 
                var currentBox = item.getProperty('id');
                currentBox = currentBox.replace('' + popBoxSuffix + '', '');   
                item.setStyle('margin', '0'); 
                document.id(currentBox).addEvent('click', function(){  
                    popBoxes.setStyle('display', 'none');
                    item.setStyles({ display: 'block', position: 'absolute' }).setStyle('z-index', '1000000');
                    // Position box where it can be seen 
                    var windowSize = document.id(window).getSize();
                    var windowScroll = document.id(window).getScroll();
                    var boxSize = item.getSize();
                    var fromTop = windowScroll.y + ((windowSize.y / 2) - (boxSize.y / 2));
                    // var leftIndent = (windowSize.x / 2) - (boxSize.x / 2);
                    item.setStyles({top: fromTop, left: leftIndent}); 
                }).setStyle('cursor', 'pointer');
                
                var myHandle = item.getElement('.msgBar');
                var handleFx = new Fx.Tween(myHandle, {duration:200});
                var boxFx = new Fx.Tween(item, {duration:200});
                
                myHandle.addEvents({
                    mouseover:  function() {
                        handleFx.start('background-color', '#69c');
                        boxFx.start('border-color', '#69c');
                    },
                    mouseout:  function() {
                        handleFx.start('background-color', '#aaa');
                        boxFx.start('border-color', '#aaa');
                    }
                });
                var myDrag = new Drag.Move(item, {
                    snap: 3,
                    // handle: myHandle,
                    onStart: function(el) {
                        el.fade(0.5);
                        el.style.cursor = 'move';
                    },
                    onComplete: function(el) {
                        el.fade('in');
                        el.style.cursor = 'default';
                    }
                });
            });
        }
        
    } // End of WPTripPlan

    
    // Kick-start this app
    WPTripPlanner.initApp();
    
});


/**
/ parseURI
/ ---------
/ Credit: James Padolsey <http://james.padolsey.com/javascript/parsing-urls-with-the-dom/>
/
/ This function creates a new DOM anchor element and uses location
/ properties (inherent) to get the desired URI data. Some String
/ operations are used (to normalize results across browsers).
*/
function parseURI(uri) {
    var a = document.createElement('a');
    a.href = uri;
    return {
        source: uri,
        protocol: a.protocol.replace(':', ''),
        host: a.hostname,
        port: a.port,
        query: a.search,
        params: (function () {
            var ret = {},
            seg = a.search.replace(/^\?/, '').split('&'),
            len = seg.length,
            i = 0,
            s;
            for (; i < len; i++) {
                if (!seg[i]) {
                    continue;
                }
                s = seg[i].split('=');
                ret[s[0]] = s[1];
            }
            return ret;
        })(),
        file: (a.pathname.match(/\/([^\/?#]+)$/i) || [, ''])[1],
        hash: a.hash.replace('#', ''),
        path: a.pathname.replace(/^([^\/])/, '/$1'),
        relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [, ''])[1],
        segments: a.pathname.replace(/^\//, '').split('/')
    };
}

function handleGoogleErrors(){
    if (directions.getStatus().code == G_GEO_UNKNOWN_ADDRESS)
        alert("No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.\nError code: " + directions.getStatus().code);
    else if (directions.getStatus().code == G_GEO_SERVER_ERROR)
        alert("A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.\n Error code: " + directions.getStatus().code);
    else if (directions.getStatus().code == G_GEO_MISSING_QUERY)
        alert("The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.\n Error code: " + directions.getStatus().code);
    else if (directions.getStatus().code == G_GEO_BAD_KEY)
        alert("The given key is either invalid or does not match the domain for which it was given. \n Error code: " + directions.getStatus().code);
    else if (directions.getStatus().code == G_GEO_BAD_REQUEST)
        alert("A directions request could not be successfully parsed.\n Error code: " + directions.getStatus().code);
    else alert("An unknown error occurred.");
 }

//Simple Set Clipboard System
//Author: Joseph Huckaby

var ZeroClipboard = {
 
 version: "1.0.4",
 clients: {}, // registered upload clients on page, indexed by id
 moviePath: '/js/ZeroClipboard.swf', // URL to movie
 nextId: 1, // ID of next movie
 
 $: function(thingy) {
     // simple DOM lookup utility function
     if (typeof(thingy) == 'string') thingy = document.getElementById(thingy);
     if (!thingy.addClass) {
         // extend element with a few useful methods
         thingy.hide = function() { this.style.display = 'none'; };
         thingy.show = function() { this.style.display = ''; };
         thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; };
         thingy.removeClass = function(name) {
             this.className = this.className.replace( new RegExp("\\s*" + name + "\\s*"), " ").replace(/^\s+/, '').replace(/\s+$/, '');
         };
         thingy.hasClass = function(name) {
             return !!this.className.match( new RegExp("\\s*" + name + "\\s*") );
         }
     }
     return thingy;
 },
 
 setMoviePath: function(path) {
     // set path to ZeroClipboard.swf
     this.moviePath = path;
 },
 
 dispatch: function(id, eventName, args) {
     // receive event from flash movie, send to client       
     var client = this.clients[id];
     if (client) {
         client.receiveEvent(eventName, args);
     }
 },
 
 register: function(id, client) {
     // register new client to receive events
     this.clients[id] = client;
 },
 
 getDOMObjectPosition: function(obj) {
     // get absolute coordinates for dom element
     var info = {
         left: 0, 
         top: 0, 
         width: obj.width ? obj.width : obj.offsetWidth, 
         height: obj.height ? obj.height : obj.offsetHeight
     };

     while (obj) {
         info.left += obj.offsetLeft;
         info.top += obj.offsetTop;
         obj = obj.offsetParent;
     }

     return info;
 },
 
 Client: function(elem) {
     // constructor for new simple upload client
     this.handlers = {};
     
     // unique ID
     this.id = ZeroClipboard.nextId++;
     this.movieId = 'ZeroClipboardMovie_' + this.id;
     
     // register client with singleton to receive flash events
     ZeroClipboard.register(this.id, this);
     
     // create movie
     if (elem) this.glue(elem);
 }
};

ZeroClipboard.Client.prototype = {
 
 id: 0, // unique ID for us
 ready: false, // whether movie is ready to receive events or not
 movie: null, // reference to movie object
 clipText: '', // text to copy to clipboard
 handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor
 cssEffects: true, // enable CSS mouse effects on dom container
 handlers: null, // user event handlers
 
 glue: function(elem) {
     // glue to DOM element
     // elem can be ID or actual DOM element object
     this.domElement = ZeroClipboard.$(elem);
     
     // float just above object, or zIndex 99 if dom element isn't set
     var zIndex = 99;
     if (this.domElement.style.zIndex) {
         zIndex = parseInt(this.domElement.style.zIndex) + 1;
     }
     
     // find X/Y position of domElement
     var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
     
     // create floating DIV above element
     this.div = document.createElement('div');
     var style = this.div.style;
     style.position = 'absolute';
     style.left = '' + box.left + 'px';
     style.top = '' + box.top + 'px';
     style.width = '' + box.width + 'px';
     style.height = '' + box.height + 'px';
     style.zIndex = zIndex;
     
     // style.backgroundColor = '#f00'; // debug
     
     var body = document.getElementsByTagName('body')[0];
     body.appendChild(this.div);
     
     this.div.innerHTML = this.getHTML( box.width, box.height );
 },
 
 getHTML: function(width, height) {
     // return HTML for movie
     var html = '';
     var flashvars = 'id=' + this.id + 
         '&width=' + width + 
         '&height=' + height;
         
     if (navigator.userAgent.match(/MSIE/)) {
         // IE gets an OBJECT tag
         var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
         html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="'+protocol+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="'+width+'" height="'+height+'" id="'+this.movieId+'" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+ZeroClipboard.moviePath+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/><param name="wmode" value="transparent"/></object>';
     }
     else {
         // all other browsers get an EMBED tag
         html += '<embed id="'+this.movieId+'" src="'+ZeroClipboard.moviePath+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+width+'" height="'+height+'" name="'+this.movieId+'" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'" wmode="transparent" />';
     }
     return html;
 },
 
 hide: function() {
     // temporarily hide floater offscreen
     if (this.div) {
         this.div.style.left = '-2000px';
     }
 },
 
 show: function() {
     // show ourselves after a call to hide()
     this.reposition();
 },
 
 destroy: function() {
     // destroy control and floater
     if (this.domElement && this.div) {
         this.hide();
         this.div.innerHTML = '';
         
         var body = document.getElementsByTagName('body')[0];
         try { body.removeChild( this.div ); } catch(e) {;}
         
         this.domElement = null;
         this.div = null;
     }
 },
 
 reposition: function(elem) {
     // reposition our floating div, optionally to new container
     // warning: container CANNOT change size, only position
     if (elem) {
         this.domElement = ZeroClipboard.$(elem);
         if (!this.domElement) this.hide();
     }
     
     if (this.domElement && this.div) {
         var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
         var style = this.div.style;
         style.left = '' + box.left + 'px';
         style.top = '' + box.top + 'px';
     }
 },
 
 setText: function(newText) {
     // set text to be copied to clipboard
     this.clipText = newText;
     if (this.ready) this.movie.setText(newText);
 },
 
 addEventListener: function(eventName, func) {
     // add user event listener for event
     // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
     eventName = eventName.toString().toLowerCase().replace(/^on/, '');
     if (!this.handlers[eventName]) this.handlers[eventName] = [];
     this.handlers[eventName].push(func);
 },
 
 setHandCursor: function(enabled) {
     // enable hand cursor (true), or default arrow cursor (false)
     this.handCursorEnabled = enabled;
     if (this.ready) this.movie.setHandCursor(enabled);
 },
 
 setCSSEffects: function(enabled) {
     // enable or disable CSS effects on DOM container
     this.cssEffects = !!enabled;
 },
 
 receiveEvent: function(eventName, args) {
     // receive event from flash
     eventName = eventName.toString().toLowerCase().replace(/^on/, '');
             
     // special behavior for certain events
     switch (eventName) {
         case 'load':
             // movie claims it is ready, but in IE this isn't always the case...
             // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
             this.movie = document.getElementById(this.movieId);
             if (!this.movie) {
                 var self = this;
                 setTimeout( function() { self.receiveEvent('load', null); }, 1 );
                 return;
             }
             
             // firefox on pc needs a "kick" in order to set these in certain cases
             if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
                 var self = this;
                 setTimeout( function() { self.receiveEvent('load', null); }, 100 );
                 this.ready = true;
                 return;
             }
             
             this.ready = true;
             this.movie.setText( this.clipText );
             this.movie.setHandCursor( this.handCursorEnabled );
             break;
         
         case 'mouseover':
             if (this.domElement && this.cssEffects) {
                 this.domElement.addClass('hover');
                 if (this.recoverActive) this.domElement.addClass('active');
             }
             break;
         
         case 'mouseout':
             if (this.domElement && this.cssEffects) {
                 this.recoverActive = false;
                 if (this.domElement.hasClass('active')) {
                     this.domElement.removeClass('active');
                     this.recoverActive = true;
                 }
                 this.domElement.removeClass('hover');
             }
             break;
         
         case 'mousedown':
             if (this.domElement && this.cssEffects) {
                 this.domElement.addClass('active');
             }
             break;
         
         case 'mouseup':
             if (this.domElement && this.cssEffects) {
                 this.domElement.removeClass('active');
                 this.recoverActive = false;
             }
             break;
     } // switch eventName
     
     if (this.handlers[eventName]) {
         for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
             var func = this.handlers[eventName][idx];
         
             if (typeof(func) == 'function') {
                 // actual function reference
                 func(this, args);
             }
             else if ((typeof(func) == 'object') && (func.length == 2)) {
                 // PHP style object + method, i.e. [myObject, 'myMethod']
                 func[0][ func[1] ](this, args);
             }
             else if (typeof(func) == 'string') {
                 // name of function
                 window[func](this, args);
             }
         } // foreach event handler defined
     } // user defined handler for event
 }
 
};




function surveyPopper(urlPop, windowW)
{
  var windowH = (screen.height - 80);
  var windowX = 10;
  var windowY = 10;
  var s = "resizable=1,width="+windowW+",height="+windowH;
  window.open(urlPop,"popFrameless","scrollbars,"+s)
}

// Note the 'addoverlay' GEvent listener brings us here
function onWalkAddOverlay(end){

    var custIcon = new GIcon(G_DEFAULT_ICON);
    custIcon.iconSize = new GSize(32, 37);
    // custIcon.shadowSize = new GSize(2, 2);
    custIcon.iconAnchor = new GPoint(16, 37);
    
    var newMarkers = [];
    var latLngs = [];
    var icon;
    
    icon = new GIcon(custIcon);
    icon.image = '/img/icons/marker_walk.png';
    
    var newMarker;
    var latLngs = [];

     // Loop through Google's markers and remove
     for (var i=0; i<= directions.getNumRoutes(); i++){
        var originalMarker = directions.getMarker(i);
        latLngs[i] = originalMarker.getLatLng();
        map.removeOverlay(originalMarker);
    }
     newMarker = new GMarker(latLngs[end], {
         icon: icon,
         draggable: false 
         });
     map.addOverlay(newMarker);
}


