﻿var GPUI = function() {
    this.version = "1.0.2";
    this.defaultAnimationLength = 300;
    this.showMessageCount = 0;
    this.showAlertCount = 0;
    this.defaultInterval = 10;

    GPAddressParser = function() {
        this.streetSuffixes = {
            "ALLEE": "ALY",
            "ALLEY": "ALY",
            "ALLY": "ALY",
            "ANEX": "ANX",
            "ANNEX": "ANX",
            "ANNX": "ANX",
            "ARCADE": "ARC",
            "AV": "AVE",
            "AVEN": "AVE",
            "AVENU": "AVE",
            "AVENUE": "AVE",
            "AVN": "AVE",
            "AVNUE": "AVE",
            "BAYOO": "BYU",
            "BAYOU": "BYU",
            "BEACH": "BCH",
            "BEND": "BND",
            "BLUF": "BLF",
            "BLUFF": "BLF",
            "BLUFFS": "BLFS",
            "BOT": "BTM",
            "BOTTM": "BTM",
            "BOTTOM": "BTM",
            "BOUL": "BLVD",
            "BOULEVARD": "BLVD",
            "BOULV": "BLVD",
            "BRANCH": "BR",
            "BRDGE": "BRG",
            "BRIDGE": "BRG",
            "BRNCH": "BR",
            "BROOK": "BRK",
            "BROOKS": "BRKS",
            "BURG": "BG",
            "BURGS": "BGS",
            "BYPA": "BYP",
            "BYPAS": "BYP",
            "BYPASS": "BYP",
            "BYPS": "BYP",
            "CAMP": "CP",
            "CANYN": "CYN",
            "CANYON": "CYN",
            "CAPE": "CPE",
            "CAUSEWAY": "CSWY",
            "CAUSWAY": "CSWY",
            "CEN": "CTR",
            "CENT": "CTR",
            "CENTER": "CTR",
            "CENTERS": "CTRS",
            "CENTR": "CTR",
            "CENTRE": "CTR",
            "CIRC": "CIR",
            "CIRCL": "CIR",
            "CIRCLE": "CIR",
            "CIRCLES": "CIRS",
            "CK": "CRK",
            "CLIFF": "CLF",
            "CLIFFS": "CLFS",
            "CLUB": "CLB",
            "CMP": "CP",
            "CNTER": "CTR",
            "CNTR": "CTR",
            "CNYN": "CYN",
            "COMMON": "CMN",
            "CORNER": "COR",
            "CORNERS": "CORS",
            "COURSE": "CRSE",
            "COURT": "CT",
            "COURTS": "CTS",
            "COVE": "CV",
            "COVES": "CVS",
            "CR": "CRK",
            "CRCL": "CIR",
            "CRCLE": "CIR",
            "CRECENT": "CRES",
            "CREEK": "CRK",
            "CRESCENT": "CRES",
            "CRESENT": "CRES",
            "CREST": "CRST",
            "CROSSING": "XING",
            "CROSSROAD": "XRD",
            "CRSCNT": "CRES",
            "CRSENT": "CRES",
            "CRSNT": "CRES",
            "CRSSING": "XING",
            "CRSSNG": "XING",
            "CRT": "CT",
            "CURVE": "CURV",
            "DALE": "DL",
            "DAM": "DM",
            "DIV": "DV",
            "DIVIDE": "DV",
            "DRIV": "DR",
            "DRIVE": "DR",
            "DRIVES": "DRS",
            "DRV": "DR",
            "DVD": "DV",
            "ESTATE": "EST",
            "ESTATES": "ESTS",
            "EXP": "EXPY",
            "EXPR": "EXPY",
            "EXPRESS": "EXPY",
            "EXPRESSWAY": "EXPY",
            "EXPW": "EXPY",
            "EXTENSION": "EXT",
            "EXTENSIONS": "EXTS",
            "EXTN": "EXT",
            "EXTNSN": "EXT",
            "FALLS": "FLS",
            "FERRY": "FRY",
            "FIELD": "FLD",
            "FIELDS": "FLDS",
            "FLAT": "FLT",
            "FLATS": "FLTS",
            "FORD": "FRD",
            "FORDS": "FRDS",
            "FOREST": "FRST",
            "FORESTS": "FRST",
            "FORG": "FRG",
            "FORGE": "FRG",
            "FORGES": "FRGS",
            "FORK": "FRK",
            "FORKS": "FRKS",
            "FORT": "FT",
            "FREEWAY": "FWY",
            "FREEWY": "FWY",
            "FRRY": "FRY",
            "FRT": "FT",
            "FRWAY": "FWY",
            "FRWY": "FWY",
            "GARDEN": "GDN",
            "GARDENS": "GDNS",
            "GARDN": "GDN",
            "GATEWAY": "GTWY",
            "GATEWY": "GTWY",
            "GATWAY": "GTWY",
            "GLEN": "GLN",
            "GLENS": "GLNS",
            "GRDEN": "GDN",
            "GRDN": "GDN",
            "GRDNS": "GDNS",
            "GREEN": "GRN",
            "GREENS": "GRNS",
            "GROV": "GRV",
            "GROVE": "GRV",
            "GROVES": "GRVS",
            "GTWAY": "GTWY",
            "HARB": "HBR",
            "HARBOR": "HBR",
            "HARBORS": "HBRS",
            "HARBR": "HBR",
            "HAVEN": "HVN",
            "HAVN": "HVN",
            "HEIGHT": "HTS",
            "HEIGHTS": "HTS",
            "HGTS": "HTS",
            "HIGHWAY": "HWY",
            "HIGHWY": "HWY",
            "HILL": "HL",
            "HILLS": "HLS",
            "HIWAY": "HWY",
            "HIWY": "HWY",
            "HLLW": "HOLW",
            "HOLLOW": "HOLW",
            "HOLLOWS": "HOLW",
            "HOLWS": "HOLW",
            "HRBOR": "HBR",
            "HT": "HTS",
            "HWAY": "HWY",
            "INLET": "INLT",
            "ISLAND": "IS",
            "ISLANDS": "ISS",
            "ISLES": "ISLE",
            "ISLND": "IS",
            "ISLNDS": "ISS",
            "JCTION": "JCT",
            "JCTN": "JCT",
            "JCTNS": "JCTS",
            "JUNCTION": "JCT",
            "JUNCTIONS": "JCTS",
            "JUNCTN": "JCT",
            "JUNCTON": "JCT",
            "KEY": "KY",
            "KEYS": "KYS",
            "KNOL": "KNL",
            "KNOLL": "KNL",
            "KNOLLS": "KNLS",
            "LA": "LN",
            "LAKE": "LK",
            "LAKES": "LKS",
            "LANDING": "LNDG",
            "LANE": "LN",
            "LANES": "LN",
            "LDGE": "LDG",
            "LIGHT": "LGT",
            "LIGHTS": "LGTS",
            "LNDNG": "LNDG",
            "LOAF": "LF",
            "LOCK": "LCK",
            "LOCKS": "LCKS",
            "LODG": "LDG",
            "LODGE": "LDG",
            "LOOPS": "LOOP",
            "MANOR": "MNR",
            "MANORS": "MNRS",
            "MEADOW": "MDW",
            "MEADOWS": "MDWS",
            "MEDOWS": "MDWS",
            "MILL": "ML",
            "MILLS": "MLS",
            "MISSION": "MSN",
            "MISSN": "MSN",
            "MNT": "MT",
            "MNTAIN": "MTN",
            "MNTN": "MTN",
            "MNTNS": "MTNS",
            "MOTORWAY": "MTWY",
            "MOUNT": "MT",
            "MOUNTAIN": "MTN",
            "MOUNTAINS": "MTNS",
            "MOUNTIN": "MTN",
            "MSSN": "MSN",
            "MTIN": "MTN",
            "NECK": "NCK",
            "ORCHARD": "ORCH",
            "ORCHRD": "ORCH",
            "OVERPASS": "OPAS",
            "OVL": "OVAL",
            "PARKS": "PARK",
            "PARKWAY": "PKWY",
            "PARKWAYS": "PKWY",
            "PARKWY": "PKWY",
            "PASSAGE": "PSGE",
            "PATHS": "PATH",
            "PIKES": "PIKE",
            "PINE": "PNE",
            "PINES": "PNES",
            "PK": "PARK",
            "PKWAY": "PKWY",
            "PKWYS": "PKWY",
            "PKY": "PKWY",
            "PLACE": "PL",
            "PLAIN": "PLN",
            "PLAINES": "PLNS",
            "PLAINS": "PLNS",
            "PLAZA": "PLZ",
            "PLZA": "PLZ",
            "POINT": "PT",
            "POINTS": "PTS",
            "PORT": "PRT",
            "PORTS": "PRTS",
            "PRAIRIE": "PR",
            "PRARIE": "PR",
            "PRK": "PARK",
            "PRR": "PR",
            "RAD": "RADL",
            "RADIAL": "RADL",
            "RADIEL": "RADL",
            "RANCH": "RNCH",
            "RANCHES": "RNCH",
            "RAPID": "RPD",
            "RAPIDS": "RPDS",
            "RDGE": "RDG",
            "REST": "RST",
            "RIDGE": "RDG",
            "RIDGES": "RDGS",
            "RIVER": "RIV",
            "RIVR": "RIV",
            "RNCHS": "RNCH",
            "ROAD": "RD",
            "ROADS": "RDS",
            "ROUTE": "RTE",
            "RVR": "RIV",
            "SHOAL": "SHL",
            "SHOALS": "SHLS",
            "SHOAR": "SHR",
            "SHOARS": "SHRS",
            "SHORE": "SHR",
            "SHORES": "SHRS",
            "SKYWAY": "SKWY",
            "SPNG": "SPG",
            "SPNGS": "SPGS",
            "SPRING": "SPG",
            "SPRINGS": "SPGS",
            "SPRNG": "SPG",
            "SPRNGS": "SPGS",
            "SPURS": "SPUR",
            "SQR": "SQ",
            "SQRE": "SQ",
            "SQRS": "SQS",
            "SQU": "SQ",
            "SQUARE": "SQ",
            "SQUARES": "SQS",
            "STATION": "STA",
            "STATN": "STA",
            "STN": "STA",
            "STR": "ST",
            "STRAV": "STRA",
            "STRAVE": "STRA",
            "STRAVEN": "STRA",
            "STRAVENUE": "STRA",
            "STRAVN": "STRA",
            "STREAM": "STRM",
            "STREET": "ST",
            "STREETS": "STS",
            "STREME": "STRM",
            "STRT": "ST",
            "STRVN": "STRA",
            "STRVNUE": "STRA",
            "SUMIT": "SMT",
            "SUMITT": "SMT",
            "SUMMIT": "SMT",
            "TERR": "TER",
            "TERRACE": "TER",
            "THROUGHWAY": "TRWY",
            "TPK": "TPKE",
            "TR": "TRL",
            "TRACE": "TRCE",
            "TRACES": "TRCE",
            "TRACK": "TRAK",
            "TRACKS": "TRAK",
            "TRAFFICWAY": "TRFY",
            "TRAIL": "TRL",
            "TRAILS": "TRL",
            "TRK": "TRAK",
            "TRKS": "TRAK",
            "TRLS": "TRL",
            "TRNPK": "TPKE",
            "TRPK": "TPKE",
            "TUNEL": "TUNL",
            "TUNLS": "TUNL",
            "TUNNEL": "TUNL",
            "TUNNELS": "TUNL",
            "TUNNL": "TUNL",
            "TURNPIKE": "TPKE",
            "TURNPK": "TPKE",
            "UNDERPASS": "UPAS",
            "UNION": "UN",
            "UNIONS": "UNS",
            "VALLEY": "VLY",
            "VALLEYS": "VLYS",
            "VALLY": "VLY",
            "VDCT": "VIA",
            "VIADCT": "VIA",
            "VIADUCT": "VIA",
            "VIEW": "VW",
            "VIEWS": "VWS",
            "VILL": "VLG",
            "VILLAG": "VLG",
            "VILLAGE": "VLG",
            "VILLAGES": "VLGS",
            "VILLE": "VL",
            "VILLG": "VLG",
            "VILLIAGE": "VLG",
            "VIST": "VIS",
            "VISTA": "VIS",
            "VLLY": "VLY",
            "VST": "VIS",
            "VSTA": "VIS",
            "WALKS": "WALK",
            "WELL": "WL",
            "WELLS": "WLS",
            "WY": "WAY"
        };

        this.states = {
            "ALABAMA": "AL",
            "ALASKA": "AK",
            "AMERICAN SAMOA": "AS",
            "ARIZONA": "AZ",
            "ARKANSAS": "AR",
            "CALIFORNIA": "CA",
            "COLORADO": "CO",
            "CONNECTICUT": "CT",
            "DELAWARE": "DE",
            "DISTRICT OF COLUMBIA": "DC",
            "FEDERATED STATES OF MICRONESIA": "FM",
            "FLORIDA": "FL",
            "GEORGIA": "GA",
            "GUAM": "GU",
            "HAWAII": "HI",
            "IDAHO": "ID",
            "ILLINOIS": "IL",
            "INDIANA": "IN",
            "IOWA": "IA",
            "KANSAS": "KS",
            "KENTUCKY": "KY",
            "LOUISIANA": "LA",
            "MAINE": "ME",
            "MARSHALL ISLANDS": "MH",
            "MARYLAND": "MD",
            "MASSACHUSETTS": "MA",
            "MICHIGAN": "MI",
            "MINNESOTA": "MN",
            "MISSISSIPPI": "MS",
            "MISSOURI": "MO",
            "MONTANA": "MT",
            "NEBRASKA": "NE",
            "NEVADA": "NV",
            "NEW HAMPSHIRE": "NH",
            "NEW JERSEY": "NJ",
            "NEW MEXICO": "NM",
            "NEW YORK": "NY",
            "NORTH CAROLINA": "NC",
            "NORTH DAKOTA": "ND",
            "NORTHERN MARIANA ISLANDS": "MP",
            "OHIO": "OH",
            "OKLAHOMA": "OK",
            "OREGON": "OR",
            "PALAU": "PW",
            "PENNSYLVANIA": "PA",
            "PUERTO RICO": "PR",
            "RHODE ISLAND": "RI",
            "SOUTH CAROLINA": "SC",
            "SOUTH DAKOTA": "SD",
            "TENNESSEE": "TN",
            "TEXAS": "TX",
            "UTAH": "UT",
            "VERMONT": "VT",
            "VIRGIN ISLANDS": "VI",
            "VIRGINIA": "VA",
            "WASHINGTON": "WA",
            "WEST VIRGINIA": "WV",
            "WISCONSIN": "WI",
            "WYOMING": "WY",
            "ARMED FORCES IN EUROPE": "AE",
            "ARMED FORCES IN THE PACIFIC": "AP",
            "ARMED FORCES IN THE AMERICAS": "AA"
        };
    }

    GPAddressParser.prototype.trimEnd = function(input) {
        return input.replace(/[\s\n]+$/, '');
    }

    GPAddressParser.prototype.trimBeginning = function(input) {
        return input.replace(/^[\s\n]+/, '');
    }

    GPAddressParser.prototype.trim = function(input) {
        return input.replace(/^[\s\n]+|[\s\n]+$/, '');
    }

    GPAddressParser.prototype.getStatesRegEx = function() {
        var returnString = "",
            i;

        for (i in this.states) {
            returnString += this.states[i] + "|";
        }

        return returnString.replace(/\|$/, '');
    }

    GPAddressParser.prototype.getStreetSuffixRegEx = function() {
        var returnString = "",
            i;

        for (i in this.streetSuffixes) {
            if (!returnString.match(this.streetSuffixes[i])) {
                returnString += this.streetSuffixes[i] + "|";
            }

            returnString += i + "|";
        }

        return returnString.replace(/\|$/, '');
    }

    GPAddressParser.prototype.parseAddress = function(input) {
        var address = new Object(),
            line1RegEx = "[\\dNSEW]+\\.?\\d*(?:-\\w+)?[^,]*$",
            line2RegEx = "(?!=,)(?:#\\W+\\d+|APA?R?T?M?E?N?T\\W+\\d+|BA?SE?ME?N?T|BU?I?LDI?N?G\\W+\\d+|DEPA?R?T?M?E?N?T\\W+\\d+|FLO?O?R?\\W+\\d+|FRO?NT|HA?NGE?R\\W+\\d+|KEY\\W+\\d+|LO?BBY|LOT\\W+\\d+|LOWE?R|OFF?I?CE?|PE?N?T?HO?U?S?E?|PIER\\W+\\d+|REAR|RO?O?M\\W+\\d+|SIDE|SLIP\W+\\d+|SPA?CE?\\W+\\d+|STOP\\W+\\d+|SU?I?TE\\W+\\d+|TRA?I?LE?R\\W+\\d+|UNIT\\W+\\d+|UPPE?R\\W+)$";

        address.country = "";
        address.name = "";
        address.line1 = "";
        address.line2 = "";
        address.city = "";
        address.state = "";
        address.zip = "";
        /*var lines = input.split("\n");
        if (lines.length == 1) {
            address.name = input;
            return address;
        }*/

        input = input.replace(/,/g, " ").replace(/\./g, "").replace(/\n/g, ",");
        input = this.trimEnd(input.toUpperCase());

        // Get country if zip code is not at the end...
        if (!input.match(/\d{5}(?:-\d{4})?$/)) {
            address.country = input.match(/(?!=,)[\w ]+$/);
            if (!address.country) {
                address.country = "";
            }
            input = this.trimEnd(input.replace(new RegExp(",?\\s*" + address.country + "$"), ""));
        }

        // Get zip code...
        address.zip = input.match(/\d{5}(?:-\d{4})?$/);
        if (!address.zip) {
            address.zip = "";
        }
        input = this.trimEnd(input.replace(new RegExp(",?\\s*" + address.zip + "$"), ""));

        // Get state...
        address.state = input.match("\\b(?:" + this.getStatesRegEx() + ")$");
        if (!address.state) {
            address.state = "";
        }
        input = this.trimEnd(input.replace(new RegExp(",?\\s*" + address.state + "$"), ""));

        // Get city...
        address.city = input.match(/(?!=,)[\w ]+$/);
        if (!address.city) {
            address.city = "";
        }
        input = this.trimEnd(input.replace(new RegExp(",?\\s*" + address.city + "$"), ""));

        // Check for military, rural route, highway contract, or po box addresses..
        if (input.match(/(?:\b(?:(?:UNIT|PSC|CMR)\s+\d*\s+)?(?:[RHP]\.?[RCO]\.?\s+)?(?:\d+\s+)?BOX\s+\b[\d\w-]+\b)|(?:US(?:CGC|S).*)/)) {
            address.line1 = input.match(/(?:\b(?:(?:UNIT|PSC|CMR)\s+\d*\s+)?(?:[RHP]\.?[RCO]\.?\s+)?(?:\d+\s+)?BOX\s+\b[\d\w-]+\b)|(?:US(?:CGC|S).*)/);
            if (!address.line1) {
                address.line1 = "";
            }
            input = this.trimEnd(input.replace(new RegExp(",?\\s*" + address.line1 + "$"), ""));
        } else {
            // Check for address line 2...
            if (input.match(line2RegEx)) {
                address.line2 = input.match(line2RegEx);
                if (!address.line2) {
                    address.line2 = "";
                }
                input = this.trimEnd(input.replace(new RegExp(",?\\s*" + address.line2 + "$"), ""));

                // Check for address line 1...
                address.line1 = input.match(line1RegEx);
                if (!address.line1) {
                    address.line1 = "";
                }
                input = this.trimEnd(input.replace(new RegExp(",?\\s*" + address.line1 + "$"), ""));
            } else {
                // Check for address line 1...
                address.line1 = input.match(line1RegEx);
                if (!address.line1) {
                    address.line1 = "";
                }
                input = this.trimEnd(input.replace(new RegExp(",?\\s*" + address.line1 + "$"), ""));

                if (input.match(line2RegEx)) {
                    address.line2 = input.match(line2RegEx);
                    if (!address.line2) {
                        address.line2 = "";
                    }
                    input = this.trimEnd(input.replace(new RegExp(",?\\s*" + address.line2 + "$"), ""));
                }
            }
        }

        address.name = input;
        if (address.name == "" && address.line1 == "") {
            if (address.city != "") {
                address.name = address.city;
                address.city = "";
                address.line1 = address.country;
                address.country = ""
            }
            else if (address.country != "") {
                address.name = address.country;
                address.country = "";
            }
        }

        return address;
    }

    this.gpAddressParser = new GPAddressParser();
}

GPUI.prototype.trimStart = function(input) {
    return input.replace(/^[\s\n]+/, '');
}

GPUI.prototype.trimEnd = function(input) {
    return input.replace(/[\s\n]+$/, '');
}

GPUI.prototype.trim = function(input) {
    return this.trimEnd(this.trimStart(input));
}

GPUI.prototype.getStyleValue = function(element, style) {
    if (typeof (element) == "string") {
        element = document.getElementById(element);
    }

    var computedStyle = "";

    if (document.defaultView && document.defaultView.getComputedStyle) {
        computedStyle = document.defaultView.getComputedStyle(element, "").getPropertyValue(style);
    } else if (element.currentStyle) {
        style = style.replace(/\-(\w)/g, function(match, p1) { return p1.toUpperCase(); });
        computedStyle = element.currentStyle[style];
    }

    return computedStyle;
};

GPUI.prototype.iterator = function(method, startValue, endValue, callback, animationLength, iterationObject) {
    if (iterationObject && typeof (iterationObject) == "string") {
        iterationObject = document.getElementById(iterationObject);
    }

    if (!iterationObject) {
        iterationObject = document.body;
    }

    if (!animationLength) {
        animationLength = this.defaultAnimationLength;
    }

    if (document.body.iteratorTimer) {
        window.clearInterval(document.body.iteratorTimer);
    }

    var startTime = (new Date()).getTime();
    var valueDelta = endValue - startValue;

    var uiObject = this;

    iterationObject.iteratorTimer = window.setInterval(
        function() {
            var time = (new Date()).getTime();
            var timeDelta = time - startTime;

            if (timeDelta >= animationLength) {
                window.clearInterval(iterationObject.iteratorTimer);

                method(endValue);

                if (callback) {
                    callback();
                }
            } else {
                var newValue = parseInt(uiObject.easeOut(timeDelta, animationLength, valueDelta));

                method(startValue + newValue);
            }
        },
        this.defaultInterval
    );
};

GPUI.prototype.easeOut = function(currentTime, endTime, valueDelta) {
    return -valueDelta * ((currentTime = currentTime / endTime - 1) * currentTime * currentTime * currentTime - 1);
};

GPUI.prototype.showMessage = function(message, messageType, displayTimeInSeconds) {
    var uiObject = this;
    
    if (!messageType || typeof(messageType) != "string") {
        messageType = "information";
    }
    
    if (!displayTimeInSeconds || typeof (displayTimeInSeconds) != "number") {
        displayTimeInSeconds = 10;
    }

    this.showMessageCount++;

    var displayTime = displayTimeInSeconds * 1000,
        windowWidth,
        messageWindow,
        messageBackground,
        messageBody,
        messageWindowHeight,
        messageWindowWidth,
        animationLength = this.defaultAnimationLength;

    if (window.innerHeight) {
        windowWidth = window.innerWidth - 6;
    } else {
        if (document.documentElement && document.documentElement.clientHeight) {
            windowWidth = document.documentElement.clientWidth - 6;
        } else if (document.body) {
            windowWidth = document.body.clientWidth - 6;
        }
    }

    messageWindow = document.createElement("div");
    messageWindow.id = "gpUI_messageWindow";
    messageWindow.style.zIndex = ((this.showMessageCount * 100) + 10001);
    document.forms[0].appendChild(messageWindow);

    messageBackground = document.createElement("div");
    messageBackground.id = "gpUI_messageBackground";
    messageBackground.className = "gpUIMessageWindowBackground";
    messageBackground.style.zIndex = ((this.showMessageCount * 100) + 10000);
    document.forms[0].appendChild(messageBackground);

    if (messageType == "error") {
        messageWindow.className = "gpUIMessageWindowError";
        messageBackground.className = "gpUIMessageWindowBackgroundError";
    } else if (messageType == "success") {
        messageWindow.className = "gpUIMessageWindowSuccess";
        messageBackground.className = "gpUIMessageWindowBackgroundSuccess";
    } else {
        messageWindow.className = "gpUIMessageWindowInformation";
        messageBackground.className = "gpUIMessageWindowBackgroundInformation";
    }

    messageBody = document.createElement("div");
    messageBody.className = "gpUIMessageBody";
    messageBody.innerHTML = message;
    messageWindow.appendChild(messageBody);

    messageWindowWidth = messageWindow.offsetWidth;

    if (messageWindowWidth > windowWidth - 60) {
        messageWindowWidth = windowWidth - 60;
        messageWindow.style.marginLeft = "-" + ((windowWidth - 60) / 2) + "px";
        messageBackground.style.marginLeft = "-" + ((windowWidth - 60) / 2) + "px";
    } else {
        messageWindow.style.marginLeft = "-" + (messageWindowWidth / 2) + "px";
        messageBackground.style.marginLeft = "-" + (messageWindowWidth / 2) + "px";
    }

    messageWindowHeight = messageWindow.offsetHeight;
    messageWindow.style.top = "-" + (messageWindowHeight + 10) + "px";
    messageBackground.style.top = "-" + (messageWindowHeight + 10) + "px";

    messageWindow.style.height = messageWindowHeight + "px";
    messageWindow.style.width = messageWindowWidth + "px";

    messageBackground.style.height = messageWindowHeight + "px";
    messageBackground.style.width = messageWindowWidth + "px";

    messageWindow.style.left = "50%";
    messageBackground.style.left = "50%";

    uiObject.iterator(
        function(currentValue) {
            messageWindow.style.top = currentValue + "px";
            messageBackground.style.top = currentValue + "px";
        },
        0 - messageWindowHeight - 10,
        0,
        function() {
            window.setTimeout(
                function() {
                    uiObject.iterator(
                        function(currentValue) {
                            messageWindow.style.top = currentValue + "px";
                            messageBackground.style.top = currentValue + "px";
                        },
                        0,
                        0 - messageWindowHeight - 10,
                        function() {
                            document.forms[0].removeChild(messageWindow);
                            document.forms[0].removeChild(messageBackground);
                            uiObject.showMessageCount--;
                        },
                        animationLength,
                        messageWindow
                    );
                },
                displayTime
            );
        },
        animationLength,
        messageWindow
    );
}

GPUI.prototype.showAlert = function(message, messageType, buttonClass) {
    if (this.showAlertCount == 0) {
        this.showModalBackground();
    }

    var uiObject = this;
    
    if (!messageType || typeof(messageType) != "string") {
        messageType = "information";
    }
    
    this.showAlertCount++;

    var windowWidth,
        windowHeight,
        messageWindow,
        messageBackground,
        messageBody,
        messageWindowHeight,
        messageWindowWidth,
        animationLength = this.defaultAnimationLength,
        buttonPanel,
        button,
        link;

    if (window.innerHeight) {
        windowWidth = window.innerWidth - 6;
        windowHeight = window.innerHeight - 6;
    } else {
        if (document.documentElement && document.documentElement.clientHeight) {
            windowWidth = document.documentElement.clientWidth - 6;
            windowHeight = document.documentElement.clientHeight - 6;
        } else if (document.body) {
            windowWidth = document.body.clientWidth - 6;
            windowHeight = document.body.clientHeight - 6;
        }
    }

    messageWindow = document.createElement("div");
    messageWindow.id = "gpUI_alertWindow";
    messageWindow.style.zIndex = ((this.showAlertCount * 100) + 10001);
    document.forms[0].appendChild(messageWindow);

    messageBackground = document.createElement("div");
    messageBackground.id = "gpUI_alertBackground";
    messageBackground.className = "gpUIAlertWindowBackground";
    messageBackground.style.zIndex = ((this.showAlertCount * 100) + 10000);
    document.forms[0].appendChild(messageBackground);

    if (messageType == "error") {
        messageWindow.className = "gpUIAlertWindowError";
        messageBackground.className = "gpUIAlertWindowBackgroundError";
    } else if (messageType == "success") {
        messageWindow.className = "gpUIAlertWindowSuccess";
        messageBackground.className = "gpUIAlertWindowBackgroundSuccess";
    } else {
        messageWindow.className = "gpUIAlertWindowInformation";
        messageBackground.className = "gpUIAlertWindowBackgroundInformation";
    }

    messageBody = document.createElement("div");
    messageBody.className = "gpUIAlertBody";
    messageBody.innerHTML = message;
    messageWindow.appendChild(messageBody);

    buttonPanel = document.createElement("div");
    buttonPanel.className = "gpUIAlertWindowButtonPanel";
    messageWindow.appendChild(buttonPanel);
        
    button = document.createElement("div");

    if (buttonClass) {
        button.className = buttonClass + " noFloat";
    } else {
        button.className = "closeButtonSM noFloat";
    }

    button.style.width = "79px";
    button.style.margin = "0 auto";
    buttonPanel.appendChild(button);                

    link = document.createElement("a");
    link.setAttribute("href", "");
    button.appendChild(link);
        
    link.onclick = function() {
        this.blur();
        uiObject.showAlertCount--;
        document.forms[0].removeChild(document.getElementById("gpUI_alertWindow"));
        document.forms[0].removeChild(document.getElementById("gpUI_alertBackground"));
        if (uiObject.showAlertCount == 0) {
            uiObject.hideModalBackground();
        }
        return false;
    }

    messageWindowWidth = messageWindow.offsetWidth;
    
    if (messageWindowWidth < 100) {
        messageWindowWidth = 100;
        messageWindow.style.width = "100px";
        messageBackground.style.width = "100px";
    }

    if (messageWindowWidth > windowWidth - 60) {
        messageWindowWidth = windowWidth - 60;
        messageWindow.style.marginLeft = "-" + ((windowWidth - 60) / 2) + "px";
        messageBackground.style.marginLeft = "-" + ((windowWidth - 60) / 2) + "px";
    } else {
        messageWindow.style.marginLeft = "-" + (messageWindowWidth / 2) + "px";
        messageBackground.style.marginLeft = "-" + (messageWindowWidth / 2) + "px";
    }

    messageWindowHeight = messageWindow.offsetHeight + 30;

    if (messageWindowHeight > windowHeight - 60) {
        messageWindowHeight = windowHeight - 60;
        messageWindow.style.marginTop = "-" + ((windowHeight - 60) / 2) + "px";
        messageBackground.style.marginTop = "-" + ((windowHeight - 60) / 2) + "px";
    } else {
        messageWindow.style.marginTop = "-" + (messageWindowHeight / 2) + "px";
        messageBackground.style.marginTop = "-" + (messageWindowHeight / 2) + "px";
    }

    messageWindow.style.height = messageWindowHeight + "px";
    messageWindow.style.width = messageWindowWidth + "px";

    messageBackground.style.height = messageWindowHeight + "px";
    messageBackground.style.width = messageWindowWidth + "px";

    messageWindow.style.top = "50%";
    messageBackground.style.top = "50%";
    messageWindow.style.left = "50%";
    messageBackground.style.left = "50%";
}

GPUI.prototype.showModalBackground = function(callback, fadeEffect) {
    if (fadeEffect == null) {
        fadeEffect = true;
    }

    var modalBackground = document.createElement("div"),
        scrollTop = 0,
        startTime,
        valueDelta,
        animationLength = this.defaultAnimationLength,
        uiObject = this;

    if (document.documentElement && document.documentElement.scrollTop) {
        scrollTop = document.documentElement.scrollTop;
    }

    if (document.body.scrollTop > scrollTop) {
        scrollTop = document.body.scrollTop;
    }

    modalBackground.id = "gpUI_modalBackground";
    modalBackground.style.position = "absolute";
    modalBackground.style.top = scrollTop + "px";
    modalBackground.style.left = "0px";
    modalBackground.style.zIndex = "100";
    modalBackground.style.margin = "0px";
    modalBackground.style.padding = "0px";
    modalBackground.style.backgroundColor = "#aaa";

    if (fadeEffect) {
        modalBackground.fadeEffect = true;
        modalBackground.style.opacity = "0.00";
        modalBackground.style.filter = "alpha(opacity=00);";
    } else {
        modalBackground.style.opacity = "0.50";
        modalBackground.style.filter = "alpha(opacity=50);";
    }

    document.body.appendChild(modalBackground);

    if (document.documentElement) {
        document.documentElement.style.overflow = "hidden";
    } else if (document.body) {
        document.body.style.overflow = "hidden";
    }

    if (window.innerWidth) {
        modalBackground.style.width = window.innerWidth + "px";
    } else if (document.documentElement.clientWidth && document.documentElement.clientWidth > 0) {
        modalBackground.style.width = document.documentElement.clientWidth + "px";
    } else {
        modalBackground.style.width = document.body.clientWidth + "px";
    }

    if (window.innerHeight) {
        modalBackground.style.height = window.innerHeight + "px";
    } else if (document.documentElement.clientHeight && document.documentElement.clientHeight > 0) {
        modalBackground.style.height = document.documentElement.clientHeight + "px";
    } else {
        modalBackground.style.height = document.body.clientHeight + "px";
    }

    if (fadeEffect) {
        if (modalBackground.fadeTimer) {
            window.clearInterval(modalBackground.fadeTimer);
        }

        startTime = (new Date()).getTime();
        valueDelta = 50;

        modalBackground.fadeTimer = window.setInterval(
            function() {
                var time = (new Date()).getTime(),
                    timeDelta = time - startTime,
                    newValue;

                if (timeDelta >= animationLength) {
                    window.clearInterval(modalBackground.fadeTimer);
                    modalBackground.style.opacity = "0.50";
                    modalBackground.style.filter = "alpha(opacity=50);";

                    if (callback) {
                        callback();
                    }
                } else {
                    newValue = parseInt(uiObject.easeOut(timeDelta, animationLength, valueDelta));

                    modalBackground.style.opacity = newValue / 100;
                    modalBackground.style.filter = "alpha(opacity=" + newValue + ");";
                }
            },
            10
        );
    } else {
        if (callback) {
            callback();
        }
    }

    if (window.addEventListener) {
        window.addEventListener("resize", this.resizeModalBackground, false);
    } else {
        window.attachEvent("onresize", this.resizeModalBackground);
    }
}

GPUI.prototype.hideModalBackground = function(callback) {
    var modalBackground = document.getElementById("gpUI_modalBackground"),
        scrollTop,
        animationLength = this.defaultAnimationLength,
        uiObject = this;

    if (modalBackground) {
        if (modalBackground.fadeEffect) {
            if (modalBackground.fadeTimer) {
                window.clearInterval(modalBackground.fadeTimer);
            }

            var startTime = (new Date()).getTime(),
                valueDelta = -50;

            modalBackground.fadeTimer = window.setInterval(
                function() {
                    var time = (new Date()).getTime(),
                        timeDelta = time - startTime,
                        newValue;

                    if (timeDelta >= animationLength) {
                        window.clearInterval(modalBackground.fadeTimer);

                        modalBackground.style.opacity = "0.00";
                        modalBackground.style.filter = "alpha(opacity=00);";

                        modalBackground.style.width = 0;
                        modalBackground.style.height = 0;

                        if (document.documentElement) {
                            document.documentElement.style.overflow = "auto";
                        }

                        document.body.style.overflow = "auto";

                        scrollTop = 0;

                        if (document.documentElement && document.documentElement.scrollTop) {
                            scrollTop = document.documentElement.scrollTop;
                        }

                        if (document.body.scrollTop > scrollTop) {
                            scrollTop = document.body.scrollTop;
                        }

                        document.body.scrollTop = scrollTop + "px";

                        document.body.removeChild(modalBackground);

                        if (callback) {
                            callback();
                        }
                    } else {
                        newValue = 50 + parseInt(uiObject.easeOut(timeDelta, animationLength, valueDelta));

                        modalBackground.style.opacity = newValue / 100;
                        modalBackground.style.filter = "alpha(opacity=" + newValue + ");";
                    }
                },
                10
            );
        } else {
            modalBackground.style.width = 0;
            modalBackground.style.height = 0;

            if (document.documentElement) {
                document.documentElement.style.overflow = "auto";
            }

            document.body.style.overflow = "auto";

            scrollTop = 0;

            if (document.documentElement && document.documentElement.scrollTop) {
                scrollTop = document.documentElement.scrollTop;
            }

            if (document.body.scrollTop > scrollTop) {
                scrollTop = document.body.scrollTop;
            }

            document.body.scrollTop = scrollTop + "px";

            document.body.removeChild(modalBackground);

            if (callback) {
                callback();
            }
        }
    }

    if (window.removeEventListener) {
        window.removeEventListener("resize", this.resizeModalBackground, false);
    } else {
        window.detachEvent("onresize", this.resizeModalBackground);
    }
}

GPUI.prototype.resizeModalBackground = function() {
    var modalBackground = document.getElementById("gpUI_modalBackground");

    if (modalBackground) {
        if (window.innerWidth) {
            modalBackground.style.width = window.innerWidth + "px";
        } else if (document.documentElement.clientWidth && document.documentElement.clientWidth > 0) {
            modalBackground.style.width = document.documentElement.clientWidth + "px";
        } else {
            modalBackground.style.width = document.body.clientWidth + "px";
        }

        if (window.innerHeight) {
            modalBackground.style.height = window.innerHeight + "px";
        } else if (document.documentElement.clientHeight && document.documentElement.clientHeight > 0) {
            modalBackground.style.height = document.documentElement.clientHeight + "px";
        } else {
            modalBackground.style.height = document.body.clientHeight + "px";
        }
    }
}

GPUI.prototype.showWorkingMessage = function(message) {
    var workingPanel = document.createElement("div"),
        workingImage = document.createElement("img"),
        workingMessage;

    this.showModalBackground();

    document.body.appendChild(workingPanel);
    workingPanel.id = "gpUI_workingPanel";
    workingPanel.className = "rounded shadowed";
    workingPanel.style.position = "absolute";
    workingPanel.style.textAlign = "center";
    workingPanel.style.zIndex = "1100";
    workingPanel.style.top = "50%";
    workingPanel.style.left = "50%";
    workingPanel.style.height = "100px";
    workingPanel.style.lineHeight = "12px";
    workingPanel.style.width = "100px";
    workingPanel.style.background = "#fbfdff";
    workingPanel.style.border = "solid 1px #9cd4f9";
    workingPanel.style.color = "#20526e";
    workingPanel.style.opacity = "0.9";
    workingPanel.style.filter = "alpha(opacity=90), progid:DXImageTransform.Microsoft.dropShadow(color=#22000000, offX=5, offY=5,  positive=true)";
    workingPanel.style.margin = "-50px 0 0 -50px";

    workingPanel.appendChild(workingImage);
    workingImage.src = "images3/workingModal.gif";
    workingImage.alt = "Working...";
    workingImage.title = "Working...";
    workingImage.style.verticalAlign = "middle";
    workingImage.style.marginTop = (50 - (workingImage.offsetHeight / 2) - 6) + "px";

    if (message) {
        workingMessage = document.createElement("span");
        workingPanel.appendChild(workingMessage);
        workingMessage.innerHTML = "<br />" + message;
    }
}

GPUI.prototype.hideWorkingMessage = function() {
    var workingPanel = document.getElementById("gpUI_workingPanel");

    this.hideModalBackground();

    document.body.removeChild(workingPanel);
}

GPUI.prototype.showWorkingPanel = function(obj, message) {
    if (typeof (obj) == "string") {
        obj = document.getElementById(obj);
    }

    var workingBackground = document.createElement("div"),
        workingPanel = document.createElement("div"),
        workingImage = document.createElement("img"),
        workingMessage;

    document.body.appendChild(workingBackground);
    workingBackground.id = "gpUI_workingBackground_" + obj.id;
    workingBackground.style.position = "absolute";
    workingBackground.style.textAlign = "center";
    workingBackground.style.backgroundColor = "#fff";
    workingBackground.style.zIndex = "1000";
    workingBackground.opacity = "0.5";
    workingBackground.style.filter = "alpha(opacity=50)";
    workingBackground.style.top = obj.offsetTop + "px";
    workingBackground.style.left = obj.offsetLeft + "px";
    workingBackground.style.height = obj.offsetHeight + "px";
    workingBackground.style.width = obj.offsetWidth + "px";

    document.body.appendChild(workingPanel);
    workingPanel.id = "gpUI_workingPanel_" + obj.id;
    workingPanel.style.position = "absolute";
    workingPanel.style.textAlign = "center";
    workingPanel.style.zIndex = "1100";
    workingPanel.style.top = obj.offsetTop + "px";
    workingPanel.style.left = obj.offsetLeft + "px";
    workingPanel.style.height = obj.offsetHeight + "px";
    workingPanel.style.lineHeight = "12px";
    workingPanel.style.width = obj.offsetWidth + "px";

    workingPanel.appendChild(workingImage);
    workingImage.src = "images3/workingModal.gif";
    workingImage.alt = "Working...";
    workingImage.title = "Working...";
    workingImage.style.verticalAlign = "middle";
    workingImage.style.marginTop = ((obj.offsetHeight / 2) - (workingImage.offsetHeight / 2) - 6) + "px";

    if (message) {
        workingMessage = document.createElement("span");
        workingPanel.appendChild(workingMessage);
        workingMessage.innerHTML = "<br />" + message;
    }
}

GPUI.prototype.hideWorkingPanel = function(obj) {
    if (typeof (obj) == "string") {
        obj = document.getElementById(obj);
    }

    var workingBackground = document.getElementById("gpUI_workingBackground_" + obj.id),
        workingPanel = document.getElementById("gpUI_workingPanel_" + obj.id);

    document.body.removeChild(workingBackground);
    document.body.removeChild(workingPanel);
}

// Returns "illegal", "weak", "medium", or "strong"...
GPUI.prototype.evaluatePassword = function(password) {
    var lower = "abcdefghijklmnopqrstuvwxyz",
        number = "0123456789",
        upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
        symbol = "!!#$%&,.:-;?@[]^ˆ_{|}~¡¡¦¦¨¨¯¯¸¸¿¿‚„‹››+<=>±±««»»××÷÷¢¢££¤¤¥¥§§©©¬¬®®°°µµ†‡•…‰€¼¼½½¾¾¹¹²²³³ªªÁáÀàÂâÄäÃãÅåÆæÇçÐðÉéÈèÊêËëƒÍíÌìÎîÏïÑñººÓóÒòÔôÖöÕõØøŒœŠšßÞþ™ÚúÙùÛûÜüÝýŸÿŽž",
        illegal = "()*'`´‘’“\"”¶·/\\",
        hasLower = false,
        hasNumber = false,
        hasUpper = false,
        hasSymbol = false,
        hasIllegal = false,
        score = 0,
        character,
        i,
        length;

    if ((password * 1) == password) {
        return "weak";
    } 

    for (i = 0, length = password.length; i < length; i++) {
        if (hasLower && hasNumber && hasSymbol && hasUpper || hasIllegal) {
            break;
        }
    
        character = password.charAt(i);

        if (!hasIllegal) {
            hasIllegal = illegal.indexOf(character) > -1;
        }
        
        if (!hasLower) {
            hasLower = lower.indexOf(character) > -1;
        }

        if (!hasNumber) {
            hasNumber = number.indexOf(character) > -1;
        }
        
        if (!hasSymbol) {
            hasSymbol = symbol.indexOf(character) > -1;
        }

        if (!hasUpper) {
            hasUpper = upper.indexOf(character) > -1;
        }
    }
    
    if (hasIllegal) {
        return "illegal";
    }

    if (password.length < 4) {
        return "weak";
    }
    
    if (hasLower) {
        score++;
    }
    
    if (hasNumber) {
        score++;
    }
    
    if (hasSymbol) {
        score++;
    }
    
    if (hasUpper) {
        score++;
    }
    
    if (password.length >= 8) {
        score++;
    }
    
    switch (score) {
        case 0:
        case 1:
        case 2:
            return "weak";
            break;
        case 3:
            return "medium";
            break;
        case 4:
        case 5:
            return "strong";
            break;
    }
}

GPUI.prototype.getElementPosition = function(element, edge) {
    if (typeof(element) == "string") {
        element = document.getElementById(element);
    }
    
    if (element == null) {
        return;
    }

    var currentPosition = 0;

    switch (edge) {
        case "right":
            currentPosition += element.offsetWidth;
            break;
        case "bottom":
            currentPosition += element.offsetHeight;
            break;
    }
    
    if (element.offsetParent) {
        while (true) {
            switch (edge) {
                case "top":
                    currentPosition += element.offsetTop;
                    break;
                case "right":
                    currentPosition += element.offsetLeft;
                    break;
                case "bottom":
                    currentPosition += element.offsetTop;
                    break;
                case "left":
                    currentPosition += element.offsetLeft;
                    break;
            }

            if (!element.offsetParent) {
                break;
            }
            
            element = element.offsetParent;
        }
    } else {
        switch (edge) {
            case "top":
                if (element.y) {
                    currentPosition += element.y;
                }
                break;
            case "right":
                if (element.x) {
                    currentPosition += element.x;
                }
                break;
            case "bottom":
                if (element.y) {
                    currentPosition += element.y;
                }
                break;
            case "left":
                if (element.x) {
                    currentPosition += element.x;
                }
                break;
        }
    }

    return currentPosition;
}

GPUI.prototype.getElementTop = function(element) {
    return this.getElementPosition(element, "top");
}

GPUI.prototype.getElementRight = function(element) {
    return this.getElementPosition(element, "right");
}

GPUI.prototype.getElementBottom = function(element) {
    return this.getElementPosition(element, "bottom");
}

GPUI.prototype.getElementLeft = function(element) {
    return this.getElementPosition(element, "left");
}

GPUI.prototype.isValidEmail = function(email) {
    if (email == "") {
        return true;
    } else {
        return email.match(/^[a-zA-Z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/) != null;
    }
}

GPUI.prototype.contains = function(array, obj) {
    for (var i = 0, length = array.length; i < length; i++) {
        if (array[i] === obj) {
            return i;
        }
    }
    
    return -1;
}

var gpUI = new GPUI();