WME Speedlimits

Adds colours to road segments to show their speeds

Устаревшая версия за 02.05.2018. Перейдите к последней версии.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name                WME Speedlimits
// @namespace           https://greasyfork.org/cs/scripts/12402-wme-speeds
// @author              Martin Kolář (based from WME Color Highlights v. 1.98)
// @description         Adds colours to road segments to show their speeds
// @include             https://editor-beta.waze.com/*
// @include             https://beta.waze.com/*
// @include             https://www.waze.com/editor*
// @include             https://www.waze.com/*/editor*
// @exclude             https://www.waze.com/user/*editor*
// @exclude             https://www.waze.com/*/user/*editor*
// @version             0.4.3.6
// @grant               none
// @contributor         FZ69617
// ==/UserScript==

/*jshint eqnull:true, eqeqeq:true, freeze:true, funcscope:true, maxerr:1000, curly:true, latedef:true, unused:strict, noarg:true, loopfunc:true, undef:true */
/*jshint -W069 */
/*jshint browser:true */
/*global Waze, I18n, OpenLayers, console */

(function()
{

// global variables

var wmeSpeedsVersion = '0.4.3.6';
var wmeSpeedsInit = false;
var wmeSpeedsColors =    ['#ff0000', '#321325', '#540804', '#BA1200', '#FA4A48', '#F39C6B', '#A7D3A6', '#ADD2C2', '#CFE795', '#F7EF81', '#BDC4A7', '#95AFBA', '#3F7CAC', '#0A369D', '#001C55'];
var wmeSpeedsColorsMph = ['#ff0000', '#321325', '#702632', '#540804', '#A00027', '#BA1200', '#F15872', '#FA4A48', '#F39C6B', '#A7D3A6', '#ADD2C2', '#CFE795', '#F7EF81', '#BDC4A7', '#95AFBA', '#3F7CAC', '#0A369D', '#001C55', '#000000'];
var wmeSpeedsMaxSpeed = 130;
var wmeSpeedsMaxMphSpeed = 85;
var wmeSpeedsLayer;
var wmeSpeedsNonDrivableSpeedSegments = [5, 8, 10, 16, 18, 19, 20, 17, 15];
var wmeSpeedsOtherDrivableSegments = [8, 20, 117, 115];
var wmeSpeedsNonDrivableSegments = [5, 10, 16, 18, 19];
var wmeSpeedsMiles = false;
var wmeSpeedsKmphToMphRatio = 0.621371192;
var wmeSpeedsInvertSpeedsColors, wmeSpeedsInvertNonDrivableSpeedsColors, wmeSpeedsHighlightOneWay, wmeSpeedsTransparentColors, wmeSpeedsNonDrivableSpeedsColors, wmeSpeedsOtherDrivableSpeedsColors, wmeSpeedsUnverified;

//  language settings
var wmeSpeedsLanguage = 'en';  //  default language
var wmeSpeedsTranslation = [];

//  icons
var wmeSpeedsTabIcon = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowNjg3OEY2RjhFMEIxMUU1OTU1MUU5MjA0ODlFQjA1MCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDowNjg3OEY3MDhFMEIxMUU1OTU1MUU5MjA0ODlFQjA1MCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjA2ODc4RjZEOEUwQjExRTU5NTUxRTkyMDQ4OUVCMDUwIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjA2ODc4RjZFOEUwQjExRTU5NTUxRTkyMDQ4OUVCMDUwIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Dhzo6gAABIFJREFUeNqsV2tMU1kQnsWiVhG6Irrro1Br9IcJoMFH1j+AURLEB2CMGBWNIIgmZhMX/W+IupsYV+NzXR9IEE00+KpBjfiE4ApWs/5YHhbqA4EFWhArwg9nTs+9PffS1kthki/33plzZubcM3Nmju7aSNBKIYhliARELMKECOMyJ8KGsCLKEbcQn7Qo/UGDAzMQuxEZiLEane1BXEQcQNT7GxjkRzYasR/xGpE1COPAx2bxuQe4rkE5YEZU8pWPhMCJ5uZzXTO8DdB54c1FWBCT1IKwuAUweVUaRCQkgt5oBF1oKOP3d3WBy26HtvL78KH0KjifV6mnUsw8QSQjavzFAHlZgYgQmaFz4mB63g4wbszUtGx74XmwHT8Kzpp/1KI2xC9iXIgO6PmvihFnGDdlQ+zJUwH9f2tuDtjPDpj7CrEQ4aKPERkjZEEBIl0RCDt3QfThIwEHwE8py6G/uwc6qypENm1tMOKe6AAFXRF9yyvfvBWi/zwMQ6WJS5aC630zOK3VIns+T9MOKQv2cK/cwTZ3HsSeOAnDRaSLdAoUzG2yLBjHDxmZTLl5CgVXrpbCqdNnBigus1yX3588rYDii5eg4Y0NzNNNsHJFCiQtXeLRuW07WLM3idPXIn4N4qkxVkw1Y6ZiINTW1fldIRnfW7CfGSei58FDR6Dszl1PMGMGkW7VYZVMDiwWuVNS030aohWLkOjYcfd2rVu7hvHpSXS+sAi+o3sxORAtcibEJwww/ODhY59O/VdbC+0dnew9MTGePVOWJbMn8UnuR3d0EM8AmcaYTD6NJSWvgLwdO1lMuFwsjaGxsUmWT5s6lT3Dw8fLPFHuRbeZgjBUcTaHhChGvH33TvFN+0t4Xl0N+wr2Diob1LrJtu57k2hV0n7Tqi23y1hG1Lx4yYJvqERb0CUy+j/57iP0ej2kp63yFP2eHoiKipS/29s7FE8iUe5Fdxc50CByPttsihGkTFQophYpnzVzJoSP/5F937xl4UH7yB0LyCe5L91kW8eLg5yg/z8oB0NcnDyC9ppyWk2UapLyzI3r2ZjikssMEuVty1HMId3qwkS1YAy+rJY4X7G2R23J8rjY8AZ6e3uh+WOLu1mYEwMZaDw9LdVTw81mmBgxAVpb26Cz08FOws2ZGyAxIV5h7d/8XfDlgyKo/6ByTEdxs3gaxv51TnPt10r2C4VgzVLo/EwFk2KgG1EiSqiZGG7yopOqYbdUDan57JMk1MlQMzFcRLqc1c9EVh9vVuV+oIP3/YtkJ7B+UzNB9Xwo9Dr/N2g8MSCIDyIuqTuip4jlYjNKnQw1E9TZBLpyL8Yp6zZIf1x0oJ+3SYoLCP2JjxYLBI0aBWExMdoDLjcbWm/f8NaUJiFa/N2MfLblhnkL4eeVqe62PDISgg0G94Y6HOBqamJtefP1UnA8q/TmV4uWtlxsz6+oS/UQ6BVveOu13ozq+en4u5gdAVAf17HA1x3R393wC7+azUac5geHVqJm4W8+dzfXFfDtWLyep6iu5wYuc6iu5ze1Xs+/CTAA2tuMX1dHe2oAAAAASUVORK5CYII=';

//  cs translation
wmeSpeedsTranslation['cs'] = {
  'scriptName': 'WME Speeds',
  'layerName': 'Rychlosti',
  'tabName': 'R',
  'speedsHeadline': 'Barvy segmentů dle rychlostí',
  'forumLink': '<a href="https://www.waze.com/forum/viewtopic.php?f=22&t=166406" target="_blank">České fórum</a>',
  'author': 'Autor: <a href="https://www.waze.com/cs/user/editor/martinkolar" target="_blank">martinkolar (4)</a>',
  'version': 'Verze:',
  'invertSpeedsTitleNonDrivable': 'Invertovat barvy rychlostí (pouze s možností nastavení rychlosti)',
  'invertSpeedsContentNonDrivable': 'Zvýrazní jen segmenty bez rychlosti (sjízdné) (červená)',
  'invertSpeedsTitle': 'Invertovat barvy rychlostí (všechny segmenty)',
  'invertSpeedsContent': 'Zvýrazní jen segmenty bez rychlosti (nesjízdné) (červená)',
  'noSpeedsSegmentsTitle': 'Nesjízdné segmenty s rychlostí',
  'noSpeedsSegmentsContent': 'Zvýrazní nesjízdné segmenty s rychlostmi (růžová)',
  'noSpeedsSegmentsOtherTitle': 'Jinak sjízdné segmenty s rychlostí',
  'noSpeedsSegmentsOtherContent': 'Zvýrazní jinak sjízdné segmenty s rychlostmi (růžová)',
  'transparentColorsTitle': 'Průsvitné barvy',
  'transparentColorsContent': 'Průsvitné barvy',
  'unverifiedSegmentsTitle': 'Nepotvrzené rychlosti na segmentech',
  'unverifiedSegmentsContent': 'Zvýrazní nepotvrzené rychlosti na segmentech',
};

//  sk translation
wmeSpeedsTranslation['sk'] = {
  'tabName': 'R',
  'speedsHeadline': 'Farby segmentov podľa rýchlostí',
  'forumLink': '<a href="https://www.waze.com/forum/viewtopic.php?f=22&t=166406" target="_blank">České fórum</a>',
  'author': 'Autor: <a href="https://www.waze.com/cs/user/editor/martinkolar" target="_blank">martinkolar (CZ)</a>',
  'version': 'Verzia:',
  'invertSpeedsTitleNonDrivable': 'Invertovať farby rýchlostí (pouze s možností nastavení rychlosti)',
  'invertSpeedsContentNonDrivable': 'Zvýrazní iba segmenty bez rýchlosti (sjízdné) (červená)',
  'invertSpeedsTitle': 'Invertovať farby rýchlostí',
  'invertSpeedsContent': 'Zvýrazní iba segmenty bez rýchlosti (červená)',
  'noSpeedsSegmentsTitle': 'Nezjazdné segmenty s rýchlosťou',
  'noSpeedsSegmentsContent': 'Zvýrazní nezjazdné segmenty s rýchlosťami (ružová)',
  'noSpeedsSegmentsOtherTitle': 'Inak zjazdné segmenty s rýchlosťou',
  'noSpeedsSegmentsOtherContent': 'Zvýrazní inak zjazdné segmenty s rýchlosťami (ružová)',
  'transparentColorsTitle': 'Priehľadné farby',
  'transparentColorsContent': 'Spriehľadniť farby rýchlostí',
  'unverifiedSegmentsTitle': 'Nepotvrdené rýchlosti na segmentoch',
  'unverifiedSegmentsContent': 'Zvýrazniť nepotvrdené rýchlosti na segmentoch',
  'scriptName': 'WME Speeds',
  'layerName': 'Rýchlosti',
};

//  en translation
wmeSpeedsTranslation['en'] = {
  'tabName': 'S',
  'speedsHeadline': 'Colors by speed',
  'forumLink': '<a href="https://www.waze.com/forum/viewtopic.php?f=819&t=166497" target="_blank">English discussion</a>',
  'author': 'Author: <a href="https://www.waze.com/cs/user/editor/martinkolar" target="_blank">martinkolar (CZ)</a>',
  'version': 'Version:',
  'invertSpeedsTitleNonDrivable': 'Invert speed (only segments with speed settings)',
  'invertSpeedsContentNonDrivable': 'Highlight segments without set speed (drivable) (red)',
  'invertSpeedsTitle': 'Invert speed',
  'invertSpeedsContent': 'Highlight segments without set speed (red)',
  'noSpeedsSegmentsTitle': 'Non-drivable segments with speeds',
  'noSpeedsSegmentsContent': 'Highlight non-drivable segments with set speed (pink)',
  'noSpeedsSegmentsOtherTitle': 'Other-drivable segments with speeds',
  'noSpeedsSegmentsOtherContent': 'Highlight other-drivable segments with set speed (pink)',
  'transparentColorsTitle': 'Transparent color',
  'transparentColorsContent': 'Make speed\'s colors transparent',
  'unverifiedSegmentsTitle': 'Highlight unverified segments',
  'unverifiedSegmentsContent': 'Highlight unverified segments',
  'scriptName': 'WME Speeds',
  'layerName': 'Speeds',
};

//  Heb translation
wmeSpeedsTranslation['he'] = {
  'tabName': 'S',
  'speedsHeadline': 'מקרא מהירויות לפי צבעים',
  'forumLink': '<a href="https://www.waze.com/forum/viewtopic.php?f=819&t=166497" target="_blank">דיון בפורום (אנגלית)</a>',
  'author': 'יוצר התוסף: martinkolar (CZ)',
  'version': 'גרסא:',
  'invertSpeedsTitleNonDrivable': 'הדגש את כל המקטעים ללא מהירות מוגדרת',
  'invertSpeedsContentNonDrivable': 'הדגש מקטעים מותרים לנהיגה ללא מהירות מוגדרת (אדום)',
  'invertSpeedsTitle': 'הפוך הגדרות',
  'invertSpeedsContent': 'הדגש מקטעים ללא מהירות מוגדרת (אדום)',
  'noSpeedsSegmentsTitle': 'מקטעים שאינם ניתנים לנהיגה עם מהירות מוגדרת',
  'noSpeedsSegmentsContent': 'הדגש מקטעים שאינם ניתנים לנהיגה עם מהירות מוגדרת (ורוד)',
  'noSpeedsSegmentsOtherTitle': 'אחר- מקטעים המותרים לנהיגה עם מהירות מוגדרת',
  'noSpeedsSegmentsOtherContent': 'הדגש מקטעים המותרים לנהיגה עם מהירות מוגדרת (ורוד)',
  'transparentColorsTitle': 'מצב שקיפות',
  'transparentColorsContent': 'הפעל מצב שקיפות צבעי מהירויות',
  'unverifiedSegmentsTitle': 'הדגש מקטעים לא מאומתים',
  'unverifiedSegmentsContent': 'הדגש מקטעים לא מאומתים',
  'scriptName': 'WME Speeds',
  'layerName': 'מהירויות',
};

//  pl translation
wmeSpeedsTranslation['pl'] = {
  'scriptName': 'WME Speeds',
  'layerName': 'Ograniczenia prękości',
  'tabName': 'P',
  'speedsHeadline': 'Kolory ograniczeń prędkości',
  'forumLink': 'Forum: <a href="https://www.waze.com/forum/viewtopic.php?f=819&t=166497" target="_blank">angielskie</a> | <a href="https://www.waze.com/forum/viewtopic.php?f=22&t=166406" target="_blank">czeskie</a>',
  'author': 'Autor: <a href="https://www.waze.com/cs/user/editor/martinkolar" target="_blank">martinkolar (4)</a>',
  'version': 'Wersja:',
  'invertSpeedsTitleNonDrivable': 'Inwersja kolorów (tylko z opcją ograniczenia)',
  'invertSpeedsContentNonDrivable': 'Zaznacza drogi bez ustawionych ograniczeń prędkości z dostępną opcją ograniczenia (czerwony)',
  'invertSpeedsTitle': 'Inwersja kolorów',
  'invertSpeedsContent': 'Zaznacza drogi bez ustawionych ograniczeń prędkości (czerwony)',
  'noSpeedsSegmentsTitle': 'Nieprzejezdne drogi z prędkościami',
  'noSpeedsSegmentsContent': 'Zaznacza nieprzejezdne drogi z ustawionymi ograniczeniami prędkości (różowy)',
  'noSpeedsSegmentsOtherTitle': 'Inne przejezdne drogi z prędkościami',
  'noSpeedsSegmentsOtherContent': 'Zaznacza inne przejezdne drogi z ustawionymi ograniczeniami prędkości (różowy)',
  'transparentColorsTitle': 'Przeźroczyste kolory',
  'transparentColorsContent': 'Przeźroczyste kolory ograniczeń',
  'unverifiedSegmentsTitle': 'Niezweryfikowane prędkości',
  'unverifiedSegmentsContent': 'Wyróżnia segmenty z niezweryfikowanymi ograniczeniami prędkości',
};

/* =========================================================================== */
function highlightSpeedsSegments() {
  wmeSpeedsInvertSpeedsColors = getId('_wmeSpeedsInvert').checked;
  wmeSpeedsInvertNonDrivableSpeedsColors = getId('_wmeSpeedsInvertNonDrivable').checked;
  wmeSpeedsNonDrivableSpeedsColors = getId('_wmeSpeedsNonDrivable').checked;
  wmeSpeedsOtherDrivableSpeedsColors = getId('_wmeSpeedsOtherDrivable').checked;
  wmeSpeedsTransparentColors = getId('_wmeSpeedsTransparentColors').checked;
  wmeSpeedsUnverified = getId('_wmeSpeedsUnverifed').checked;
  wmeSpeedsHighlightOneWay = false;
  var roadGroupSelector = document.getElementById('layer-switcher-group_road');

  if (wmeSpeedsLayer.getVisibility() && roadGroupSelector.checked) {

    var speedDiv = wmeSpeedsMiles ? 5 : 10;
    var maxSpeed = wmeSpeedsMiles ? wmeSpeedsMaxMphSpeed : wmeSpeedsMaxSpeed;
    var speedsColors = wmeSpeedsMiles ? wmeSpeedsColorsMph : wmeSpeedsColors;
    var speedOpacity = wmeSpeedsTransparentColors ? 0.5 : 1;
    var speedValue = wmeSpeedsMiles ? kmphToMph : function (x) { return x; };

    var features = [];

    for (var seg in W.model.segments.objects) {
      var segment = W.model.segments.get(seg);

      if (!isOnScreen(segment)) {
        continue;
      }

      var attributes = segment.attributes;
      var roadType = attributes.roadType;

      if ((wmeSpeedsNonDrivableSpeedsColors && wmeSpeedsNonDrivableSegments.indexOf(roadType) !== -1) ||
          (wmeSpeedsOtherDrivableSpeedsColors && wmeSpeedsOtherDrivableSegments.indexOf(roadType) !== -1)) {
        if (typeof attributes.fwdMaxSpeed === 'number' || typeof attributes.revMaxSpeed === 'number') {
          features.push(new OpenLayers.Feature.Vector(segment.geometry.clone(), {}, {
              strokeColor: "#DC0073",
              strokeWidth: 8,
              strokeOpacity: speedOpacity
            }));
        }
        continue;
      }

      var speed1 = { index: 0, allow: attributes.fwdDirection, unverified: attributes.fwdMaxSpeedUnverified };
      var speed2 = { index: 0, allow: attributes.revDirection, unverified: attributes.revMaxSpeedUnverified };

      if (!speed1.allow && !speed2.allow) {
        continue;
      }

      if (speed1.allow && typeof attributes.fwdMaxSpeed === 'number') {
        speed1.value = speedValue(attributes.fwdMaxSpeed);
        speed1.exact = (speed1.value % speedDiv) === 0;

        if (speed1.value >= maxSpeed) {
          speed1.index = Math.ceil(maxSpeed / speedDiv);
        }
        else {
          speed1.index = Math.ceil(speed1.value / speedDiv);
        }
      }

      if (speed2.allow && typeof attributes.revMaxSpeed === 'number') {
        speed2.value = speedValue(attributes.revMaxSpeed);
        speed2.exact = (speed2.value % speedDiv) === 0;

        if (speed2.value >= maxSpeed) {
          speed2.index = Math.ceil(maxSpeed / speedDiv);
        }
        else {
          speed2.index = Math.ceil(speed2.value / speedDiv);
        }
      }

      speed1.color = speedsColors[speed1.index];
      speed2.color = speedsColors[speed2.index];

      if ((!wmeSpeedsInvertSpeedsColors && !wmeSpeedsInvertNonDrivableSpeedsColors) && ((speed1.index === 0  && speed2.index === 0) || (!speed2.allow && speed1.index === 0) || (!speed1.allow && speed2.index === 0))) {
        continue;
      }

      if (wmeSpeedsInvertSpeedsColors && ((speed1.index === 0  && speed2.index === 0) || (!speed2.allow && speed1.index === 0) || (!speed1.allow && speed2.index === 0))) {
        features.push(new OpenLayers.Feature.Vector(segment.geometry.clone(), {}, {
            strokeColor: "#ff0000",
            strokeWidth: 8,
            strokeOpacity: speedOpacity
          }));
        continue;
      }

      if (wmeSpeedsInvertNonDrivableSpeedsColors && ((speed1.index === 0  && speed2.index === 0) || (!speed2.allow && speed1.index === 0) || (!speed1.allow && speed2.index === 0)) && wmeSpeedsNonDrivableSpeedSegments.indexOf(roadType) === -1) {
        features.push(new OpenLayers.Feature.Vector(segment.geometry.clone(), {}, {
            strokeColor: "#ff0000",
            strokeWidth: 8,
            strokeOpacity: speedOpacity
          }));
        continue;
      }

      if (wmeSpeedsInvertSpeedsColors || wmeSpeedsInvertNonDrivableSpeedsColors) {
        continue;
      }

      if (wmeSpeedsHighlightOneWay && ((!attributes.fwdDirection && typeof attributes.fwdMaxSpeed === 'number') ||
                                       (!attributes.revDirection && typeof attributes.revMaxSpeed === 'number'))) {
        features.push(new OpenLayers.Feature.Vector(segment.geometry.clone(), {}, {
            strokeColor: attributes.fwdDirection ? "#ffffff" : "#999999",
            strokeDashstyle: "15 15",
            strokeWidth: 8,
            strokeOpacity: speedOpacity
          }));
        continue;
      }

      var oneSpeed = null;

      if (speed1.allow && speed2.allow) {
        if (speed1.index === 0 || speed2.index === 0) {
          features.push(new OpenLayers.Feature.Vector(segment.geometry.clone(), {}, {
              strokeColor: "#ff00ff",
              strokeWidth: 8,
              strokeOpacity: speedOpacity
            }));
          continue;
        }

        if ((speed1.index === speed2.index) && (speed1.exact === speed2.exact) &&
            (!wmeSpeedsUnverified || (speed1.unverified === speed2.unverified))) {
          oneSpeed = speed1;
        }
      }
      else if (speed1.allow) {
        oneSpeed = speed1;
      }
      else if (speed2.allow) {
        oneSpeed = speed2;
      }

      if (oneSpeed !== null) {
        if (wmeSpeedsUnverified && oneSpeed.unverified) {
          features.push(new OpenLayers.Feature.Vector(segment.geometry.clone(), {}, {
              strokeColor: oneSpeed.color,
              strokeDashstyle: "1 14",
              strokeLinecap: "round",
              strokeWidth: 8,
              strokeOpacity: speedOpacity
            }));
        }
        else {
          features.push(new OpenLayers.Feature.Vector(segment.geometry.clone(), {}, {
              strokeColor: oneSpeed.color,
              strokeDashstyle: oneSpeed.exact ? "none" : "4 1",
              strokeLinecap: oneSpeed.exact ? "round" : "butt",
              strokeWidth: 8,
              strokeOpacity: speedOpacity
            }));
        }
        continue;
      }

      if ((attributes.fwdDirection && attributes.fwdMaxSpeed === 126) ||
          (attributes.revDirection && attributes.revMaxSpeed === 126)) {
        features.push(new OpenLayers.Feature.Vector(segment.geometry.clone(), {}, {
            strokeColor: "#ff00ff",
            strokeWidth: 8,
            strokeOpacity: speedOpacity
          }));
        continue;
      }

      // draw two speeds

      var speed1Dotted = speed1.allow && wmeSpeedsUnverified && speed1.unverified;
      var speed2Dotted = speed2.allow && wmeSpeedsUnverified && speed2.unverified;

      if (speed1.allow) {
          if (speed1Dotted) {
            features.push(new OpenLayers.Feature.Vector(segment.geometry.clone(), {}, {
                strokeColor: speed1.color,
                strokeDashstyle: speed2Dotted ? "1 14" : "1 29",
                strokeLinecap: "round",
                strokeWidth: 8,
                strokeOpacity: speedOpacity
              }));
          }
          else {
            features.push(new OpenLayers.Feature.Vector(segment.geometry.clone(), {}, {
                strokeColor: speed1.color,
                //strokeDashstyle: speed1.exact ? "15 15" : "4 1 4 1 4 1 0 15",
                //strokeDashstyle: speed1.exact ? "0 8 15 7" : "0 8 4 1 4 1 4 1 0 7",
                strokeDashstyle: speed1.exact ? (speed2Dotted ? "0 8 15 7" : "15 15") : (speed2Dotted ? "0 8 4 1 4 1 4 1 0 7" : "4 1 4 1 4 1 0 15"),
                strokeLinecap: "butt",
                strokeWidth: 8,
                strokeOpacity: speedOpacity
              }));
          }
      }

      if (speed2.allow) {
          if (speed2Dotted) {
            features.push(new OpenLayers.Feature.Vector(segment.geometry.clone(), {}, {
                strokeColor: speed2.color,
                strokeDashstyle: "1 29",
                strokeLinecap: "round",
                strokeWidth: 8,
                strokeOpacity: speedOpacity
              }));
          }
          else {
            features.push(new OpenLayers.Feature.Vector(segment.geometry.clone(), {}, {
                strokeColor: speed2.color,
                //strokeDashstyle: speed2.exact ? "0 15 15 0" : "0 15 4 1 4 1 4 1",
                //strokeDashstyle: speed2.exact ? (speed1Dotted ? "0 8 15 7" : "8 15 7 0") : (speed1Dotted ? "0 8 4 1 4 1 4 1 0 7" : "3 1 4 15 4 1 2 0"),
                strokeDashstyle: speed2.exact ? (speed1Dotted ? "0 8 15 7" : "0 15 15 0") : (speed1Dotted ? "0 8 4 1 4 1 4 1 0 7" : "0 15 4 1 4 1 4 1"),
                strokeLinecap: "butt",
                strokeWidth: 8,
                strokeOpacity: speedOpacity
              }));
          }
      }

    } // end of loop

    wmeSpeedsLayer.removeAllFeatures();
    wmeSpeedsLayer.addFeatures(features);
  }
} // end of function

function makeSpeedsTab() {
  var addon = document.createElement('section');

  addon.innerHTML += '<h3 style="margin-bottom: 5px;">' + fe_t('speedsHeadline') + '</h3>';

  function optionHtml(id, title_t, content_t) {
    return '<label title="' + fe_t(content_t) + '"><input id="' + id + '" type="checkbox"/>' + fe_t(title_t) + '</label><br>';
  }

  addon.innerHTML += optionHtml("_wmeSpeedsInvert", 'invertSpeedsTitle', 'invertSpeedsContent');
  addon.innerHTML += optionHtml("_wmeSpeedsInvertNonDrivable", 'invertSpeedsTitleNonDrivable', 'invertSpeedsContentNonDrivable');
  addon.innerHTML += optionHtml("_wmeSpeedsNonDrivable", 'noSpeedsSegmentsTitle', 'noSpeedsSegmentsContent');
  addon.innerHTML += optionHtml("_wmeSpeedsOtherDrivable", 'noSpeedsSegmentsOtherTitle', 'noSpeedsSegmentsOtherContent');
  addon.innerHTML += optionHtml("_wmeSpeedsUnverifed", 'unverifiedSegmentsTitle', 'unverifiedSegmentsContent');
  addon.innerHTML += optionHtml("_wmeSpeedsTransparentColors", 'transparentColorsTitle', 'transparentColorsContent');

  var speedsForTab = wmeSpeedsMiles ? wmeSpeedsColorsMph : wmeSpeedsColors;

  addon.innerHTML += '<div style="margin-top: 10px;"></div>';

  for (var i = 1; i < speedsForTab.length; i++) {
    var actualSpeedForTab;
    if ((i+1) === speedsForTab.length) {
      if (wmeSpeedsMiles) {
        actualSpeedForTab = ' &gt; ' + wmeSpeedsMaxMphSpeed + '&nbsp;mph';
      }
      else {
        actualSpeedForTab = ' &gt; ' + wmeSpeedsMaxSpeed + '&nbsp;km/h';
      }
    }
    else if (wmeSpeedsMiles) {
      actualSpeedForTab = (i * 5) + '&nbsp;mph';
    }
    else {
      actualSpeedForTab = (i * 10) + '&nbsp;km/h';
    }

    addon.innerHTML += '<div style="width: 28%; float: left;background-color: ' + speedsForTab[i] + ';padding:2px 0;border-radius:5px;color:' + getContrastColor(speedsForTab[i]) + ';font-size:14px;text-align:center;margin: 0 3px 3px;">' + actualSpeedForTab + '</div>';
  }

  addon.innerHTML += '<p style="font-size:11px;margin-top:15px;clear:both;">' + fe_t('forumLink') + '<br>' + fe_t('author') + '<br>' + fe_t('version') + ' ' + wmeSpeedsVersion + '</p>';

  var userTabs = getId('user-info');
  var navTabs = getElementsByClassName('nav-tabs', userTabs)[0];
  var tabContent = getElementsByClassName('tab-content', userTabs)[0];

  var newtab = document.createElement('li');
  newtab.innerHTML = '<a title="WME Speeds" href="#sidepanel-wme-speeds" data-toggle="tab"><img src="data:image/png;base64,' + wmeSpeedsTabIcon + '" width="16" height="16" style="margin-top: -2px;">&nbsp;' + /*fe_t('tabName') +*/ '</a>';
  navTabs.appendChild(newtab);

  addon.id = "sidepanel-wme-speeds";
  addon.className = "tab-pane";
  tabContent.appendChild(addon);
}

/* helper function */
function getElementsByClassName(classname, node) {
  node = node || document.getElementsByTagName("body")[0];
  var a = [];
  var re = new RegExp('\\b' + classname + '\\b');
  var els = node.getElementsByTagName("*");
  for (var i=0,j=els.length; i<j; i++) {
    if (re.test(els[i].className)) {
      a.push(els[i]);
    }
  }
  return a;
}

function getId(node) {
  return document.getElementById(node);
}

function changeLayer() {
  var roadGroupSelector = document.getElementById('layer-switcher-group_road');
  var layerSelector = document.getElementById('layer-switcher-item_speeds');

  if (roadGroupSelector.checked && layerSelector.checked) {
    highlightSpeedsSegments();
  } else {
    wmeSpeedsLayer.removeAllFeatures();
  }

  if (layerSelector.checked) {
    localStorage.DrawSegmentSpeeds = true;
  }
  else {
    localStorage.DrawSegmentSpeeds = false;
  }
}

function kmphToMph(kmph) {
  return Math.round(kmph * wmeSpeedsKmphToMphRatio);
}

function fe_t(name, params) { //  function for translation
  if (typeof params === 'object') {
    var returnString = wmeSpeedsTranslation[wmeSpeedsLanguage][name];

    for (var i in params) {
      do {
        returnString = returnString.replace('{' + i + '}', params[i]);
      } while (returnString.indexOf('{' + i + '}') !== -1);
    }

    return returnString;
  }
  else {
    return wmeSpeedsTranslation[wmeSpeedsLanguage][name];
  }
}

function isOnScreen(segment) {
  var e = W.map.getExtent();
  var eg = e.toGeometry();
  return eg.intersects(segment.geometry);
}

function getContrastColor(hex_color) {
  var r = parseInt(hex_color.substr(1, 2), 16);
  var g = parseInt(hex_color.substr(3, 2), 16);
  var b = parseInt(hex_color.substr(5, 2), 16);
  var yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
  return (yiq >= 128) ? 'black' : 'white';
}

/* =========================================================================== */
function initialiseSpeedsHighlights() {
  if (wmeSpeedsInit) {
    return ;
  }

  // init shortcuts

  if (typeof(Waze) === 'undefined') {
    console.log("WME Speeds: Waze : NOK");
    setTimeout(initialiseSpeedsHighlights, 500);
    return ;
  }

  if (!W.map) {
      window.console.log("WME Speeds: waiting for WME...");
      setTimeout(initialiseSpeedsHighlights, 555);
      return ;
  }

  if (typeof(OpenLayers) === 'undefined') {
    console.log("WME Speeds: OpenLayers : NOK");
    setTimeout(initialiseSpeedsHighlights, 500);
    return ;
  }

  if (wmeSpeedsTranslation[I18n.locale] != null) {
    wmeSpeedsLanguage = I18n.locale;
  }

  var userInfo = getId('user-info');
  if (typeof getElementsByClassName('nav-tabs', userInfo)[0] === 'undefined') {
    setTimeout(initialiseSpeedsHighlights, 500);
    return ;
  }

  wmeSpeedsLayer = new OpenLayers.Layer.Vector(fe_t('layerName'), {
    displayInLayerSwitcher: true,
    uniqueName: "__DrawSegmentSpeeds"
  });

  // I18n.translations.en.layers.name["__DrawSegmentSpeeds"] = fe_t('scriptName');
  W.map.addLayer(wmeSpeedsLayer);

  var roadGroupSelector = document.getElementById('layer-switcher-group_road');

  if (roadGroupSelector !== null) {
    var roadGroup = roadGroupSelector.parentNode.parentNode.querySelector('.children');
    var toggler = document.createElement('li');
    var togglerContainer = document.createElement('div');
    var checkbox = document.createElement('input');
    var label = document.createElement('label');
    var labelText = document.createElement('span');

    togglerContainer.className = 'controls-container toggler';
    checkbox.type = 'checkbox';
    checkbox.id = 'layer-switcher-item_speeds';
    checkbox.className = 'toggle';
    checkbox.disabled = !roadGroupSelector.checked;

    if (localStorage.DrawSegmentSpeeds === 'true') {
      checkbox.checked = 'checked';
    }

    togglerContainer.appendChild(checkbox);
    label.htmlFor = checkbox.id;
    labelText.className = 'label-text';
    labelText.appendChild(document.createTextNode(fe_t('layerName')));
    label.appendChild(labelText);
    togglerContainer.appendChild(label);
    toggler.appendChild(togglerContainer);
    roadGroup.appendChild(toggler);

    checkbox.addEventListener('click', function(e) {
      wmeSpeedsLayer.setVisibility(e.target.checked);
    });

    roadGroupSelector.addEventListener('click', function(e) {
      wmeSpeedsLayer.setVisibility(e.target.checked & checkbox.checked);
      checkbox.disabled = !e.target.checked;
    });
  }

  if (localStorage.DrawSegmentSpeeds === 'true') {
    wmeSpeedsLayer.setVisibility(localStorage.DrawSegmentSpeeds === 'true');
  } else {
    wmeSpeedsLayer.setVisibility(false);
  }

  // begin periodic updates
  //window.setInterval(highlightSpeedsSegments,333);

  // trigger code when page is fully loaded, to catch any missing bits
  window.addEventListener("load", function() {
    var mapProblems = getId('map-problems-explanation');
    if (mapProblems !== null) {
      mapProblems.style.display = "none";
    }
  });

  if (W.model.isImperial) {
    wmeSpeedsMiles = true;
  }

  // register some events...
  W.map.events.register("zoomend", null, highlightSpeedsSegments);
  W.map.events.register("changelayer", null, changeLayer);

  //W.map.events.register("movestart", null, highlightSpeedsSegments);
  //W.map.events.register("move", null, highlightSpeedsSegments);
  W.map.events.register("moveend", null, highlightSpeedsSegments);

  W.map.baseLayer.events.register("loadend", null, highlightSpeedsSegments);

  W.model.events.register("mergeend", null, highlightSpeedsSegments);

  //W.vent.on("operationPending", highlightSpeedsSegments);
  W.vent.on("operationDone", highlightSpeedsSegments);

  wmeSpeedsInit = true;

  makeSpeedsTab();

  // restore saved settings
  if (localStorage.WMESpeedsScript) {
    console.log("WME Speeds: Loading Options");
    var options = JSON.parse(localStorage.WMESpeedsScript);

    getId('_wmeSpeedsInvert').checked = options[1];
    getId('_wmeSpeedsNonDrivable').checked = options[2];
    getId('_wmeSpeedsOtherDrivable').checked = options[3];
    getId('_wmeSpeedsTransparentColors').checked = options[4];
    getId('_wmeSpeedsUnverifed').checked = options[5];
    getId('_wmeSpeedsInvertNonDrivable').checked = options[6];
  }

  // overload the WME exit function
  var saveWmeSpeedsOptions = function() {
    if (localStorage) {
      console.log("WME Speeds: Saving Options");
      var options = [];

      // preserve previous options which may get lost after logout
      if (localStorage.WMESpeedsScript) {
        options = JSON.parse(localStorage.WMESpeedsScript);
      }

      options[1] = getId('_wmeSpeedsInvert').checked;
      options[2] = getId('_wmeSpeedsNonDrivable').checked;
      options[3] = getId('_wmeSpeedsOtherDrivable').checked;
      options[4] = getId('_wmeSpeedsTransparentColors').checked;
      options[5] = getId('_wmeSpeedsUnverifed').checked;
      options[6] = getId('_wmeSpeedsInvertNonDrivable').checked;

      localStorage.WMESpeedsScript = JSON.stringify(options);
    }
  };
  //  save options
  window.addEventListener("beforeunload", saveWmeSpeedsOptions, false);

  getId('_wmeSpeedsInvert').onclick = highlightSpeedsSegments;
  getId('_wmeSpeedsNonDrivable').onclick = highlightSpeedsSegments;
  getId('_wmeSpeedsOtherDrivable').onclick = highlightSpeedsSegments;
  getId('_wmeSpeedsTransparentColors').onclick = highlightSpeedsSegments;
  getId('_wmeSpeedsUnverifed').onclick = highlightSpeedsSegments;
  getId('_wmeSpeedsInvertNonDrivable').onclick = highlightSpeedsSegments;

  //initial highlight
  highlightSpeedsSegments();
}

/* engage! =================================================================== */
initialiseSpeedsHighlights();

})();
/* end ======================================================================= */