﻿// object for displaying MapTips
geodata.maptips.MapTipsLayer = function (map) {
    this.id = "GDMapTips";
    this.overlapGridCellWidth = 60;
    this.overlapGridCellHeight = 60;
    this.alwaysShowWeatherWithPriorityLowerThan = 24;
    this.containerId = null;
    this.map = map;
    this.enabled = true;
    this.mapTipItems = [];
    this.weatherItems = [];
    this.skiResorts = [];
    this.iconFont = new esri.symbol.Font("10px",
	    esri.symbol.Font.STYLE_NORMAL,
	    esri.symbol.Font.VARIANT_NORMAL,
	    esri.symbol.Font.WEIGHT_NORMAL,
	    "Verdana");
    this.iconFontHalo = new esri.symbol.Font("10px",
	    esri.symbol.Font.STYLE_NORMAL,
	    esri.symbol.Font.VARIANT_NORMAL,
	    esri.symbol.Font.WEIGHT_NORMAL,
	    "Verdana");
    this.iconFontLight = new esri.symbol.Font("10px",
	    esri.symbol.Font.STYLE_NORMAL,
	    esri.symbol.Font.VARIANT_NORMAL,
	    esri.symbol.Font.WEIGHT_NORMAL,
	    "Verdana");

    this.iconTextColor = new dojo.Color([255, 255, 255]);
    this.iconClosedTextColor = new dojo.Color([255, 255, 255]);
    this.operaTextColor = new dojo.Color([32, 197, 237]);
    this.temperatureTextColor = new dojo.Color("#575859");
    this.selectedMapTipItem = null;
    this.weatherInfoTemplate = null;
    this.snowInfoTemplate = null;
    this.snowInfoGroupTemplate = null;

    this.setupInfoWindow = function () {
        var heading = gdGetText("/map/weather/weatherheading");
        var snowHeading = gdGetText("/snowreport/snowreportheader");
        var snowDepthCm = gdGetText("/snowreport/snowdepthcm").replace(/\{0\}/g, "#{SnowDepth}").replace(/\#/g, "$");
        var snowDepthIn = gdGetText("/snowreport/snowdepthin").replace(/\{0\}/g, "#{SnowDepth}").replace(/\#/g, "$");
        var openSlopes = gdGetText("/snowreport/openslopes").replace(/\{0\}/g, "#{SlopesOpen}").replace(/\{1\}/g, "#{SlopesTotal}").replace(/\#/g, "$");
        var openLifts = gdGetText("/snowreport/openlifts").replace(/\{0\}/g, "#{LiftsOpen}").replace(/\{1\}/g, "#{LiftsTotal}").replace(/\#/g, "$");
        var snowLinktext = gdGetText("/snowreport/detailedsnowreport");
        var snowTooltip = gdGetTooltip("/snowreport/detailedsnowreport").replace(/\{0\}/g, "#{Name}").replace(/\#/g, "$");
        var snowDepthTooltip = gdGetTooltip("/snowreport/snowdepthinfo");
        var lastUpdated = gdGetText("/snowreport/lastupdated");
        var tooltip = gdGetTooltip("/weather/detailedforecast").replace(/\{0\}/g, "#{LocationName}").replace(/\#/g, "$");
        var linktext = gdGetText("/weather/detailedforecast");

        this.weatherInfoTemplate = new esri.InfoTemplate(
            "<div class=\"c_map_weatherheading\">" + heading + "</div>" +
            "<div class=\"c_map_weatherlocation\">${LocationName}</div>",
            "<div class=\"c_map_weatherforecast\">" +
            "  <div class=\"c_map_forecast_container\">${forecastHtml}</div> " +
            "  <div class=\"c_map_detailedforecast\">" +
            "    <a title=\"" + tooltip + "\" target=\"_blank\" href=\"${yrUrl}\"><img title=\"" + tooltip + "\" alt=\"\" src=\"/images/icons/vn_external_gray.png\" class=\"leftfloating noborder\"/><span>" + linktext + "</span></a>" +
            "  </div>" +
            "</div>");
        this.snowInfoTemplate = new esri.InfoTemplate(
            "<div class=\"c_mapsnowreport\">" +
            "<div class=\"c_map_weatherheading\">" + snowHeading + "</div>" +
            "<div class=\"c_snowreportheader\"><span>${Name}</span></div>" +
            "<div class=\"${ClosedCssClass} c_snowreportclosed\"><span>${ClosedText}</span></div>" +
            "<div class=\"c_snowreportupdated\"><span class=\"bold\">" + lastUpdated + "</span><span>${GlobalLatestDateFormatted}</span></div>" +
            "</div>",
            "<div class=\"c_mapsnowreport\">" +
            "<div class=\"c_snowreportdetails\"><span>" + (gdClientData.languageCode.toLowerCase() == "en-us" ? snowDepthIn : snowDepthCm) +
            "<img class=\"depthinfoicon\" title=\"" + snowDepthTooltip + "\" alt=\"" + snowDepthTooltip + "\" src=\"/images/icons/snowreport/vn_depth_info.png\"/></span>" +
            "<span>" + openSlopes + "</span>" +
            "<span>" + openLifts + "</span></div>" +
            "<div class=\"c_snowreportexternal\">" +
            "<a href=\"${Url}\" title=\"" + snowTooltip + "\">" +
            "<img class=\"leftfloating noborder\" src=\"/images/icons/vn_external_gray.png\" alt=\"\" title=\"\" />" +
            "<span>" + snowLinktext + "</span></a>" +
            "</div>" +
            "</div>");
        this.snowInfoGroupTemplate = new esri.InfoTemplate(
            "<div class=\"c_mapsnowreport\"><div class=\"c_map_weatherheading\">" + snowHeading + "</div></div>",
            "<div class=\"c_mapsnowreport\"><div class=\"c_snowreportlist\">${html}</div></div>");
        this.map.infoWindow.resize(210, 247);
        dojo.connect(this.map.infoWindow, "onShow", this, function () {
            var infoLayer = this.map.infoWindow.domNode; //dojo.byId("gdMapDiv_infowindow");
            infoLayer.style.cssText = ("" + infoLayer.style.cssText).replace("z-index: 40;", "z-index: 40000;");
            if (this.map.infoWindow.anchor == esri.dijit.InfoWindow.ANCHOR_UPPERRIGHT || this.map.infoWindow.anchor == esri.dijit.InfoWindow.ANCHOR_UPPERLEFT) {
                //dojo.style(this.map.infoWindow._window, "top", "20px");
                //dojo.style(this.map.infoWindow._pointer, "top", "200px");
            }
            else {
                dojo.style(this.map.infoWindow._window, "top", "20px");
            }
        });
        dojo.connect(this.map.infoWindow, "onHide", this, function () {
            var infoLayer = dojo.byId("gdMapDiv_infowindow");
            infoLayer.style.cssText = "display: none;z-index: 40;";
        });
    }

    this.getWeatherForecastText = function (wdi) {
        var symbolNumber = 0;
        if (wdi.SymbolNumber > 0 && wdi.SymbolNumber < 16) {
            symbolNumber = wdi.SymbolNumber;
        }
        else if (wdi.SymbolNumber == 16) {
            symbolNumber = 1;
        }
        else if (wdi.SymbolNumber == 17) {
            symbolNumber = 3;
        }
        else if (wdi.SymbolNumber == 18) {
            symbolNumber = 5;
        }
        else if (wdi.SymbolNumber == 19) {
            symbolNumber = 8;
        }
        var retVal = gdGetText("/weather/weather" + symbolNumber);
        if (wdi.WindSpeed > 0) {
            retVal += ", " + gdGetText("/weather/wind" + this.getWindSpeedId(wdi.WindSpeed));
        }
        return retVal;
    }

    this.getWindSpeedId = function (ws) {
        var retVal;
        if (ws < 0.3)
            retVal = 1;
        else if (ws < 1.6)
            retVal = 2;
        else if (ws < 3.4)
            retVal = 3;
        else if (ws < 5.5)
            retVal = 4;
        else if (ws < 8.0)
            retVal = 5;
        else if (ws < 10.8)
            retVal = 6;
        else if (ws < 13.9)
            retVal = 7;
        else if (ws < 17.2)
            retVal = 8;
        else if (ws < 20.8)
            retVal = 9;
        else if (ws < 24.5)
            retVal = 10;
        else if (ws < 28.5)
            retVal = 11;
        else if (ws < 32.6)
            retVal = 12;
        else
            retVal = 13;
        return retVal;
    }

    this.addOperaWorkaround = function (item) {
        var padLen = Math.ceil(item.icon.defaultIcon.width / 10);
        if (padLen < 1) padLen = 1;
        var text = "_";
        while (--padLen > 0) text = text + "_";
        var g = new esri.geometry.Point(item.X, item.Y, null);
        var s = new esri.symbol.TextSymbol(text, this.iconFont, this.operaTextColor);
        s.setAlign(esri.symbol.TextSymbol.ALIGN_MIDDLE);
        s.setOffset(0, 0);
        var gr = new esri.Graphic(g, s, { index: item.index, selected: item.selected }, null);
        this.map.graphics.add(gr);
    }

    this.addOperaWorkaroundWeather = function (gr) {
        var s = new esri.symbol.TextSymbol("____", this.iconFont, this.operaTextColor);
        s.setAlign(esri.symbol.TextSymbol.ALIGN_MIDDLE);
        s.setOffset(0, 0);
        this.map.graphics.add(new esri.Graphic(gr.geometry, s, gr.attributes, this.weatherInfoTemplate));
        this.map.graphics.add(new esri.Graphic(gr.geometry, gr.symbol, {}, null));
    }

    this.addMapTipImage = function (item) {
        var g = new esri.geometry.Point(item.X, item.Y, null);
        var s = new esri.symbol.PictureMarkerSymbol(item.icon.defaultIcon.url, item.icon.defaultIcon.width, item.icon.defaultIcon.height);
        //var s = new esri.symbol.SimpleMarkerSymbol(esri.symbol.SimpleMarkerSymbol.STYLE_DIAMOND, 20, new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new dojo.Color([0,0,0]), 1), new dojo.Color([255,255,0,0.5]));
        var gr = new esri.Graphic(g, s, { index: item.index, selected: item.selected }, null);
        this.map.graphics.add(gr);
    }

    this.addMapTipText = function (item) {
        var text = item.iconHtml;
        if (text != null) {
            text = text.replace("&nbsp;&nbsp;", "");
            if (text != "") {
                var g = new esri.geometry.Point(item.X, item.Y, null);
                var s = new esri.symbol.TextSymbol(text, this.iconFont, this.iconTextColor);
                s.setAlign(esri.symbol.TextSymbol.ALIGN_MIDDLE);
                if (dojo.isIE)
                    s.setOffset(4, 3);
                else
                    s.setOffset(4, 1);
                var gr = new esri.Graphic(g, s, { index: item.index, selected: item.selected }, null);
                this.map.graphics.add(gr);
            }
        }
    }

    this.addMapTips = function (items, selectedItem) {
        this.hideCurrentItem();
        this.mapTipItems = items;
        this.selectedMapTipItem = selectedItem;
        this.updateGraphics();
    }

    this.updateGraphics = function () {
        this.map.graphics.clear();
        var previousId = null;
        var overlapGrid = [];
        var ogw = Math.ceil(this.map.width / this.overlapGridCellWidth) + 2;
        var ogh = Math.ceil(this.map.height / this.overlapGridCellHeight) + 2;
        for (var x = 0; x < ogw; x++) {
            overlapGrid[x] = [];
            for (var y = 0; y < ogh; y++) {
                overlapGrid[x][y] = false;
            }
        }

        dojo.forEach(this.mapTipItems, function (item) { item.selected = false; });
        if (dojo.isOpera) {
            // Mouseover doesn't work for picturemarkers in Opera, so we add a text symbol
            // to cover the picture marker and give us the mouseover effect.
            dojo.forEach(this.mapTipItems, this.addOperaWorkaround, this);
        }
        dojo.forEach(this.mapTipItems, this.addMapTipImage, this);
        dojo.forEach(this.mapTipItems, this.addMapTipText, this);
        if (this.selectedMapTipItem) {
            this.selectedMapTipItem.selected = true;
            if (dojo.isOpera) this.addOperaWorkaround(this.selectedMapTipItem);
            this.addMapTipImage(this.selectedMapTipItem);
            this.addMapTipText(this.selectedMapTipItem);
        }
        this.map.graphics.enableMouseEvents();


        dojo.forEach(this.weatherItems, function (item) {
            var forecastHtml = "";
            var count = 0;
            var currentTime = new Date();
            var symbolFc = null;

            dojo.forEach(item.forecasts, function (fc) {
                if (count < 4 && fc.Period == 2) {
                    var d = this.parseDate(fc.From);
                    if (currentTime.getFullYear() < d.getFullYear() || currentTime.getMonth() < d.getMonth() || currentTime.getDate() < d.getDate()) {
                        if (symbolFc == null) symbolFc = fc;
                        forecastHtml += this.createForecastHtml(fc, d);
                        count++;
                    }
                }
            }, this);
            if (symbolFc != null) {
                var g = new esri.geometry.Point(item.Longitude, item.Latitude, null);
                var s = new esri.symbol.PictureMarkerSymbol(this.getSymbolUrl(symbolFc, true), 43, 43);
                var gr = new esri.Graphic(g, s, { LocationName: item.LocationName, forecastHtml: forecastHtml, yrUrl: this.getYrUrl(item) }, this.weatherInfoTemplate);
                var sp = this.map.toScreen(gr.geometry);
                var x = Math.floor(sp.x / this.overlapGridCellWidth);
                var y = Math.floor(sp.y / this.overlapGridCellHeight);
                if (this.checkOverlap(x, y, overlapGrid, item.Priority)) {
                    if (dojo.isOpera) {
                        // Mouseover doesn't work for picturemarkers in Opera, so we add a text symbol
                        // to cover the picture marker and give us the mouseover effect.
                        this.addOperaWorkaroundWeather(gr);
                    }
                    else {
                        this.map.graphics.add(gr);
                    }
                    this.addTemperatureSymbol(g, item, forecastHtml, symbolFc);
                }
            }
        }, this);

        // Initialize all ski resorts
        dojo.forEach(this.skiResorts, function (item) {
            item.mapPoint = new esri.geometry.Point(item.UTMX, item.UTMY, null);
            item.screenPoint = this.map.toScreen(item.mapPoint);
            item.groupPoint = null;
            item.groupScreenPoint = null;
            item.groupedResorts = [];
        }, this);

        // Group overlapping ski resorts into groups
        var groupedResorts = [];
        dojo.forEach(this.skiResorts, function (item) {
            var grouped = false;
            dojo.forEach(groupedResorts, function (resort) {
                if (!grouped && Math.abs(item.screenPoint.x - resort.groupScreenPoint.x) < 100 && Math.abs(item.screenPoint.y - resort.groupScreenPoint.y) < 35) {
                    // Resort overlaps with previously added group, add the resort to this group.
                    grouped = true;
                    var c = resort.groupedResorts.length;
                    resort.groupedResorts.push(item);
                    // Adjust screen and map coordinates of group to allow for the new member of the group
                    resort.groupPoint = new esri.geometry.Point((resort.groupPoint.x * c + item.mapPoint.x) / (c + 1), (resort.groupPoint.y * c + item.mapPoint.y) / (c + 1), null);
                    resort.groupScreenPoint = new esri.geometry.Point((resort.groupScreenPoint.x * c + item.screenPoint.x) / (c + 1), (resort.groupScreenPoint.y * c + item.screenPoint.y) / (c + 1), null);
                }
            }, this);
            if (!grouped) {
                item.groupedResorts.push(item); // Add resort to its own group
                item.groupScreenPoint = item.screenPoint;
                item.groupPoint = item.mapPoint;
                groupedResorts.push(item);
            }
        }, this);

        // Merge overlapping groups
        var goAgain = true;
        while (goAgain) {
            var newGrouping = [];
            dojo.forEach(groupedResorts, function (item) {
                var grouped = false;
                dojo.forEach(newGrouping, function (group) {
                    if (!grouped && Math.abs(item.groupScreenPoint.x - group.groupScreenPoint.x) < 100 && Math.abs(item.groupScreenPoint.y - group.groupScreenPoint.y) < 35) {
                        // Group overlaps with previously added group, join the two groups.
                        grouped = true;
                        var c1 = item.groupedResorts.length;
                        var c2 = group.groupedResorts.length;
                        dojo.forEach(item.groupedResorts, function (subItem) {
                            group.groupedResorts.push(subItem);
                        }, this);
                        item.groupedResorts = [];
                        // Adjust screen and map coordinates of group to allow for the new members of the group
                        group.groupPoint = new esri.geometry.Point((group.groupPoint.x * c2 + item.groupPoint.x * c1) / (c1 + c2), (group.groupPoint.y * c2 + item.groupPoint.y * c1) / (c1 + c2), null);
                        group.groupScreenPoint = new esri.geometry.Point((group.groupScreenPoint.x * c2 + item.groupScreenPoint.x * c1) / (c1 + c2), (group.groupScreenPoint.y * c2 + item.screenPoint.y * c1) / (c1 + c2), null);
                    }
                }, this);
                if (!grouped) {
                    newGrouping.push(item);
                }
            }, this);
            if (groupedResorts.length == newGrouping.length)
                goAgain = false;
            groupedResorts = newGrouping;
        }

        // Add the groups to the map
        dojo.forEach(groupedResorts, function (item) {
            if (item.groupedResorts && item.groupedResorts.length > 1) {
                this.addSkiResortGroup(item);
            }
            else {
                this.addSkiResortIcon(item.mapPoint, item.SnowDepthObject, item, this.snowInfoTemplate, this.isSkiResortClosed(item), 1);
            }
        }, this);

    }

    this.addSkiResortIcon = function (mapPoint, snowDepth, dataItem, infoTemplate, closed, count) {

        var icon = "/images/map/snowinfo/snowinfo_alpine";
        var w = 0;
        var h = 0;
        if (closed) {
            w = 74 + count * 2;
            h = 29 + count * 2;
            icon += "_closed";
        }
        else if (snowDepth.depth > 99) {
            w = 93 + count * 2;
            h = 30 + count * 2;
            icon += "_large";
        }
        else {
            w = 86 + count * 2;
            h = 30 + count * 2;
            icon += "_small";
        }
        if (count > 1) {
            icon += "_stack" + count;
        }
        icon += ".png";

        var s = new esri.symbol.PictureMarkerSymbol(icon, w, h);
        var gr = new esri.Graphic(mapPoint, s, dataItem, infoTemplate);
        this.map.graphics.add(gr);
        var ts = null;
        if (closed) {
            ts = new esri.symbol.TextSymbol(gdGetText("/snowreport/map/closed"), this.iconFont, this.iconClosedTextColor);
            ts.setOffset(-12 - count / 2, count / 2);
        }
        else {
            ts = new esri.symbol.TextSymbol(snowDepth.text, this.iconFont, this.iconTextColor);
            ts.setOffset(-2 - count / 2, -5 + count);
        }
        ts.setAlign(esri.symbol.TextSymbol.ALIGN_START);
        var tgr = new esri.Graphic(mapPoint, ts, dataItem, infoTemplate);
        this.map.graphics.add(tgr);
    }

    this.getSkiResortClosedStatus = function (item) {
        if (item.IsClosed) {
            item.ClosedCssClass = "c_snowreportclosed_closed";
            item.ClosedText = gdGetText("/snowreport/map/closed");
        }
        else if (item.IsClosedEndSeason) {
            item.ClosedCssClass = "c_snowreportclosed_closed";
            item.ClosedText = gdGetText("/snowreport/map/closedendofseason");
        }
        else if (item.IsClosedTooCold || item.IsClosedTooWindy) {
            item.ClosedCssClass = "c_snowreportclosed_closed";
            item.ClosedText = gdGetText("/snowreport/map/closedbadweather");
        }
        else if (item.IsOnlyWeekends) {
            item.ClosedCssClass = "c_snowreportclosed_onlyweekends";
            item.ClosedText = gdGetText("/snowreport/map/weekendsonly");
        }
        else {
            item.ClosedCssClass = "c_snowreportclosed_open";
            item.ClosedText = "";
        }
    }

    this.addSkiResortGroup = function (item) {
        var closed = true;
        var count = 0;
        var maxSnowDepth = 0;
        dojo.forEach(item.groupedResorts, function (subItem) {
            count++;
            if (!this.isSkiResortClosed(subItem)) {
                closed = false;
                if (subItem.TopSnowTerrainCm > maxSnowDepth)
                    maxSnowDepth = subItem.TopSnowTerrainCm;
            }
        }, this);
        if (count > 5) count = 5;
        var d = this.getSnowDepth(maxSnowDepth);
        var dataItem = this.createGroupedResortDataItem(item);
        this.addSkiResortIcon(item.groupPoint, d, dataItem, this.snowInfoGroupTemplate, closed, count);
    }

    this.isSkiResortClosed = function (skiResort) {
        return (skiResort.IsClosed || skiResort.IsClosedEndSeason || skiResort.IsClosedTooWindy || skiResort.IsClosedTooCold);
    }

    this.createGroupedResortDataItem = function (resort) {
        var dataItem = { html: "", groupedResorts: resort.groupedResorts };
        var count = 0;
        dojo.forEach(resort.groupedResorts, function (item) {
            item.sortValue = this.isSkiResortClosed(item) ? 0 : 10000;
            item.sortValue += item.TopSnowTerrainCm;
        }, this);
        resort.groupedResorts = resort.groupedResorts.sort(function (r1, r2) {
            return r2.sortValue - r1.sortValue;
        });
        dojo.forEach(resort.groupedResorts, function (item) {
            count++;
            if (count <= gdClientData.maxSkiResortsInList) {
                var tooltip = gdGetTooltip("/snowreport/map/zoomtoresort").replace(/\{0\}/g, item.Name);
                dataItem.html += "<div class=\"map_skiresort\" title=\"" + tooltip + "\" onmouseover=\"dojo.addClass(this, 'map_skiresort_hover')\" onmouseout=\"dojo.removeClass(this, 'map_skiresort_hover')\" onclick=\"gdZoomToPoint(" + item.UTMX + "," + item.UTMY + "," + gdClientData.zoomToSkiResortLevel + ")\"><span class=\"skiresorticon\"><img alt=\"\" src=\"";
                if (this.isSkiResortClosed(item))
                    dataItem.html += "/images/icons/snowreport/vn_snowreport_closed.png";
                else
                    dataItem.html += "/images/icons/snowreport/vn_snowreport_blue.png";
                dataItem.html += "\"/></span><div class=\"c_resortname\">" + item.Name + "</div><div class=\"c_snowdepth\">" + item.SnowDepthObject.text + "</div></div>";
            }
        }, this);
        if (count > gdClientData.maxSkiResortsInList) {
            var ext = this.calculateExtent(resort.groupedResorts);
            var text = gdGetText("/snowreport/map/zoomtoresorts").replace(/\{0\}/g, count);
            var tooltip = gdGetTooltip("/snowreport/map/zoomtoresorts").replace(/\{0\}/g, count);
            dataItem.html += "<div title=\"" + tooltip + "\" class=\"map_skiresortzoom\" onmouseover=\"dojo.addClass(this, 'map_skiresortzoom_hover')\" onmouseout=\"dojo.removeClass(this, 'map_skiresortzoom_hover')\" onclick=\"gdZoomToEnvelope(" + ext.minX + "," + ext.minY + "," + ext.maxX + "," + ext.maxY + ")\" class=\"c_map_weatherlocation\">" + text + "</div>";
        }
        return dataItem;
    }

    this.addTemperatureSymbol = function (g, item, forecastHtml, symbolFc) {
        var arrTempSymbOffset = this.getTemperatureSymbolOffset(symbolFc, false);
        var xoffset = arrTempSymbOffset[0];
        var yoffset = arrTempSymbOffset[1];
        var nHaloWidth = 1;

        var symTxtTemperatureHalo1 = new esri.symbol.TextSymbol(this.getTemperatureNoPostFix(symbolFc), this.iconFontHalo, new dojo.Color("white"));
        symTxtTemperatureHalo1.setAlign(esri.symbol.TextSymbol.ALIGN_MIDDLE);
        symTxtTemperatureHalo1.setOffset(xoffset - nHaloWidth, yoffset - nHaloWidth);
        var grTextHalo1 = new esri.Graphic(g, symTxtTemperatureHalo1, { LocationName: item.LocationName, forecastHtml: forecastHtml, yrUrl: this.getYrUrl(item) }, this.weatherInfoTemplate);
        this.map.graphics.add(grTextHalo1);

        var symTxtTemperatureHalo2 = new esri.symbol.TextSymbol(this.getTemperatureNoPostFix(symbolFc), this.iconFontHalo, new dojo.Color("white"));
        symTxtTemperatureHalo2.setAlign(esri.symbol.TextSymbol.ALIGN_MIDDLE);
        symTxtTemperatureHalo2.setOffset(xoffset - nHaloWidth, yoffset + nHaloWidth);
        var grTextHalo2 = new esri.Graphic(g, symTxtTemperatureHalo2, { LocationName: item.LocationName, forecastHtml: forecastHtml, yrUrl: this.getYrUrl(item) }, this.weatherInfoTemplate);
        this.map.graphics.add(grTextHalo2);

        var symTxtTemperatureHalo3 = new esri.symbol.TextSymbol(this.getTemperatureNoPostFix(symbolFc), this.iconFontHalo, new dojo.Color("white"));
        symTxtTemperatureHalo3.setAlign(esri.symbol.TextSymbol.ALIGN_MIDDLE);
        symTxtTemperatureHalo3.setOffset(xoffset + nHaloWidth, yoffset - nHaloWidth);
        var grTextHalo3 = new esri.Graphic(g, symTxtTemperatureHalo3, { LocationName: item.LocationName, forecastHtml: forecastHtml, yrUrl: this.getYrUrl(item) }, this.weatherInfoTemplate);
        this.map.graphics.add(grTextHalo3);

        var symTxtTemperatureHalo4 = new esri.symbol.TextSymbol(this.getTemperatureNoPostFix(symbolFc), this.iconFontHalo, new dojo.Color("white"));
        symTxtTemperatureHalo4.setAlign(esri.symbol.TextSymbol.ALIGN_MIDDLE);
        symTxtTemperatureHalo4.setOffset(xoffset + nHaloWidth, yoffset + nHaloWidth);
        var grTextHalo4 = new esri.Graphic(g, symTxtTemperatureHalo4, { LocationName: item.LocationName, forecastHtml: forecastHtml, yrUrl: this.getYrUrl(item) }, this.weatherInfoTemplate);
        this.map.graphics.add(grTextHalo4);

        var symTxtTemperature = new esri.symbol.TextSymbol(this.getTemperatureNoPostFix(symbolFc), this.iconFontLight, this.temperatureTextColor);
        symTxtTemperature.setAlign(esri.symbol.TextSymbol.ALIGN_MIDDLE);
        symTxtTemperature.setOffset(xoffset, yoffset);

        var grTextTemp = new esri.Graphic(g, symTxtTemperature, { LocationName: item.LocationName, forecastHtml: forecastHtml, yrUrl: this.getYrUrl(item) }, this.weatherInfoTemplate);
        this.map.graphics.add(grTextTemp);
    }

    this.checkOverlap = function (x, y, overlapGrid, priority) {
        if (priority >= this.alwaysShowWeatherWithPriorityLowerThan) {
            for (var i = x - 1; i < x + 1; i++)
                for (var j = y - 1; j < y + 1; j++)
                    if (i >= 0 && j >= 0 && i < overlapGrid.length && j < overlapGrid[i].length && overlapGrid[i][j])
                        return false;
        }
        for (var i = x - 1; i < x + 1; i++)
            for (var j = y - 1; j < y + 1; j++)
                if (i >= 0 && j >= 0 && i < overlapGrid.length && j < overlapGrid[i].length)
                    overlapGrid[i][j] = true;
        return true;
    }

    this.getDayString = function (dayNumber) {
        return gdGetText("/map/weather/weekday" + dayNumber);
    }

    this.getTemperature = function (weatherForecast) {
        if (gdClientData.languageCode.toLowerCase() == "en-us")
            return Math.round(((9.0 / 5.0) * weatherForecast.Temperature) + 32) + "°F";
        else
            return weatherForecast.Temperature + "°C";
    }

    this.getSnowDepth = function (snowDepthCm) {
        if (gdClientData.languageCode.toLowerCase() == "en-us")
            return { depth: Math.round(snowDepthCm / 2.54), text: gdGetText("/snowreport/map/icontextin").replace(/\{0\}/g, Math.round(snowDepthCm / 2.54)) };
        else
            return { depth: Math.round(snowDepthCm), text: gdGetText("/snowreport/map/icontextcm").replace(/\{0\}/g, Math.round(snowDepthCm)) };
    }

    this.getTemperatureNoPostFix = function (weatherForecast) {
        if (gdClientData.languageCode.toLowerCase() == "en-us")
            return Math.round(((9.0 / 5.0) * weatherForecast.Temperature) + 32) + "°";
        else
            return weatherForecast.Temperature + "°";
    }

    this.getSnowReportUrl = function (url) {
        /*
        * E.g. http://www.skiinfo.no/Snorapport/Vassfjellet-ENOVASSF-100-no.jhtml?
        * Replace end of url with specified language.
        * Comparing end string of url including ".jhtml" to avoid replacing wrong part of url.
        * Not very scalable way, if url changes. Hopefully skiinfo will provide language specific url's in xml in the future.
        */
        var stringToReplace = "no.jhtml";
        var formatReplace = "{0}.jhtml";
        var language = gdClientData.languageCode;
        if (language == "en-us" || language == "en-gb" || language == "cn")
            language = "en";
        var newUrlPart = formatReplace.replace(/\{0\}/g, language);
        if (stringToReplace == newUrlPart)
            return url;
        return url.replace(stringToReplace, newUrlPart);
    }

    this.getYrUrl = function (weatherLocation) {
        if (gdClientData.languageCode == "no")
            return weatherLocation.NBUrl.replace("varsel.xml", "")
        else
            return weatherLocation.ENUrl.replace("forecast.xml", "")
    }

    this.getSymbolUrl = function (weatherForecast, shadow) {
        var suffix = ""; if (shadow) suffix = "_s";
        var url = weatherForecast.SymbolNumber + (weatherForecast.Period == 0 ? "n" : "d") + suffix + ".png";
        while (url.length < ("00n" + suffix + ".png").length) url = "0" + url;
        if (shadow)
            return "/images/icons/weather_small_shadow/" + url;
        else
            return "/images/icons/weather/" + url;
    }

    this.getTemperatureSymbolOffset = function (weatherForecast, shadow) {
        var xoffset;
        var yoffset;
        var result = new Array();

        switch (weatherForecast.SymbolNumber) {
            case 1:
            case 2:
                xoffset = -1;
                yoffset = -3;
                break;
            case 3:
                xoffset = -5;
                yoffset = -6;
                break;
            case 4:
                xoffset = -1;
                yoffset = -7;
                break;
            case 5:
            case 6:
            case 7:
            case 8:
                xoffset = -5;
                yoffset = -6;
                break;
            case 9:
            case 10:
            case 11:
            case 12:
            case 13:
            case 14:
                xoffset = -2;
                yoffset = -0;
                break;
            case 15:
                xoffset = -2;
                yoffset = -3;
                break;
            case 16:
                xoffset = -2;
                yoffset = 2;
                break;
            case 17:
            case 18:
            case 19:
                xoffset = -2;
                yoffset = 4;
                break;
            //        case 99:                                                                                                                              
            //        if (weatherForecast.Period == "d") {                                                                                                                      
            //                xoffset = 0;                                                                                                                      
            //                yoffset=0;                                                                                                                      
            //            }                                                                                                                      
            //            else {                                                                                                                      
            //                xoffset = 0;                                                                                                                      
            //                yoffset=0;                                                                                                                                  
            //            }                                                                                                                      
            //            break;                                                                                                                      
            default:
                xoffset = -2;
                yoffset = -3;
        }
        result[0] = xoffset;
        result[1] = yoffset;
        return result;
    }

    this.getTemperatureSymbolUrl = function (weatherForecast, shadow) {
        var temperature;
        temperature = this.getTemperature(weatherForecast);


        //        var suffix = ""; if (shadow) suffix = "_s";
        //        var url = weatherForecast.SymbolNumber + (weatherForecast.Period == 0 ? "n" : "d") + suffix + ".png";
        //        while (url.length < ("00n" + suffix + ".png").length) url = "0" + url;
        //        if (shadow)
        //            return "/images/icons/weather_small_shadow/" + url;
        //        else
        //            return "/images/icons/weather/" + url;
    }

    this.createForecastHtml = function (weatherForecast, d) {
        var html = "";
        var tooltip = this.getWeatherForecastText(weatherForecast) + " (" + gdGetText("/weather/time/atnoon") + ")";
        html += "    <div class=\"c_map_forecast\">";
        html += "      <div class=\"weather_day\">";
        html += "        <span>" + this.getDayString(d.getDay()) + "</span>";
        html += "      </div>";
        html += "      <div class=\"weather_symbol\">";
        html += "        <img alt=\"" + tooltip + "\" title=\"" + tooltip + "\" src=\"" + this.getSymbolUrl(weatherForecast) + "\"/>";
        html += "      </div>";
        html += "      <div class=\"weather_temp\">";
        html += "        <span>" + this.getTemperature(weatherForecast) + "</span>";
        html += "      </div>";
        html += "    </div>";
        return html;
    }

    this.parseDate = function (dateString) {
        //"04/29/2009 06:00:00"
        var s = dateString.split(" ");
        var datePart = s[0];
        var timePart = s[1];
        var dateParts = datePart.split("/");
        var timeParts = timePart.split(":");
        var result = new Date();
        result.setFullYear(dateParts[2] * 1);
        result.setMonth(dateParts[0] * 1 - 1, dateParts[1] * 1);
        result.setHours(timeParts[0] * 1, timeParts[1] * 1, timeParts[2] * 1, 0);
        return result;
    }

    this.addWeather = function (weatherForecasts) {
        if (this.weatherInfoTemplate == null) this.setupInfoWindow();
        var weatherItems = [];
        var wLen = 0;
        // Gather all forecasts for same locationid in one object
        for (var i = 0, len = weatherForecasts.length; i < len; i++) {
            var fc = weatherForecasts[i];
            if (wLen == 0 || weatherItems[wLen - 1].locationId != fc.locationId) {
                wLen++;
                fc.forecasts = [];
                weatherItems.push(fc);
                fc.forecasts.push(fc);
            }
            else
                weatherItems[wLen - 1].forecasts.push(fc);
        }
        this.weatherItems = weatherItems;
        this.updateGraphics();
    }

    this.addSnowInfo = function (skiResorts) {
        if (this.snowInfoTemplate == null) this.setupInfoWindow();
        this.skiResorts = skiResorts;
        dojo.forEach(this.skiResorts, function (item) {
            item.SnowDepthObject = this.getSnowDepth(item.TopSnowTerrainCm);
            item.SnowDepth = item.SnowDepthObject.depth;
            item.Url = this.getSnowReportUrl(item.Url);
            this.getSkiResortClosedStatus(item);
        }, this);
        this.updateGraphics();
    }

    this.getMapTip = function (index) {
        for (var i = 0, len = this.mapTipItems.length; i < len; i++) {
            var item = this.mapTipItems[i];
            if (item.index == index) return item;
        }
        return null;
    }

    this.showTip = function (index, e, productID, selected) {

        var item = null;
        if (this.enabled) {
            if (selected)
                item = this.selectedMapTipItem;
            else
                item = this.getMapTip(index);
            if (item == null && this.selectedMapTipItem != null && this.selectedMapTipItem.index == index)
                item = this.selectedMapTipItem;

            if (item.productId == 0) 
                item.productId = productID*1;  // sets item product id equals the first product in list
            
            geodata.maptips.currentMapTipsWindow.show(item);
        }

        return item;
    }

    this.hideCurrentItem = function () {
        var item = geodata.maptips.currentMapTipsWindow.hide();
        if (this.map.infoWindow.isShowing) this.map.infoWindow.hide();
    }

    this.graphicClicked = function (evt) {
        this.hideCurrentItem();
        if (evt.graphic && evt.graphic.attributes && evt.graphic.attributes.groupedResorts) {
            var ext = this.calculateExtent(evt.graphic.attributes.groupedResorts);
            if (ext.count > 1) {
                gdZoomToEnvelope(ext.minX, ext.minY, ext.maxX, ext.maxY);
            }
            else if (ext.count == 1) {
                gdZoomToPoint(ext.minX, ext.minY, gdClientData.zoomToSkiResortLevel);
            }
        }
    }

    this.calculateExtent = function (skiResorts) {
        var minX = 99999999;
        var minY = 99999999;
        var maxX = -99999999;
        var maxY = -99999999;
        var count = 0;
        dojo.forEach(skiResorts, function (item) {
            if (minX > item.UTMX) minX = item.UTMX;
            if (minY > item.UTMY) minY = item.UTMY;
            if (maxX < item.UTMX) maxX = item.UTMX;
            if (maxY < item.UTMY) maxY = item.UTMY;
            count++;
        }, this);
        return { minX: minX, minY: minY, maxX: maxX, maxY: maxY, count: count };
    }

}
// MapTipsLayer

