
    // issues:
    // xmlhttprequest timeout? bother with this?
    // error log should be reporting errors

    // notes:
    // to get longitude and lattitude in google maps, center map, then
    // javascript:void(prompt('',gApplication.getMap().getCenter()));
    // multiple leg trips, don't forget drop down setting
    // multi leg trips could be difficult, where to link to for purchase? maybe that's where we can charge a fee
    // multi leg trips also too many concurrent xmlhttprequests?
    // do something about atlantic city casinos
    // i don't have the atlantic city trips for megabus added
    // for each operator, max nbr passengers, max date, detecting changes
    // write a better, multithreaded proxy, not servlet, runs from command line, handles redirects

    // things i've learned:
    // javascript associative arrays are crap, conflict with prototype declarations
    // ie6 doesn't support javascript const
    // div padding increases the div's width
    // <input type="image"> submits the x,y coordinates
    // <select> without any options doesn't get submitted with the form
    // neither does any input without a name
    // Transfer-Encoding: chunked is interesting, don't need a Content-Length header

var routeFunctions = new Array();

    // neighborhood codes

var ALBANY_DOWNTOWN = 0;
var ANN_ARBOR_UM = ALBANY_DOWNTOWN + 1;
var ATLANTIC_CITY_BOARDWALK = ANN_ARBOR_UM + 1;
var BALTIMORE_PENN_STATION = ATLANTIC_CITY_BOARDWALK + 1;
var BALTIMORE_TRAVEL_PLAZA = BALTIMORE_PENN_STATION + 1;
var BALTIMORE_WHITE_MARSH = BALTIMORE_TRAVEL_PLAZA + 1;
var BOSTON_SOUTH_STATION = BALTIMORE_WHITE_MARSH + 1;
var BUFFALO_AIRPORT = BOSTON_SOUTH_STATION + 1;
var BUFFALO_TRANSPORTATION_CENTER = BUFFALO_AIRPORT + 1;
var CHAMPAIGN_ILLINOIS_TERMINAL = BUFFALO_TRANSPORTATION_CENTER + 1;
var CHICAGO_UNION_STATION = CHAMPAIGN_ILLINOIS_TERMINAL + 1;
var CINCINNATI_DOWNTOWN = CHICAGO_UNION_STATION + 1;
var CLEVELAND_TOWER_CITY = CINCINNATI_DOWNTOWN + 1;
var COLUMBIA_WABASH = CLEVELAND_TOWER_CITY + 1;
var COLUMBUS_DOWNTOWN = COLUMBIA_WABASH + 1;
var COLUMBUS_OSU = COLUMBUS_DOWNTOWN + 1;
var DES_MOINES_DOWNTOWN = COLUMBUS_OSU + 1;
var DETROIT_DOWNTOWN = DES_MOINES_DOWNTOWN + 1;
var DETROIT_WSU = DETROIT_DOWNTOWN + 1;
var INDIANAPOLIS_DOWNTOWN = DETROIT_WSU + 1;
var IOWA_CITY_UI = INDIANAPOLIS_DOWNTOWN + 1;
var KANSAS_CITY_DOWNTOWN = IOWA_CITY_UI + 1;
var MADISON_HUXLEY = KANSAS_CITY_DOWNTOWN + 1;
var MADISON_DUTCH_MILL = MADISON_HUXLEY + 1;
var MEMPHIS_MATA = MADISON_DUTCH_MILL + 1;
var MILWAUKEE_AMTRAK = MEMPHIS_MATA + 1;
var MILWAUKEE_RYAN_ROAD = MILWAUKEE_AMTRAK + 1;
var MINNEAPOLIS_CENTRAL = MILWAUKEE_RYAN_ROAD + 1;
var MINNEAPOLIS_METRODOME = MINNEAPOLIS_CENTRAL + 1;
var NEW_YORK_CHINATOWN = MINNEAPOLIS_METRODOME + 1;
var NEW_YORK_PENN = NEW_YORK_CHINATOWN + 1;
var NEW_YORK_PORT_AUTHORITY = NEW_YORK_PENN + 1;
var NEW_YORK_SOHO = NEW_YORK_PORT_AUTHORITY + 1;
var NORMAL_AMTRAK = NEW_YORK_SOHO + 1;
var PHILADELPHIA_30TH_STREET = NORMAL_AMTRAK + 1;
var PHILADELPHIA_CHERRY_HILL_MALL = PHILADELPHIA_30TH_STREET + 1;
var PHILADELPHIA_CHINATOWN = PHILADELPHIA_CHERRY_HILL_MALL + 1;
var PITTSBURGH_CONVENTION_CENTER = PHILADELPHIA_CHINATOWN + 1;
var RIDGEWOOD_ROUTE_17 = PITTSBURGH_CONVENTION_CENTER + 1;
var ROCHESTER_AMTRAK = RIDGEWOOD_ROUTE_17 + 1;
var ROCHESTER_HENRIETTA = ROCHESTER_AMTRAK + 1;
var ST_LOUIS_UNION = ROCHESTER_HENRIETTA + 1;
var STATE_COLLEGE_PENN_STATE = ST_LOUIS_UNION + 1;
var SYRACUSE_REGIONAL = STATE_COLLEGE_PENN_STATE + 1;
var TOLEDO_SOUTHWYCK = SYRACUSE_REGIONAL + 1;
var TORONTO_COACH = TOLEDO_SOUTHWYCK + 1;
var WASHINGTON_BETHESDA = TORONTO_COACH + 1;
var WASHINGTON_CHINATOWN = WASHINGTON_BETHESDA + 1;
var WASHINGTON_DUPONT = WASHINGTON_CHINATOWN + 1;
var WASHINGTON_GREENBELT = WASHINGTON_DUPONT + 1;
var WASHINGTON_MCPHERSON = WASHINGTON_GREENBELT + 1;
var WASHINGTON_ROSSLYN = WASHINGTON_MCPHERSON + 1;
var WASHINGTON_UNION_STATION = WASHINGTON_ROSSLYN + 1;

    // time zones

var PST = 0;
var MST = 1;
var CST = 2;
var EST = 3;

var timeZones = new Array();
timeZones[ALBANY_DOWNTOWN] = EST;
timeZones[ANN_ARBOR_UM] = EST;
timeZones[ATLANTIC_CITY_BOARDWALK] = EST;
timeZones[BALTIMORE_PENN_STATION] = EST;
timeZones[BALTIMORE_TRAVEL_PLAZA] = EST;
timeZones[BALTIMORE_WHITE_MARSH] = EST;
timeZones[BOSTON_SOUTH_STATION] = EST;
timeZones[BUFFALO_AIRPORT] = EST;
timeZones[BUFFALO_TRANSPORTATION_CENTER] = EST;
timeZones[CHAMPAIGN_ILLINOIS_TERMINAL] = CST;
timeZones[CHICAGO_UNION_STATION] = CST;
timeZones[CINCINNATI_DOWNTOWN] = EST;
timeZones[CLEVELAND_TOWER_CITY] = EST;
timeZones[COLUMBIA_WABASH] = CST;
timeZones[COLUMBUS_DOWNTOWN] = EST;
timeZones[COLUMBUS_OSU] = EST;
timeZones[DES_MOINES_DOWNTOWN] = CST;
timeZones[DETROIT_DOWNTOWN] = EST;
timeZones[DETROIT_WSU] = EST;
timeZones[INDIANAPOLIS_DOWNTOWN] = EST;
timeZones[IOWA_CITY_UI] = CST;
timeZones[KANSAS_CITY_DOWNTOWN] = CST;
timeZones[MADISON_HUXLEY] = CST;
timeZones[MADISON_DUTCH_MILL] = CST;
timeZones[MEMPHIS_MATA] = CST;
timeZones[MILWAUKEE_AMTRAK] = CST;
timeZones[MILWAUKEE_RYAN_ROAD] = CST;
timeZones[MINNEAPOLIS_CENTRAL] = CST;
timeZones[MINNEAPOLIS_METRODOME] = CST;
timeZones[NEW_YORK_CHINATOWN] = EST;
timeZones[NEW_YORK_PENN] = EST;
timeZones[NEW_YORK_PORT_AUTHORITY] = EST;
timeZones[NEW_YORK_SOHO] = EST;
timeZones[NORMAL_AMTRAK] = CST;
timeZones[PHILADELPHIA_30TH_STREET] = EST;
timeZones[PHILADELPHIA_CHERRY_HILL_MALL] = EST;
timeZones[PHILADELPHIA_CHINATOWN] = EST;
timeZones[PITTSBURGH_CONVENTION_CENTER] = EST;
timeZones[RIDGEWOOD_ROUTE_17] = EST;
timeZones[ROCHESTER_AMTRAK] = EST;
timeZones[ROCHESTER_HENRIETTA] = EST;
timeZones[ST_LOUIS_UNION] = CST;
timeZones[STATE_COLLEGE_PENN_STATE] = EST;
timeZones[SYRACUSE_REGIONAL] = EST;
timeZones[TOLEDO_SOUTHWYCK] = EST;
timeZones[TORONTO_COACH] = EST;
timeZones[WASHINGTON_BETHESDA] = EST;
timeZones[WASHINGTON_CHINATOWN] = EST;
timeZones[WASHINGTON_DUPONT] = EST;
timeZones[WASHINGTON_GREENBELT] = EST;
timeZones[WASHINGTON_MCPHERSON] = EST;
timeZones[WASHINGTON_ROSSLYN] = EST;
timeZones[WASHINGTON_UNION_STATION] = EST;

    // objects

function Operator(nameInput, urlInput, logoURLInput, ratingInput, yelpURLInput, restroomInput, wifiInput, powerInput) {

    this.name = nameInput;
    this.url = urlInput;
    this.logoURL = logoURLInput;
    this.rating = ratingInput;
    this.yelpURL = yelpURLInput;
    this.restroom = restroomInput;
    this.wifi = wifiInput;
    this.power = powerInput;
}

function Location(nameInput, mapURLInput, neighborhoodCodeInput) {

    this.name = nameInput;
    this.mapURL = mapURLInput;
    this.neighborhoodCode = neighborhoodCodeInput;
}

function Route(operatorInput, startLocationInput, endLocationInput) {

    this.operator = operatorInput;
    this.startLocation = startLocationInput;
    this.endLocation = endLocationInput;
}

function Ticket(operatorInput, startLocationInput, endLocationInput, departTimeInput, arriveTimeInput, basePriceInput, priceInput) {

    this.operator = operatorInput;
    this.startLocation = startLocationInput;
    this.endLocation = endLocationInput;
    this.departTime = departTimeInput;
    this.arriveTime = arriveTimeInput;
    this.basePrice = basePriceInput;
    this.price = priceInput;
}

    // global functions

Array.prototype.contains = function(element) {

    for (var i = 0; i < this.length; i++)
        if (this[i] === element)
            return true;

    return false;
};

Array.prototype.indexOf = function(element) {

    for (var i = 0; i < this.length; i++)
        if (this[i] === element)
            return i;

    return -1;
};

Array.prototype.unique = function() {

    var r = new Array();
    o:for(var i = 0, n = this.length; i < n; i++) {
        for(var x = 0, y = r.length; x < y; x++)
            if(r[x] === this[i])
                continue o;
        r[r.length] = this[i];
    }

    return r;
};

function escapeHtml(input) {

    input = input.replace(/&/g, '&amp;');
    input = input.replace(/</g, '&lt;');
    return input;
}

function getParameter(name) {

    var url = window.location.href;
    var encodedName = encodeURIComponent(name);

    if (url.indexOf(encodedName + '=') === -1)
        return null;
    else {
        var value = url.substring(url.indexOf(encodedName + '=') + (encodedName + '=').length);
        if (value.indexOf('&') != -1)
            value = value.substring(0, value.indexOf('&'));
        return decodeURIComponent(value);
    }
}

function createHttpRequest() {

    var httpRequest = null;
    try {
        httpRequest = new XMLHttpRequest();
    } catch(e) {
        try {
            httpRequest = new ActiveXObject('MSXML2.XMLHTTP');
        } catch(e) {
            try {
                httpRequest = new ActiveXObject('Microsoft.XMLHTTP');
            } catch(e) {}
        }
    }

    return httpRequest;
}

function toMilitaryTime(timeString) {

    var colonIndex = timeString.indexOf(':');
    var time = timeString.substring(timeString.length - 2, timeString.length) === 'am' ? 0 : 1200;
    time += parseInt(timeString.substring(0, timeString.length - 2).replace(':', '')) % 1200;

    return time;
}

    // offset can be negative
function addMilitary(time, offset) {

    var temp = time + offset;

    temp += 2400;
    if (offset >= 0 && time % 100 + offset % 100 > 59)
        temp += 40;
    else if (offset < 0 && Math.abs(offset) % 100 > time % 100)
        temp -= 40;
    temp = temp % 2400;

    return temp;
}

function toCents(priceString) {
    return parseInt(priceString.substring(1, priceString.length).replace('.', ''));
}

function getTimeZoneOffset(timeZone, date) {

    var timeZoneOffset;
    var daylightSavingsStartDate;
    var daylightSavingsEndDate;

    switch(timeZone) {
        case PST: // 480
        case MST: // 420
        case CST: // 360
        case EST: // 300

            timeZoneOffset = 480 - 60 * timeZone;

            daylightSavingsStartDate = new Date(date.getFullYear(), 2, 1, 0, 0, 0, 0);
            while (daylightSavingsStartDate.getDay() !== 0)
                daylightSavingsStartDate.setDate(daylightSavingsStartDate.getDate() + 1);
            daylightSavingsStartDate.setDate(daylightSavingsStartDate.getDate() + 7);
            daylightSavingsEndDate = new Date(date.getFullYear(), 10, 1, 0, 0, 0, 0);
            while (daylightSavingsEndDate.getDay() !== 0)
                daylightSavingsEndDate.setDate(daylightSavingsEndDate.getDate() + 1);

            if (date.getTime() >= daylightSavingsStartDate.getTime() && date.getTime() < daylightSavingsEndDate.getTime())
                timeZoneOffset -= 60;

            return timeZoneOffset;

        default:
            alert('Uh oh');
            return null;
    }
}

function hasPassed(timeString, date, timeZone) {

    var dateCopy = new Date(date.getTime());

    var militaryTime = toMilitaryTime(timeString);
    dateCopy.setHours(Math.floor(militaryTime / 100));
    dateCopy.setMinutes(militaryTime % 100);
    dateCopy.setSeconds(0);
    dateCopy.setMilliseconds(0);

    var time = dateCopy.getTime();
    time -= dateCopy.getTimezoneOffset() * 60000;
    time += getTimeZoneOffset(timeZone, dateCopy) * 60000;

    return time < (new Date()).getTime();
}

function inTimeFrame(timeString, timeOfDay) {

    var time = toMilitaryTime(timeString);

    switch(timeOfDay) {
        case 'anytime':
            return true;
        case 'morning':
            return time <= 1200;
        case 'afternoon':
            return time >= 1200 && time <= 1800;
        case 'evening':
            return time >= 1700;
        default:
            alert('inTimeFrame() error: ' + timeOfDay);
            return true;
    }
}

function toDayString(date) {

    switch(date.getDay()) {
        case 0:
            return 'Sunday';
        case 1:
            return 'Monday';
        case 2:
            return 'Tuesday';
        case 3:
            return 'Wednesday';
        case 4:
            return 'Thursday';
        case 5:
            return 'Friday';
        case 6:
            return 'Saturday';
        default:
            alert('Uh oh');
            return null;
    }
}

function toMonthString(date) {

    switch(date.getMonth()) {
        case 0:
            return 'January';
        case 1:
            return 'February';
        case 2:
            return 'March';
        case 3:
            return 'April';
        case 4:
            return 'May';
        case 5:
            return 'June';
        case 6:
            return 'July';
        case 7:
            return 'August';
        case 8:
            return 'September';
        case 9:
            return 'October';
        case 10:
            return 'November';
        case 11:
            return 'December';
        default:
            alert('Uh oh');
            return null;
    }
}





