<script>

proj4.defs('EPSG:3413', '+proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 ' +
          '+x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs');
proj4.defs('EPSG:3031', '+proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs');

var GOCIhour="00"
function updatehour(el){
    var hour=el.value;
    GOCIhour=hour;
    urlTemplateTC = urlTemplateGOCI.replace('{h}', GOCIhour);
    trueSource.refresh();
    updateProducts();
    updatePermalink();    
    $('.btn').css({ 'background': '#808080' } );
    el.style.background = '#FFFFFF';
}

//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

var popup_container = document.getElementById('popup');
var popup_content = document.getElementById('popup-content');
var popup_closer = document.getElementById('popup-closer');


popup_closer.onclick = function() {
  popup_overlay.setPosition(undefined);
  popup_closer.blur();
  return false;
};


var popup_overlay = new ol.Overlay(/** @type {olx.OverlayOptions} */ ({
  element: popup_container,
  autoPan: true,
  autoPanAnimation: {
    duration: 250
  }
}));


//////////////////////////////////////////////////////////////////////////////
///// Following time functions are used to help updating L2 products    //////
///// 8-day average requires calculation to get the right time interval //////
//////////////////////////////////////////////////////////////////////////////

function bodyResizeFunction() {
    var h1 = window.innerHeight;
    var w1 = Math.round(window.innerWidth*0.08);
    var ha = document.getElementById("algo_panel").getBoundingClientRect().top;
    var hl = document.getElementById("date-panel").getBoundingClientRect().top;
    var h6 = hl - ha + 65;
    var h = h1 - h6;
    if(h<h6) h = h6;
    $('div#map').height(h);

    // update button group position
    var top1 = h - 70;
    $('#hourbuttons').css( {top: top1} );
    $('.btn').css({ width: w1} );
    if(w1<60) $('.btn[value=08]').css({ width: 60} );

    // now update color bar legend height
    h = h - 100;
    if(h>520) h = 520;
    $('#legend').height(h);
}


//////////////////////////////////////////////////////////////////////////////
function dateToDayOfYear(d) {   // d is a Date object
    var yn = d.getFullYear();
    var mn = d.getMonth();
    var dn = d.getDate();
    var d1 = new Date(yn,0,1,12,0,0); // noon on Jan. 1
    var d2 = new Date(yn,mn,dn,12,0,0); // noon on input date
    var ddiff = Math.round((d2-d1)/864e5);
    return ddiff+1; 
};

//////////////////////////////////////////////////////////////////////////////
function dayOfYearToDate(year, day) {

    var firstDate = new Date(year, 0, 1, 12, 0, 0); // jan. 1, noon
    var newDate   = new Date(firstDate.getTime() +  86400000*(day-1));
    
    return newDate;
};

//////////////////////////////////////////////////////////////////////////////
function eightdaystr(date) {
    var year = date.getFullYear();
    var day = dateToDayOfYear(date);
    var dayn = dateToDayOfYear(new Date(year, 11, 31, 12, 0, 0));
    var day1 = Math.floor(((day-1)/8)) * 8 + 1;
    var day2 = day1 + 7;
    if(day2>dayn) day2 = dayn;
    date1 = dayOfYearToDate(year, day1);
    date2 = dayOfYearToDate(year, day2);
    mo1 = date1.getMonth() + 1;
    if (mo1<10) mo1 = '0' + mo1;
    mo2 = date2.getMonth() + 1;
    if (mo2<10) mo2 = '0' + mo2;
    d1 = date1.getDate();
    if(d1<10) d1 = '0' + d1;
    d2 = date2.getDate();
    if(d2<10) d2 = '0' + d2;

    eigthdayfile = year.toString() + '_' + mo1 + d1 + '_' + mo2 + d2;
    return eigthdayfile;
};
//////////////////////////////////////////////////////////////////////////////

var unitsnames = { chl:    "mg/m&sup3;",
                   k490:   "m<sup>-1</sup>", 
                   kpar:   "m<sup>-1</sup>", 
                   nLw400: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw412: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw445: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)",  
                   nLw488: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw510: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw555: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw620: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw638ag: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw638_hr:"mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw665: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw672: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw681: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw709: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw746: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw779: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw865: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw885: "mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   nLw1020:"mW/(cm&sup2;&nbsp;&micro;m&nbsp;sr)", 
                   par:    "E/(m&sup2;&nbsp;day)", 
                   a445:   "m<sup>-1</sup>", 
                   aph445: "m<sup>-1</sup>", 
                   adg445: "m<sup>-1</sup>", 
                   bb445:  "m<sup>-1</sup>", 
                   bbp445: "m<sup>-1</sup>", 
                   a555:   "m<sup>-1</sup>", 
                   bb555:  "m<sup>-1</sup>",
                   chl_oci:"mg/m&sup3;",
                   chl_nn: "mg/m&sup3;",
                   adg_443:"m<sup>-1</sup>", 
                   tsm_nn: "g/m&sup3;",
                   qa_score:"",
                   d61chl:   "mg/m&sup3;",
                   d61pchl:  ""
};

var VIIRSprods = {
          chl:     "Chl-a",
          k490:    "Kd(490)",
          kpar:    "Kd(par)",
          nLw412:  "nLw(410)",
          nLw445:  "nLw(443)",
          nLw488:  "nLw(486)",
          nLw555:  "nLw(551)",
          nLw638ag:"nLw(638)",
          nLw672:  "nLw(671)",
          nLw746:  "nLw(745)",
          nLw865:  "nLw(862)"
};

var VIIRSJ1prods = {
          chl:     "Chl-a",
          k490:    "Kd(490)",
          kpar:    "Kd(par)",
          nLw412:  "nLw(411)",
          nLw445:  "nLw(445)",
          nLw488:  "nLw(489)",
          nLw555:  "nLw(556)",
          nLw638ag:"nLw(642)",
          nLw672:  "nLw(667)",
};

var VIIRSMIXprods = {
          chl:     "Chl-a",
          k490:    "Kd(490)",
          kpar:    "Kd(par)",
};

var VIIRSexpprods = {
          par:       "PAR",
          a445:      "a(443)",
          aph445:    "a_ph(443)",
          adg445:    "a_dg(443)",
          bb445:     "b_b(443)",
          bbp445:    "b_bp(443)",
          a555:      "a(551)",
          bb555:     "b_b(551)",
          chl_oci:   "Chl-a_OCI",
          chl_oci_l2:"Chl-a_OCI_L2",
          qa_score:  "QA score",
          nLw638_hr:  "nLw(638) HR"
};

var VIIRSJ1expprods = {
          par:       "PAR",
          qa_score:  "QA score",
          nLw638_hr:  "nLw(642) HR"
};

var VIIRSuserprods = {
          d61chl:    "Chl-a anom.",
          d61pchl:   "Chl-a anom. ratio"
};

var OLCIprods = {
          chl:     "Chl-a",
          k490:    "Kd(490)",
          nLw400:  "nLw(400)",
          nLw412:  "nLw(413)",
          nLw445:  "nLw(443)",
          nLw488:  "nLw(490)",
          nLw510:  "nLw(510)",
          nLw555:  "nLw(560)",
          nLw620:  "nLw(620)",
          nLw665:  "nLw(665)",
          nLw672:  "nLw(674)",
          nLw681:  "nLw(681)",
          nLw709:  "nLw(709)",
          nLw746:  "nLw(754)", // will restore later when data are available
          nLw779:  "nLw(779)",
          nLw865:  "nLw(865)",
          nLw885:  "nLw(885)",
          nLw1020: "nLw(1020)"
};

var OLCIexpprods = {
          chl_nn:    "Chl-a [NN]",
          tsm_nn:    "TSM [NN]",
          adg_443:   "a_dg(443) [NN]",
          qa_score:  "QA score"
};

var GOCIprods = {
          chl:     "Chl-a",
          k490:    "Kd(490)",
          nLw412:  "nLw(412)",
          nLw445:  "nLw(443)",
          nLw488:  "nLw(490)",
          nLw555:  "nLw(555)",
          nLw660:  "nLw(660)",
          nLw680:  "nLw(680)",
          nLw745:  "nLw(745)",
          nLw865:  "nLw(865)",
          qa_score: "QA score"
};
var lastVIIRSalgo = "noaa_msl12_nrt";
var lastOLCIalgo  = "esa_olci_nrt";

var lookuparr;
var lookupenabled = false;
var lookupupdated = false;

//////////////////////////////////////////////////////////////////////////////
///// set up  default zoom, center and rotation   ////////////////////////////
//////////////////////////////////////////////////////////////////////////////
var center = [0, 0];
var lat = 0;
var lon = 0;
var prodAlgo;
var prodTAve;
var prodName;
var yyyymmdd;
var dayspast;
var sensor;
var projectionNumber = 4326; // LonLat

var projectionString = "EPSG:" + projectionNumber;
var projection = ol.proj.get(projectionString);
if(projectionNumber==3413) projection.setExtent([-5050747.26, -5050747.26, 5050747.26, 5050747.26]);
if(projectionNumber==3031) projection.setExtent([-5065906.00413311, -5065906.00413311, 5065906.00413311, 5065906.00413311]);
var projectionExtent = projection.getExtent();

var zoom = 1;
var minZoom = 1;
var maxZoom = 9;
if(projectionNumber==4326) {
    zoom = 2;
    minZoom = 2;
    maxZoom = 10;
}

var mintime = 1293901200000; // 2011-01-01 12:00
var lDate = new Date(2010,9,1,12,0,0); // noon on Oct. 1, 2010
var cDate = new Date();
var ndays = Math.floor((cDate.getTime() - lDate.getTime())/86400000);
center[0] = 0; 
if(projectionNumber==4326) center[0] -= 360.0*ndays;
var year  = cDate.getFullYear();
var month = cDate.getMonth() + 1;
if(month<10) month = '0' + month;
var day   = cDate.getDate();
if(day  <10) day   = '0' + day;
yyyymmdd = year.toString() + month + day;

ndays += 2;
var truedays = new Array(ndays);
var proddays = new Array(ndays);
var prodhour = new Array(ndays);
var prod8day = new Array(ndays);
var prodmnth = new Array(ndays);
var prodclim = new Array(ndays);
var prodtime;

var iday;
for(iday=0; iday<ndays; iday++){
    var nDate = new Date(lDate.getTime() + 86400000*iday);
    var yn = nDate.getFullYear();
    var mn = nDate.getMonth() + 1;
    if(mn<10) mn = '0' + mn;
    var dn = nDate.getDate();
    if(dn<10) dn = '0' + dn;
    truedays[iday] = yn.toString() + '/' + yn + mn + dn;
    proddays[iday] = 'daily/' + yn + '/' + yn + mn + dn;
    prodhour[iday] = 'hourly/' + yn + '/' + yn + mn + dn;
    prod8day[iday] = '8_day/' + yn + '/' + eightdaystr(nDate);
    prodmnth[iday] = 'monthly/' + yn + '/' + yn + mn;
    prodclim[iday] = 'climatology';
};

bodyResizeFunction();

//////////////////////////////////////////////////////////////////////////////
///// try to restore the application state from the permalink  ///////////////
//////////////////////////////////////////////////////////////////////////////
if (window.location.hash !== '') {

    var hash = window.location.hash.replace('#', '');
    var parts = hash.split('/');
    var i;

    // set default sensor to VIIRS
    var sensorval = "VIIRS";
    var lastalgo = lastVIIRSalgo;
    var coord1 = [0, 0];

    for(i = 0; i<parts.length; i++){
        var keyval = parts[i].split('=');
        if(keyval.length<2) continue;
        var key = keyval[0];
        var val = keyval[1];
        var yesno;

        switch(key) {

            case "date":
                if(val==="yesterday") {
                    var presentDate = new Date();
                    var yesterDate  = new Date(presentDate.getTime() - 86400000);
                    var yn = yesterDate.getFullYear();
                    var mn = yesterDate.getMonth() + 1;
                    if(mn<10) mn = '0' + mn;
                    var dn = yesterDate.getDate();
                    if(dn<10) dn = '0' + dn;
                    yyyymmdd = yn.toString() + mn + dn;
                }
                else {
                    var idate = parseInt(val);
                    if( (idate > 20100101) && (idate < 21100101)) yyyymmdd = idate.toString();
                }
                break;
            case "hr":
                var ihr = parseInt(val);
                if( (ihr>0) && (ihr<8) ){
                    GOCIhour = "0" + ihr;
                    $('.btn[value="'+ GOCIhour +'"]').css({"background": "#FFFFFF"});
                }
                break;
            case "zoom":
                zoom = parseInt(val);
                break;
            case "lat":
                coord1[1] = parseFloat(val);
                lat = coord1[1];
                break;
            case "lon":
		coord1[0] = parseFloat(val);
                lon = coord1[0];
                break;
            case "tc":
                if(val==="true") yesno = true; else yesno = false;
                document.getElementById("truecolor").checked = yesno;
                break;
            case "l2":
                if(val==="true") yesno = true; else yesno = false;
                document.getElementById("l2product").checked = yesno;
                break;
            case "sens":
                sensorval = val;
                if (sensorval==="OLCIDEV") sensorval = "OLCI";
                break;
            case "algo":
                $("#algo_select").val(val);
                lastalgo = val;
                break;
            case "prod":
                $("#prod_select").val(val);
                break;
            case "proj":
                var ival = parseInt(val);
                if((ival==4326)||(ival==3413)||(ival==3031)){
                    $("#proj_select").val(val);
                    projectionNumber = ival;
                    projectionString = "EPSG:" + projectionNumber;
                    projection = ol.proj.get(projectionString);
                    if(projectionNumber==3413) projection.setExtent([-5050747.26, -5050747.26, 5050747.26, 5050747.26]);
                    if(projectionNumber==3031) projection.setExtent([-5065906.00413311, -5065906.00413311, 5065906.00413311, 5065906.00413311]);
                    projectionExtent = projection.getExtent();
                    if(projectionNumber==4326) {
                        minZoom = 2;
                        maxZoom = 10;
                    } else {
                        minZoom = 1;
                        maxZoom = 9;
                    }
                }
                break;
            case "ave":
                for (var radioCounter = 0 ; radioCounter < document.getElementsByName('timeave').length; radioCounter++) {
                    var val1 = document.getElementsByName('timeave')[radioCounter].value;
                    if(val===val1) { 
                        document.getElementsByName('timeave')[radioCounter].checked = true;
                        break;
                    }
                }
                break;
            case "cbar":
                if(val==="true") yesno = true; else yesno = false;
                document.getElementById("colorbars").checked = yesno;
                break;
            case "gran":
                if(val==="true") yesno = true; else yesno = false;
                document.getElementById("granlines").checked = yesno;
                break;
            case "coast":
                if(val==="true") yesno = true; else yesno = false;
                document.getElementById("coastline").checked = yesno;
                break;
            case "grid":
                if(val==="true") yesno = true; else yesno = false;
                document.getElementById("gridlines").checked = yesno;
                break;
            default:
                break;
        }
        
    }

    var yyyy = parseInt(yyyymmdd.substring(0,4));
    var mm   = parseInt(yyyymmdd.substring(4,6))-1;
    var dd   = parseInt(yyyymmdd.substring(6,8));
    cDate = new Date(yyyy,mm,dd,12,0,0);
    dayspast = Math.round((cDate-lDate)/864e5);

    if(projectionNumber != 4326){
        coord1 = ol.proj.transform(coord1, 'EPSG:4326', projectionString);
    }

    center[0] = coord1[0];
    center[1] = coord1[1];
    if(projectionNumber==4326) center[0] -= 360.0*dayspast;

    if( projectionNumber!=4326) {
        $("#sens_select option[value=GOCI]").attr('disabled', 'disabled');
        if (sensorval=="GOCI") sensorval = "VIIRS";
    }

    $("#sens_select").val(sensorval);
    sensor = sensorval;
    if( (sensor=="VIIRS") || (sensor=="VIIRSJ1") ) lastVIIRSalgo = lastalgo;
    if( (sensor=="OLCI")|| (sensor=="OLCIDEV") ) lastOLCIalgo = lastalgo;


};


//////////////////////////////////////////////////////////////////////////////
//////      attributions                                     /////////////////
//////////////////////////////////////////////////////////////////////////////
var attribution_true  = new ol.Attribution({
    html: 'VIIRS SNPP and NOAA-20 true color and granule boundaries produced from JPSS SNPP VIIRS SDR. '
});

var attribution_OLCI  = new ol.Attribution({
    html: 'Contains modified Copernicus Sentinel data [2016]. OLCI true color and granule boundaries produced from <a href="https://sentinel.esa.int/web/sentinel/missions/sentinel-3/data-products/olci">Sentinel 3 OLCI</a> Level-1 data. '
});

var attribution_GOCI  = new ol.Attribution({
    html: 'GOCI True Color layer derived from GOCI Level-1 data. '
});

var attribution_prod  = new ol.Attribution({
    html: 'Ocean Color data produced by NOAA/NESDIS/STAR Ocean Color group. '
});

var attribution_coast = new ol.Attribution({
    html: 'Shorelines &copy; <a href="http://openstreetmapdata.com/data/generalized-coastlines">OpenStreetMapData</a> <a href="http://openstreetmapdata.com/info/license">(license)</a>. '
});

var attribution_land  = new ol.Attribution({
    html: 'Landmask from <a href="https://lpdaac.usgs.gov/dataset_discovery/modis/modis_products_table/mod44w">USGS LP DAAC</a>. '
});
var attribution_bath  = new ol.Attribution({
    html: 'Bathymetry from <a href="https://www.ngdc.noaa.gov/mgg/global/global.html">NOAA/NESDIS/NCEI Marine Geology and Geophysics</a>. '
});
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
//////      projections and resolutions                      /////////////////
//////////////////////////////////////////////////////////////////////////////
var tileGridLand;
var tileGridTrue;
var tileGridProds;
var tileGridProdsN;
var tileGridProdsH;
var tileGridProdsE;
var tileGridCoast;

var tileSizeLand;
var tileSizeTC;
var tileSizeProds;
var tileSizeCoast;

var resolutionsLand;
var resolutionsTrue;
var resolutionsProds;
var resolutionsProdsH;
var resolutionsCoast;

function setProjRes(){

    if(projectionNumber==4326){
        tileSizeLand  = 1350;
        tileSizeTC    = 512;
        tileSizeProds = 540;
        tileSizeCoast = 1024;

        var nZoomLand  = 6;
        var nZoomTC    = 8;
        var nZoomProds = 5;
        var nZoomProdsH= 7;
        var zZoomCoast = 8;
    }
    else {
        tileSizeLand  = 1024;
        tileSizeTC    = 512;
        tileSizeProds = 512;
        tileSizeCoast = 1024;

        var nZoomLand  = 6;
        var nZoomTC    = 7;
        var nZoomProds = 4;
        var nZoomProdsH= 6;
        var zZoomCoast = 8;
    }

    // resolutions for landmask
    var maxResolutionLand = ol.extent.getHeight(projectionExtent) / tileSizeLand;
    resolutionsLand = new Array(nZoomLand);
    for (z = 0; z < nZoomLand; ++z) {
        resolutionsLand[z] = maxResolutionLand / Math.pow(2, z);
    }

    // resolutions for enhanced TC 
    var maxResolutionTC = ol.extent.getHeight(projectionExtent) / tileSizeTC;
    resolutionsTrue = new Array(nZoomTC);
    for (z = 0; z < nZoomTC; ++z) {
        resolutionsTrue[z] = maxResolutionTC / Math.pow(2, z);
    };

    // resolutions for L2 products
    var maxResolutionProds = ol.extent.getHeight(projectionExtent) / tileSizeProds;
    resolutionsProds = new Array(nZoomProds);
    for (z = 0; z < nZoomProds; ++z) {
        resolutionsProds[z] = maxResolutionProds / Math.pow(2, z);
    }

    // resolutions for L2 products are different
    var maxResolutionProdsH = ol.extent.getHeight(projectionExtent) / tileSizeProds;
    resolutionsProdsH = new Array(nZoomProdsH);
    for (z = 0; z < nZoomProdsH; ++z) {
        resolutionsProdsH[z] = maxResolutionProdsH / Math.pow(2, z);
    }

    // resolutions for coastlines are different
    var maxResolutionCoast = ol.extent.getHeight(projectionExtent) / tileSizeCoast;
    resolutionsCoast = new Array(zZoomCoast);
    for (z = 0; z < zZoomCoast; ++z) {
        resolutionsCoast[z] = maxResolutionCoast / Math.pow(2, z);
    }


    tileGridLand = new ol.tilegrid.TileGrid({
        origin: ol.extent.getTopLeft(projectionExtent),
        resolutions: resolutionsLand,
        tileSize: tileSizeLand
    });

    tileGridTrue = new ol.tilegrid.TileGrid({
        origin: ol.extent.getTopLeft(projectionExtent),
        resolutions: resolutionsTrue,
        tileSize: tileSizeTC
    });

    tileGridProdsN = new ol.tilegrid.TileGrid({
        origin: ol.extent.getTopLeft(projectionExtent),
        resolutions: resolutionsProds,
        tileSize: tileSizeProds
    });

    tileGridProdsH = new ol.tilegrid.TileGrid({
        origin: ol.extent.getTopLeft(projectionExtent),
        resolutions: resolutionsProdsH,
        tileSize: tileSizeProds
    });

    tileGridProdsE = new ol.tilegrid.TileGrid({
        origin: ol.extent.getTopLeft(projectionExtent),
        resolutions: resolutionsTrue,
        tileSize: tileSizeTC
    });

    tileGridCoast = new ol.tilegrid.TileGrid({
        origin: ol.extent.getTopLeft(projectionExtent),
        resolutions: resolutionsCoast,
        tileSize: tileSizeCoast
    });

};

setProjRes();
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
//////      template strings for data locations              /////////////////
//////////////////////////////////////////////////////////////////////////////
var urlTemplateTC; 
var urlTemplateOLCI;
var urlTemplateGOCI;
var urlTemplateVIIRS;

var urlTemplateGranG;
var urlTemplateGrid;
var urlTemplateCoast;
var urlTemplateLand;
var urlTemplateMask;
var urlTemplateBath;

var urlTemplateProd;
var urlTemplateProdG;
var urlTemplateProdE;
var urlTemplateProdH;

function setUrlTemplates(){

    if(projectionNumber==4326){ // LonLat
        urlTemplateOLCI  = './OLCI/truecolor/{d}/{z}/{y}_{x}.png';
        urlTemplateGOCI  = './GOCI/truecolor/{d}/{h}/{z}/{y}_{x}.png';
        urlTemplateVIIRS = './{sens}/truecolor_enh/{d}/{z}/{y}_{x}.png';

        urlTemplateGranG = './{sens}/granules/{d}.geojson';
        urlTemplateGrid  = './gridlines/LonLat/{z}/{y}_{x}.geojson';
        urlTemplateCoast = './coastlines/tiles3/{z}/c_{x}_{y}.png';
        urlTemplateLand  = './landmask/v3/{z}/{y}_{x}.png';
        urlTemplateMask  = './landmask/v3/{z}/{y}_{x}.png';
        urlTemplateBath  = './bathymetry/vA/{z}/{y}_{x}.png';
        urlTemplateProdG = './{sens}/l2products/{algo}/{prod}/{d}/{z}/{y}_{x}.png';
        urlTemplateProdE = '../../../../data/socd2/mecb/color/ocview/{sens}/l2products/{algo}/{prod}/{d}/{z}/{y}/{y}_{x}.png';
        urlTemplateProdH = '../../../../data/socd2/mecb/color/ocview/{sens}/l2products/{algo}/{prod}/{d}/{h}/{z}/{y}_{x}.png';
    }

    if(projectionNumber==3413){ // ARCTIC
        urlTemplateOLCI  = '../../../../data/socd2/mecb/color/ocview/{sens}/truecolor_ARCTIC/{d}/{z}/{y}_{x}.png';
        urlTemplateGOCI  = './nowhere/';
        urlTemplateVIIRS = '../../../../data/socd2/mecb/color/ocview/{sens}/truecolor_ARCTIC/{d}/{z}/{y}_{x}.png';

        urlTemplateGranG = './{sens}/granules/{d}_1.geojson';
        urlTemplateGrid  = './gridlines/arctic/{z}/{y}_{x}.geojson';
        urlTemplateCoast = './coastlines_ARCTIC/tiles3/{z}/c_{x}_{y}.png';
        urlTemplateLand  = './landmask_arctic/v3/{z}/{y}_{x}.png';
        urlTemplateMask  = './landmask_arctic/v3/{z}/{y}_{x}.png';
        urlTemplateBath  = './bathymetry_arctic/vA/{z}/{y}_{x}.png';
      //urlTemplateProdG = './{sens}/l2products/{algo}_arctic/{prod}/{d}/{z}/{y}/{y}_{x}.png';
        urlTemplateProdG = '../../../../data/socd2/mecb/color/ocview/{sens}/l2products/{algo}_arctic/{prod}/{d}/{z}/{y}/{y}_{x}.png';
        urlTemplateProdE = '../../../../data/socd2/mecb/color/ocview/{sens}/l2products/{algo}_ARCTIC/{prod}/{d}/{z}/{y}/{y}_{x}.png';
        urlTemplateProdH = './nowhere/';
    }

    if(projectionNumber==3031){ // ANTARCTIC
        urlTemplateOLCI  = '../../../../data/socd2/mecb/color/ocview/{sens}/truecolor_ANTARCTIC/{d}/{z}/{y}_{x}.png';
        urlTemplateGOCI  = './nowhere/';
        urlTemplateVIIRS = '../../../../data/socd2/mecb/color/ocview/{sens}/truecolor_ANTARCTIC/{d}/{z}/{y}_{x}.png';
        urlTemplateGranG = './{sens}/granules/{d}_1.geojson';
        urlTemplateGrid  = './gridlines/antarctic/{z}/{y}_{x}.geojson';
        urlTemplateCoast = './coastlines_ANTARCTIC/tiles3/{z}/c_{x}_{y}.png';
        urlTemplateLand  = './landmask_antarctic/v3/{z}/{y}_{x}.png';
        urlTemplateMask  = './landmask_antarctic/v3/{z}/{y}_{x}.png';
        urlTemplateBath  = './bathymetry_antarctic/vA/{z}/{y}_{x}.png';
      //urlTemplateProdG = './{sens}/l2products/{algo}_antarctic/{prod}/{d}/{z}/{y}/{y}_{x}.png';
        urlTemplateProdG = '../../../../data/socd2/mecb/color/ocview/{sens}/l2products/{algo}_antarctic/{prod}/{d}/{z}/{y}/{y}_{x}.png';
        urlTemplateProdE = '../../../../data/socd2/mecb/color/ocview/{sens}/l2products/{algo}_ANTARCTIC/{prod}/{d}/{z}/{y}/{y}_{x}.png';
        urlTemplateProdH = './nowhere/';
    }
};

setUrlTemplates();
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/////     landmask layer                                          ////////////
//////////////////////////////////////////////////////////////////////////////
var parseUrlLand = function(tileCoord, pixelRatio, projection) {
    var z = tileCoord[0];
    var x = tileCoord[1];
    var y = -tileCoord[2] - 1;

    if(projectionNumber==4326) {
        var n = Math.pow(2, z + 1); // 2 tiles at z=0
        x = x % n;
        if (x < 0) { x = x + n; }
    }

    return urlTemplateLand.replace('{z}', z.toString())
                          .replace('{y}', y.toString())
                          .replace('{x}', x.toString());
};
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/////   Enhanced Resolution True Color layer                      ////////////
//////////////////////////////////////////////////////////////////////////////
var parseUrlTrue = function(tileCoord, pixelRatio, projection) {
    var z = tileCoord[0];
    var x = tileCoord[1];
    var y = -tileCoord[2] - 1;

    var q = dayspast;
    if(projectionNumber==4326) {
        var n = Math.pow(2, z + 1); // 2 tiles at z=0
        q = -Math.floor(x/n);   // how many days past the reference day
        x = x % n;
        if (x < 0) x = x + n;
    }
 
    return    urlTemplateTC.replace('{d}', truedays[q])
                           .replace('{z}', z.toString())
                           .replace('{y}', y.toString())
                           .replace('{x}', x.toString());
};
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//////      L2 products layer                                /////////////////
//////////////////////////////////////////////////////////////////////////////
var parseUrlProds = function(tileCoord, pixelRatio, projection) {
    var z = tileCoord[0];
    var x = tileCoord[1];
    var y = -tileCoord[2] - 1;

    var q = dayspast;
    if(projectionNumber==4326) {
        var n = Math.pow(2, z + 1); // 2 tiles at z=0
        q = -Math.floor(x/n);   // how many days past the reference day
        x = x % n;
        if (x < 0) x = x + n;
    } 

    return urlTemplateProd.replace('{d}', prodtime[q])
                          .replace('{z}', z.toString())
                          .replace(/{y}/g, y.toString())
                          .replace('{x}', x.toString());
};
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/////     coastlines layer                                        ////////////
//////////////////////////////////////////////////////////////////////////////
var parseUrlCoast = function(tileCoord, pixelRatio, projection) {
    var z = tileCoord[0];
    var x = tileCoord[1];
    var y = -tileCoord[2] - 1;

    if(projectionNumber==4326) {
        var n = Math.pow(2, z + 1); // 2 tiles at z=0
        x = x % n;
        if (x < 0) { x = x + n; }
    }

    return urlTemplateCoast.replace('{z}', z.toString())
                           .replace('{y}', y.toString())
                           .replace('{x}', x.toString());
};
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/////     gridlines  layer                                        ////////////
//////////////////////////////////////////////////////////////////////////////
function lineStyleFunction(feature, resolution) {
//  var ftype = feature.get('name');
//  console.log("ftype = " + ftype);
//  if(ftype!="MOBY") {
    return new ol.style.Style({
        stroke: new ol.style.Stroke({
            color: '#202020',
            width: 1,
            lineDash : [3,3]
        }),
        image: new ol.style.Circle({
            radius: 10,
            fill: new ol.style.Fill({color: 'rgba(255, 0, 0, 0.1)'}),
            stroke: new ol.style.Stroke({color: 'red', width: 1})
        }),
        text: new ol.style.Text({
            textAlign: "center",
            textBaseline: "middle",
            font: "bold 18px Courier New",
            text: feature.get('name'),
            fill: new ol.style.Fill({color: "#000000"}),
            stroke: new ol.style.Stroke({color: "#ffffff", width: 2}),
            offsetX: 0,
            offsetY: 0,
            placement: "line",
            maxAngle: 2.0943951023931953,
            overflow: "false",
            rotation: 0.0
        })
    });
/*
  }
  else {
        return new ol.style.Style({
          image: new ol.style.Circle({
            radius: 10,
            fill: new ol.style.Fill({color: 'rgba(255, 0, 0, 0.1)'}),
            stroke: new ol.style.Stroke({color: 'red', width: 1})
          }),
          text: feature.get('name')
        });
  }
*/
}
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/////    Granule boundaries layer                                  ///////////
//////////////////////////////////////////////////////////////////////////////
var granStyle = new ol.style.Style({
    fill: new ol.style.Fill({
        color: 'rgba(255, 255, 255, 0.5)'
    }),
    stroke: new ol.style.Stroke({
        color: '#7F7FFF',
        width: 1
    })
});

//////////////////////////////////////////////////////////////////////////////
var vectorSource;
var granLayer;
if(projectionNumber==4326) granLayer = new ol.layer.Image({});
else                       granLayer = new ol.layer.Vector({});
var nDaysPastgran = 0;

//////////////////////////////////////////////////////////////////////////////
function updateGranules(){
    // if granule layer is nota enable, do nothing
    if (document.getElementById("granlines").checked===false) return;

    // calculate the current visible day
    if(projectionNumber==4326) {
        var center = mapview.getCenter();
        dayspast = -Math.floor( (center[0] + 180.0)/360.0 );
    } 
    else {
        dayspast = Math.round((cDate-lDate)/864e5);
    }
 
    var sensval = $("#sens_select").val();

    // if we already have the right day, do nothing
    if((dayspast===nDaysPastgran)&&(sensor===sensval)) return;
  
    nDaysPastgran = dayspast;  
    sensor = sensval;
    var urlpath = urlTemplateGranG.replace('{sens}', sensval).replace('{d}', truedays[dayspast]);

    vectorSource =  new ol.source.Vector({
        url: urlpath,
        format: new ol.format.GeoJSON()
    });

    map.removeLayer(granLayer);

    if(projectionNumber==4326) {
        granLayer = new ol.layer.Image({
            source: new ol.source.ImageVector({
                source: vectorSource,
                projection: projection,
                style: granStyle
            }),
            visible: document.getElementById("granlines").checked
        });
    }
    else {
        granLayer = new ol.layer.Vector({
            source: vectorSource,
            projection: projection,
            style: granStyle,
            visible: document.getElementById("granlines").checked
        });
    }

    map.addLayer(granLayer);

    // remove highlighted granule if any
    if ( (highlight) && (highlight.getId().length > 0) ) {
        featureOverlay.getSource().removeFeature(highlight);
        highlight = undefined;
    }

};
//////////////////////////////////////////////////////////////////////////////


var landSource;
var trueSource;
var prodSource;
var coastSource;
var gridSource;
var wrapgrid;

var landLayer;
var trueTile;
var prodTile;
var coastLayer;
var gridLayer;

function setSourcesLayers(){

    landSource = new ol.source.TileImage({
        attributions: [attribution_land],
        tileUrlFunction: parseUrlLand,
        projection: projection,
        wrapX: false,
        tileGrid: tileGridLand
    });

    trueSource = new ol.source.TileImage({
        attributions: [attribution_true],
        tileUrlFunction: parseUrlTrue,
        projection: projection,
        wrapX: false,
        transition: 0,
        tileGrid: tileGridTrue
    });

    prodSource = new ol.source.TileImage({
        attributions: [attribution_prod],
        tileUrlFunction: parseUrlProds,
        projection: projection,
        wrapX: false,
        tileGrid: tileGridProdsN
    });

    coastSource = new ol.source.TileImage({
        attributions: [attribution_coast],
        tileUrlFunction: parseUrlCoast,
        projection: projection,
        wrapX: false,
        tileGrid: tileGridCoast
    });

    wrapgrid = false;
    if(projectionNumber==4326) wrapgrid = true;

    gridSource = new ol.source.VectorTile({
        url: urlTemplateGrid,
        projection: projection,
        wrapX: wrapgrid,
        format: new ol.format.GeoJSON()
    });


    landLayer = new ol.layer.Tile({
        source: landSource,
        useInterimTilesOnError: false,
        visible: true
    });

    trueTile = new ol.layer.Tile({
        source: trueSource,
        useInterimTilesOnError: false,
        visible: document.getElementById("truecolor").checked
    });

    prodTile = new ol.layer.Tile({
        source: prodSource,
        useInterimTilesOnError: false,
        visible: document.getElementById("l2product").checked
    });

    coastLayer = new ol.layer.Tile({
        source: coastSource,
        useInterimTilesOnError: false,
        visible: document.getElementById('coastline').checked
    });

    gridLayer = new ol.layer.VectorTile({
        source: gridSource,
        style: lineStyleFunction,
        visible: document.getElementById('gridlines').checked
    });
};

setSourcesLayers();


//////////////////////////////////////////////////////////////////////////////
var updateColorbar = function () {

    var cbval = document.getElementById("colorbars").checked;
    var l2val = document.getElementById("l2product").checked;
    var legendid = document.getElementById('legend');
    var prodval = $("#prod_select").val();
    if ((cbval === true) && (l2val === true)){
        // var pc = Math.round($(window).height()/10);
        legendid.innerHTML = "<img src='./VIIRS/l2products/colorbars/" + prodval + "_colorbar.png' style='height:100%;' />";
    }
    else{
        legendid.innerHTML = '&nbsp';
    }

};
//////////////////////////////////////////////////////////////////////////////

var updateLookupArr = function () {

    lookupupdated = false;
    var prodval = $("#prod_select").val();
    var lookupurl = "./VIIRS/l2products/colorbars/" + prodval + "_lookup.json";
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            lookuparr = JSON.parse(xmlhttp.responseText);
            lookupupdated = true;
        }
    }

    xmlhttp.open("GET", lookupurl, true);
    xmlhttp.send();

};

//////////////////////////////////////////////////////////////////////////////
var updateLookup = function ( x, y, red, green, blue, xmax) {

    var lookuptxt = document.getElementById('lookup');
    var info = document.getElementById('granuleindicator');
    if ( (red===green) && (green===blue) )  {
        lookuptxt.innerHTML = "";
        info.innerHTML = "";
        return;
    }
    else {
        var i, ibest, rgbdiff, minrgbdiff, value, r, g, b;
        ibest = 0;
        minrgbdiff = 100000;
        value = 0.0;
        for (i=0; i<lookuparr.length; i++) {
            r = lookuparr[i].red;
            g = lookuparr[i].green;
            b = lookuparr[i].blue;
            rgbdiff = Math.abs(r - red  ) +
                      Math.abs(g - green) +
                      Math.abs(b - blue );
            if (minrgbdiff>rgbdiff) {
                minrgbdiff = rgbdiff;
                ibest = i;
                value = lookuparr[i].val;
            }
        }

        var prodval = $("#prod_select").val();
        var prodtxt = $("#prod_select option:selected").text();
        var units = unitsnames[prodval];
        // lookuptxt.innerHTML = value + " " + units + "  " + ibest + " " + minrgbdiff;
        if ( ibest === (lookuparr.length - 1) ) value = "&ge;" + value;
        lookuptxt.innerHTML = value + "&nbsp;" + units;
        info.innerHTML = prodtxt + " = " + lookuptxt.innerHTML;
        var px = x + 10;
        var py = y - 30;
        if (py<0) py = 0;
        if ( px > ( xmax - 10 - $("#lookup").outerWidth() ) ) px = xmax - 10 - $("#lookup").outerWidth();
        $('#lookup').css({top: py + 'px'});
        $('#lookup').css({left: px + 'px'});
    }
    
};


//////////////////////////////////////////////////////////////////////////////
var updateProducts = function () {

    var projval = $("#proj_select").val();
    var sensval = $("#sens_select").val();
    var algoval = $("#algo_select").val();
    var prodval = $("#prod_select").val();
    var l2val = document.getElementById("l2product").checked;

    var list = $("#prod_select");

    list.empty().append($("<optgroup></optgroup>").attr("label","OC data products:")).append($("<optgroup></optgroup>").attr("label","Primary:")); 
    // if( (sensval=="VIIRS") || (sensval=="VIIRSJ1") ) {
    if( (sensval=="VIIRS") ) {

        $.each(VIIRSprods, function(key, value) {
            list.append($("<option/>", { value: key,  text: value}));
        });

        list.append($("<optgroup></optgroup>").attr("label","Experimental:")); 
        $.each(VIIRSexpprods, function(key, value) {
            list.append($("<option/>", { value: key,  text: value}));
        });

        list.append($("<optgroup></optgroup>").attr("label","User specific:")); 
        $.each(VIIRSuserprods, function(key, value) {
            list.append($("<option/>", { value: key,  text: value}));
        });

        if ( prodval in VIIRSprods) {
           list.val(prodval);
        }
        if ( prodval in VIIRSexpprods) {
           list.val(prodval);
        }
        if ( prodval in VIIRSuserprods) {
           list.val(prodval);
        }
        if ( prodval == "nLw400" ) { $("#prod_select option[value=nLw412]").attr('selected', 'selected');  }
        if ( prodval == "nLw510" ) { $("#prod_select option[value=nLw555]").attr('selected', 'selected');  }
        if ( prodval == "nLw620" ) { $("#prod_select option[value=nLw672]").attr('selected', 'selected');  }
        if ( prodval == "nLw660" ) { $("#prod_select option[value=nLw672]").attr('selected', 'selected');  }
        if ( prodval == "nLw680" ) { $("#prod_select option[value=nLw672]").attr('selected', 'selected');  }
        if ( prodval == "nLw681" ) { $("#prod_select option[value=nLw672]").attr('selected', 'selected');  }
        if ( prodval == "nLw709" ) { $("#prod_select option[value=nLw672]").attr('selected', 'selected');  }
        if ( prodval == "nLw779" ) { $("#prod_select option[value=nLw865]").attr('selected', 'selected');  }
        if ( prodval == "nLw885" ) { $("#prod_select option[value=nLw865]").attr('selected', 'selected');  }
        if ( prodval == "nLw1020") { $("#prod_select option[value=nLw865]").attr('selected', 'selected');  }

        prodval = $("#prod_select").val();

        lastVIIRSalgo = algoval;
    }

    if( sensval=="VIIRSJ1" ) {

        $.each(VIIRSJ1prods, function(key, value) {
            list.append($("<option/>", { value: key,  text: value}));
        });

        list.append($("<optgroup></optgroup>").attr("label","Experimental:")); 
        $.each(VIIRSJ1expprods, function(key, value) {
            list.append($("<option/>", { value: key,  text: value}));
        });

        if ( prodval in VIIRSJ1prods) {
           list.val(prodval);
        }
        if ( prodval in VIIRSJ1expprods) {
           list.val(prodval);
        }

        if ( prodval == "nLw400" ) { $("#prod_select option[value=nLw412]").attr('selected', 'selected');  }
        if ( prodval == "nLw510" ) { $("#prod_select option[value=nLw555]").attr('selected', 'selected');  }
        if ( prodval == "nLw620" ) { $("#prod_select option[value=nLw672]").attr('selected', 'selected');  }
        if ( prodval == "nLw660" ) { $("#prod_select option[value=nLw672]").attr('selected', 'selected');  }
        if ( prodval == "nLw680" ) { $("#prod_select option[value=nLw672]").attr('selected', 'selected');  }
        if ( prodval == "nLw681" ) { $("#prod_select option[value=nLw672]").attr('selected', 'selected');  }
        if ( prodval == "nLw709" ) { $("#prod_select option[value=nLw672]").attr('selected', 'selected');  }
        if ( prodval == "nLw779" ) { $("#prod_select option[value=nLw865]").attr('selected', 'selected');  }
        if ( prodval == "nLw885" ) { $("#prod_select option[value=nLw865]").attr('selected', 'selected');  }
        if ( prodval == "nLw1020") { $("#prod_select option[value=nLw865]").attr('selected', 'selected');  }

        prodval = $("#prod_select").val();

        lastVIIRSalgo = algoval;
    }

    if( sensval=="VIIRSMIX" ) {

        $.each(VIIRSMIXprods, function(key, value) {
            list.append($("<option/>", { value: key,  text: value}));
        });

        if ( prodval in VIIRSMIXprods) {
           list.val(prodval);
        }

        prodval = $("#prod_select").val();

        lastVIIRSalgo = algoval;
    }

    if( (sensval=="VIIRS") || (sensval=="VIIRSJ1") || (sensval=="VIIRSMIX") ) {
        if ( ( algoval == "noaa_msl12_bmw" ) || ( algoval == "noaa_msl12_idps_nrt2" ) || ( algoval == "noaa_msl12_nrt" ) ) {
            $("#prod_select option[value=nLw746]").attr('disabled', 'disabled');
            $("#prod_select option[value=nLw865]").attr('disabled', 'disabled');
            $("#prod_select option[value=par]").attr('disabled', 'disabled');
            $("#prod_select option[value=chl_oci_l2]").attr('disabled', 'disabled');
            $("#prod_select option[value=nLw638_hr]").attr('disabled', 'disabled');

            $("#prod_select option[value=nLw746]").removeAttr('selected');
            $("#prod_select option[value=nLw865]").removeAttr('selected');
            $("#prod_select option[value=par]").removeAttr('selected');
            $("#prod_select option[value=chl_oci_l2]").removeAttr('selected');
            $("#prod_select option[value=nLw638_hr]").removeAttr('selected');

            if ( ( prodval == "par" ) || ( prodval == "chl_oci_l2" ) ) {
                $("#prod_select option[value=chl]").attr('selected', 'selected');
                prodval = $("#prod_select").val();
            }
            if ( ( prodval == "nLw746" ) || ( prodval == "nLw865" ) ) {
                $("#prod_select option[value=nLw672]").attr('selected', 'selected');
                prodval = $("#prod_select").val();
            }
            if ( prodval == "nLw638_hr" ) {
                $("#prod_select option[value=nLw638ag]").attr('selected', 'selected');
                prodval = $("#prod_select").val();
            }

            $("#prod_select option[value=d61chl]").removeAttr('disabled');
            $("#prod_select option[value=d61pchl]").removeAttr('disabled');
        }
        if ( algoval == "noaa_msl12_swir" ) {
            $("#prod_select option[value=nLw746]").removeAttr('disabled');
            $("#prod_select option[value=nLw865]").removeAttr('disabled');
            $("#prod_select option[value=chl_oci_l2]").removeAttr('disabled');
            $("#prod_select option[value=par]").attr('disabled', 'disabled');
            $("#prod_select option[value=par]").removeAttr('selected');
            $("#prod_select option[value=nLw638_hr]").attr('disabled', 'disabled');
            $("#prod_select option[value=nLw638_hr]").removeAttr('selected');
            $("#prod_select option[value=d61chl]").attr('disabled', 'disabled');
            $("#prod_select option[value=d61chl]").removeAttr('selected');
            $("#prod_select option[value=d61pchl]").attr('disabled', 'disabled');
            $("#prod_select option[value=d61pchl]").removeAttr('selected');
            if ( ( prodval == "d61chl" ) || ( prodval == "d61pchl" ) ) {
                $("#prod_select option[value=chl]").attr('selected', 'selected');
                prodval = $("#prod_select").val();
            }
            if ( prodval == "par" ) {
                $("#prod_select option[value=chl]").attr('selected', 'selected');
                prodval = $("#prod_select").val();
            }
            if ( prodval == "nLw638_hr" ) {
                $("#prod_select option[value=nLw638ag]").attr('selected', 'selected');
                prodval = $("#prod_select").val();
            }
        }
        if ( algoval == "noaa_msl12_nsw" ) {
            $("#prod_select option[value=d61chl]").attr('disabled', 'disabled');
            $("#prod_select option[value=d61chl]").removeAttr('selected');
            $("#prod_select option[value=d61pchl]").attr('disabled', 'disabled');
            $("#prod_select option[value=d61pchl]").removeAttr('selected');
            if ( ( prodval == "d61chl" ) || ( prodval == "d61pchl" ) ) {
                $("#prod_select option[value=chl]").attr('selected', 'selected');
                prodval = $("#prod_select").val();
            }

            $("#prod_select option[value=nLw746]").removeAttr('disabled');
            $("#prod_select option[value=nLw865]").removeAttr('disabled');
            $("#prod_select option[value=chl_oci_l2]").removeAttr('disabled');
            $("#prod_select option[value=par]").removeAttr('disabled');
            $("#prod_select option[value=nLw638_hr]").removeAttr('disabled');
        }

    }


    if( (sensval==="OLCI") ) {

        lastOLCIalgo = algoval;

        $.each(OLCIprods, function(key, value) {
            list.append($("<option/>", { value: key,  text: value}));
        });

        if (prodval in OLCIprods) {
           list.val(prodval);
        }

        list.append($("<optgroup></optgroup>").attr("label","Experimental:"));
        $.each(OLCIexpprods, function(key, value) {
            list.append($("<option/>", { value: key,  text: value}));
        });

        if ( prodval in OLCIexpprods) {
           list.val(prodval);
        }
        else {
            // $("#prod_select option[value=chl]").attr('selected', 'selected');
        }
/*
        if ( ( prodval == "kpar" ) || ( prodval == "par" ) || ( prodval == "a445" ) || ( prodval == "aph445" ) || 
           ( prodval == "adg445" ) || ( prodval == "bb445" ) || ( prodval == "bbp445" ) || ( prodval == "a555" )  || 
           ( prodval == "a555" ) || ( prodval == "bb555" )  || ( prodval == "chl_oci" )  || ( prodval == "chl_oci_l2" ) ){
            $("#prod_select option[value=chl]").attr('selected', 'selected');   
        }
*/
        prodval = $("#prod_select").val();

    }


    if( (sensval==="GOCI") ) {

        $.each(GOCIprods, function(key, value) {
            list.append($("<option/>", { value: key,  text: value}));
        });
        if (prodval in GOCIprods) {
           list.val(prodval);
        }
        if ( prodval == "nLw400" ) { $("#prod_select option[value=nLw412]").attr('selected', 'selected');  }
        if ( prodval == "nLw510" ) { $("#prod_select option[value=nLw555]").attr('selected', 'selected');  }
        if ( prodval == "nLw620" ) { $("#prod_select option[value=nLw680]").attr('selected', 'selected');  }
        if ( prodval == "nLw660" ) { $("#prod_select option[value=nLw680]").attr('selected', 'selected');  }
        if ( prodval == "nLw672" ) { $("#prod_select option[value=nLw680]").attr('selected', 'selected');  }
        if ( prodval == "nLw681" ) { $("#prod_select option[value=nLw680]").attr('selected', 'selected');  }
        if ( prodval == "nLw709" ) { $("#prod_select option[value=nLw680]").attr('selected', 'selected');  }
        if ( prodval == "nLw779" ) { $("#prod_select option[value=nLw865]").attr('selected', 'selected');  }
        if ( prodval == "nLw885" ) { $("#prod_select option[value=nLw865]").attr('selected', 'selected');  }
        if ( prodval == "nLw1020") { $("#prod_select option[value=nLw865]").attr('selected', 'selected');  }

        if ( ( prodval == "kpar" ) || ( prodval == "par" ) || ( prodval == "a445" ) || ( prodval == "aph445" ) || 
           ( prodval == "adg445" ) || ( prodval == "bb445" ) || ( prodval == "bbp445" ) || ( prodval == "a555" )  || 
           ( prodval == "a555" ) || ( prodval == "bb555" )  || ( prodval == "chl_oci" )  || ( prodval == "chl_oci_l2" ) ) {
            $("#prod_select option[value=chl]").attr('selected', 'selected');   
        }

        prodval = $("#prod_select").val();
    }

    // force daily and disable time average for products which are daily only
    if( (sensval=="VIIRSMIX") || (prodval=="nLw638_hr") || (prodval=="d61chl") || (prodval=="d61pchl") ) {
        $("input[type=radio][value=daily]").prop('checked', true);
        $("input[type=radio][value!=daily]").attr('disabled', true).parent('label').addClass('disabled-label');
    } 
    else {
        $("input[type=radio]").attr('disabled', false).parent('label').removeClass('disabled-label');
    }

    urlTemplateProd = urlTemplateProdG.replace('{sens}', sensval)
                                      .replace('{algo}', algoval)
                                      .replace('{prod}', prodval);


    tileGridProds = tileGridProdsN;

    var timeaveval = $('[name="timeave"]:checked').val();

    if(timeaveval==="climatology") {
        prodtime = prodclim;
    }

    if(timeaveval==="monthly") {
        prodtime = prodmnth;
    }

    if(timeaveval==="8_day") { 
        prodtime = prod8day;
    }

    if(timeaveval==="daily") {
        prodtime = proddays;
    }
    
    if(sensval==="GOCI") {
        urlTemplateProd = urlTemplateProdH.replace('{sens}', sensval)
                                          .replace('{algo}', algoval)
                                          .replace('{prod}', prodval)
                                          .replace('{h}',   GOCIhour);

        tileGridProds = tileGridProdsH;
        if(timeaveval==="daily") prodtime = prodhour;
    }
    else if( ((sensval=="VIIRS")||(sensval=="VIIRSJ1")) &&(prodval.substr(-3)=="_hr")) {
        urlTemplateProd = urlTemplateProdE.replace('{sens}', sensval)
                                          .replace('{algo}', algoval)
                                          .replace('{prod}', prodval);

        tileGridProds = tileGridProdsE;
    }

    // update product source since the resolutions and tilegrids may change
    prodSource = new ol.source.TileImage({
        attributions: [attribution_prod],
        tileUrlFunction: parseUrlProds,
        projection: projection,
        wrapX: false,
        tileGrid: tileGridProds
    });

    // update the layer with the new source
    prodTile = new ol.layer.Tile({
        source: prodSource,
        useInterimTilesOnError: false,
        visible: document.getElementById("l2product").checked
    });

    // replace the old layer with updated one; products layer has index 2
    map.getLayers().removeAt(2);
    map.getLayers().insertAt(2, prodTile);
    

    prodTile.setVisible(l2val);
    prodSource.refresh();
    updateColorbar();

};

//////////////////////////////////////////////////////////////////////////////
var updateTrueColor = function () {

    var projval = $("#proj_select").val();
    var sensval = $("#sens_select").val();

    popup_overlay.setPosition(undefined);
    popup_closer.blur();

    if( sensval=="GOCI") {
        $("#proj_select option[value=3413]").attr('disabled', 'disabled');
        $("#proj_select option[value=3031]").attr('disabled', 'disabled');
    } else {
        $("#proj_select option[value=3413]").removeAttr('disabled');
        $("#proj_select option[value=3031]").removeAttr('disabled');
    }

    if(sensval=="VIIRSMIX") {
        $("#truecolor").prop('checked', false).prop('disabled', true).parent('label').addClass('disabled-label'); 
        if(document.getElementById("granlines").checked == true)  $('#granlines').trigger('click');
        $("#granlines").prop('disabled', true).parent('label').addClass('disabled-label'); 
    }
    else {
        $("#truecolor").prop('disabled', false).parent('label').removeClass('disabled-label'); 
        $("#granlines").prop('disabled', false).parent('label').removeClass('disabled-label'); 
    }

    var logopicid = document.getElementById('logopic');
    if( (sensval=="VIIRS") || (sensval=="VIIRSJ1") || (sensval=="VIIRSMIX") ) {
        urlTemplateTC = urlTemplateVIIRS.replace('{sens}', sensval);
        trueSource.setAttributions([attribution_true]);
        logopicid.innerHTML = "<a href='http://www.noaa.gov/' target=”_blank”><img id='NOAA Logo' src='./icons/NOAA-Transparent-Logo_65px.png' alt='JPSS' style='height:40px;'></a>" +
                              "<a href='http://www.jpss.noaa.gov/' target=”_blank”><img id='JPSS Logo' src='./icons/JPSS_EMBLEM_65px.png' alt='JPSS' style='height:40px;'></a>" +
                              "<a href='https://www.star.nesdis.noaa.gov/star/index.php' target=”_blank”><img id='NESDIS/STAR Logo' src='./icons/NOAA-STAR_65px.png' alt='NESDIS/STAR' style='height:40px;'></a>" +
                              "<a href='https://www.star.nesdis.noaa.gov/socd/mecb/color/index.php' target=”_blank”><img id='Ocean Color Logo' src='./icons/STAR_OC_65px.png' alt='Ocean Color' style='height:40px;'></a>";

        $('.hourbuttons').hide();

        $("#algo_select").empty();
        $("#algo_select").append($("<optgroup></optgroup>").attr("value","noaa_msl12").attr("label","NOAA-MSL12:")); 
        $("#algo_select").append($("<option></option>").attr("value","noaa_msl12_nrt").text("NIR-NRT")); 
        if( (sensval=="VIIRS") || (sensval=="VIIRSJ1") ) {
            if(projval==4326){
                $("#algo_select").append($("<option></option>").attr("value","noaa_msl12_bmw").text("NIR-SCI")); 
                $("#algo_select").append($("<option></option>").attr("value","noaa_msl12_swir").text("SWIR")); 
            }
            $("#algo_select").append($("<option></option>").attr("value","noaa_msl12_nsw").text("NIR-SWIR")); 
            if(projval!=4326) {
                if(lastVIIRSalgo=="noaa_msl12_bmw")  lastVIIRSalgo = "noaa_msl12_nrt";
                if(lastVIIRSalgo=="noaa_msl12_swir") lastVIIRSalgo = "noaa_msl12_nrt";
            }
            $("#algo_select").val(lastVIIRSalgo); // select the last used VIIRS algo
        }
    }
    else if (sensval==="OLCI")  {
        urlTemplateTC = urlTemplateOLCI.replace('{sens}', sensval);
        trueSource.setAttributions([attribution_OLCI]);
        logopicid.innerHTML = "<a href='https://sentinel.esa.int/web/sentinel/missions/sentinel-3/data-products/olci' target=”_blank”><img id='Copernicus Logo' src='./icons/copernicus.png' alt='Copernicus' style='height:30px;'></a><br>" +
                              "<a href='https://sentinel.esa.int/web/sentinel/missions/sentinel-3/data-products/olci' target=”_blank”><img id='ESA Logo' src='./icons/esa_logo.png' alt='ESA' style='height:30px;'></a><br>" +
                              "<a href='https://www.eumetsat.int/website/home/index.html' target=”_blank”><img id='EUMETSAT Logo' src='./icons/EUMETSAT_logo.png' alt='EUMETSAT' style='height:25px;'></a>" ;

        $('.hourbuttons').hide();

        $("#algo_select").empty();
        $("#algo_select").append($("<option></option>").attr("value","esa_olci_nrt").text("OLCI_NRT")); 
        // $("#algo_select").append($("<option></option>").attr("value","esa_olci_rep").text("OLCI_REP")); 
        $("#algo_select").val(lastOLCIalgo); // select the last used OLCI algo

    }
    else if (sensval=="GOCI")  { // GOCI
        urlTemplateTC = urlTemplateGOCI.replace('{h}', GOCIhour);
        trueSource.setAttributions([attribution_GOCI]);
        logopicid.innerHTML = "";    
        $('.hourbuttons').show();

        $("#algo_select").empty();
        $("#algo_select").append($("<option></option>").attr("value","ksa_goci_nir").text("GOCI_NIR").attr('selected', 'selected')); 

    } 
    else {
        console.log("unknown sensor value " + sensval);
    }

    trueTile.setVisible(document.getElementById('truecolor').checked);
    trueSource.refresh();
};

//////////////////////////////////////////////////////////////////////////////
var updateProjection = function () {

    var projval = $("#proj_select").val();
    var sensval = $("#sens_select").val();

    if(projectionNumber == projval) return;
    var prevprojectionNumber = projectionNumber;


    if( projval==4326) {
        $("#sens_select option[value=GOCI]").removeAttr('disabled');
    } else {
        $("#sens_select option[value=GOCI]").attr('disabled', 'disabled');
    }


    projectionNumber = projval;
    projectionString = "EPSG:" + projectionNumber;
    projection = ol.proj.get(projectionString);
    if(projectionNumber==3413) projection.setExtent([-5050747.26, -5050747.26, 5050747.26, 5050747.26]);
    if(projectionNumber==3031) projection.setExtent([-5065906.00413311, -5065906.00413311, 5065906.00413311, 5065906.00413311]);
    projectionExtent = projection.getExtent();
    if(projectionNumber==4326) {
        minZoom = 2;
        maxZoom = 10;
    }
    else {
        minZoom = 1;
        maxZoom = 9;
    }
    zoom = mapview.getZoom();
    if(prevprojectionNumber==4326) zoom -= 1;
    if(    projectionNumber==4326) zoom += 1;

    mousePositionControl.setProjection(projection);

    map.removeLayer(granLayer);
    map.removeLayer(gridLayer);
    map.removeLayer(coastLayer);
    map.removeLayer(prodTile);
    map.removeLayer(trueTile);
    map.removeLayer(landLayer);

    popup_overlay.setPosition(undefined);
    popup_closer.blur();

    setProjRes();
    setUrlTemplates();
    setSourcesLayers();

    if(projectionNumber==4326) granLayer = new ol.layer.Image({});
    else                       granLayer = new ol.layer.Vector({});

    dayspast = Math.round((cDate-lDate)/864e5);
    var coord1 = [ lon, lat ];
    if(projectionNumber != 4326){
        coord1 = ol.proj.transform(coord1, 'EPSG:4326', projectionString);
    }

    center[0] = coord1[0];
    center[1] = coord1[1];
    if(projectionNumber==4326) center[0] -= 360.0*dayspast;
    else {
        if( (center[0]<projectionExtent[0]) || (center[0]>projectionExtent[2]) || 
            (center[1]<projectionExtent[1]) || (center[1]>projectionExtent[3]) ) {
            center[0] = 0;
            center[1] = 0;
            zoom = 2;
        }
    }

    mapview = new ol.View({
        center: center,
        projection: projection,
        zoom: zoom,
        minZoom: minZoom,
        maxZoom: maxZoom
    });

    map.setView(mapview);

    map.addLayer(landLayer);
    map.addLayer(trueTile);
    map.addLayer(prodTile);
    map.addLayer(coastLayer);
    map.addLayer(gridLayer);
    map.addLayer(granLayer);

    nDaysPastgran = -1; // invalidate the existing granule layer
    updateGranules();

};





//////////////////////////////////////////////////////////////////////////////
//////  customCordinate function for mousePositionControl    /////////////////
//////////////////////////////////////////////////////////////////////////////
var customCordinate = function(coord){

    var coord1 = [coord[0], coord[1]];
    if(projectionNumber == 4326){
        var dayspast1 = -Math.floor( (coord[0] + 180.0)/360.0 );
        coord1[0] += dayspast1*360.0;
        var nDate = new Date(lDate.getTime() + dayspast1*86400000);
        var yn = nDate.getFullYear();
        var mn = nDate.getMonth() + 1;
        if(mn<10) mn = '0' + mn;
        var dn = nDate.getDate();
        if(dn<10) dn = '0' + dn;
    }
    else {
        yn = yyyymmdd.substring(0,4);
        mn = yyyymmdd.substring(4,6);
        dn = yyyymmdd.substring(6,8);
        coord1 = ol.proj.transform(coord, projectionString, 'EPSG:4326');
    }

    return yn + "-" + mn + "-" + dn + ":&nbsp;&nbsp;     " + Math.round(coord1[1]*10000)/10000 + "&deg " + Math.round(coord1[0]*10000)/10000 + '&deg';
}

//////////////////////////////////////////////////////////////////////////////
//////    openlayers input controls                          /////////////////
//////////////////////////////////////////////////////////////////////////////
var attribution = new ol.control.Attribution({
  collapsible: true,
  collapsed: true
});

var mousePositionControl = new ol.control.MousePosition({
    coordinateFormat: customCordinate,
    projection: projectionString,
    undefinedHTML: ''
});

var scaleLineControl = new ol.control.ScaleLine();

///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////            MAP OBJECT                                               ///////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

var mapview = new ol.View({
        center: center,
        projection: projection,
        zoom: zoom,
        minZoom: minZoom,
        maxZoom: maxZoom
});

var map = new ol.Map({
    controls: ol.control.defaults({ attribution: false }).extend([attribution]).extend([mousePositionControl]).extend([scaleLineControl]),
    target: 'map',
    keyboardEventTarget: document,
    layers: [
        landLayer,
        trueTile,
        prodTile,
        coastLayer,
        gridLayer,
        granLayer
    ],
    overlays: [popup_overlay],
    view: mapview
});
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
zoomslider = new ol.control.ZoomSlider();
map.addControl(zoomslider);

var GOCI_minlon = 113.0;
var GOCI_maxlon = 149.0;
var GOCI_ctrlon = 131.0;
var GOCI_minlat = 24.0;
var GOCI_maxlat = 48.0;
var GOCI_ctrlat = 36.0;

///////////////////////////////////////////////////////////////////////////////////////////
///   permalink ///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
var shouldUpdate = true;
// var view = map.getView();
var updatePermalink = function() {

    var sensval = $("#sens_select").val();

    var center = mapview.getCenter();
    if(projectionNumber!=4326) {
        center[0] = Math.max(center[0], projectionExtent[0]);
        center[0] = Math.min(center[0], projectionExtent[2]); 
    }
    center[1] = Math.max(center[1], projectionExtent[1]);
    center[1] = Math.min(center[1], projectionExtent[3]);

    if(projectionNumber==4326) {
        dayspast = -Math.floor( (center[0] + 180.0)/360.0 );
        cDate = new Date(lDate.getTime() + dayspast*86400000);
        if(sensval=="GOCI"){
            if((center[0] + dayspast*360.0) < (GOCI_minlon - 18)) center[0] = GOCI_ctrlon - dayspast*360.0;
            if((center[0] + dayspast*360.0) > (GOCI_maxlon + 18)) center[0] = GOCI_ctrlon - dayspast*360.0;
            if((center[0] + dayspast*360.0) < GOCI_minlon) center[0] = GOCI_minlon - dayspast*360.0;
            if((center[0] + dayspast*360.0) > GOCI_maxlon) center[0] = GOCI_maxlon - dayspast*360.0;
            if(center[1] < (GOCI_minlat-12)) center[1] = GOCI_ctrlat;
            if(center[1] > (GOCI_maxlat-12)) center[1] = GOCI_ctrlat;
            if(center[1] < GOCI_minlat) center[1] = GOCI_minlat;
            if(center[1] > GOCI_maxlat) center[1] = GOCI_maxlat;
        }
    } else {
        dayspast = Math.round((cDate-lDate)/864e5);
    } 

    mapview.setCenter(center);

    var yn = cDate.getFullYear();
    var mn = cDate.getMonth() + 1;
    if(mn<10) mn = '0' + mn;
    var dn = cDate.getDate();
    if(dn<10) dn = '0' + dn;
    yyyymmdd = yn.toString() + mn + dn;
    document.getElementById("curryear").value = yn.toString();
    document.getElementById("currmonth").value = mn.toString();
    document.getElementById("currd").value = dn.toString();

    var coord1 = [ center[0], center[1] ];
    if(projectionNumber!=4326) {
        coord1 = ol.proj.transform(coord1, projectionString, 'EPSG:4326');
    }
    else {
        coord1[0] +=  360.0*dayspast;
    }

    lon = Math.round(coord1[0] * 10000) / 10000;
    lat = Math.round(coord1[1] * 10000) / 10000;
    var timeaveval = $('[name="timeave"]:checked').val();
    var algoval = $("#algo_select").val();
    var prodval = $("#prod_select").val();
    var projval = $("#proj_select").val();
    var trueyes = document.getElementById("truecolor").checked;
    var l2pryes = document.getElementById("l2product").checked;
    var cbaryes = document.getElementById("colorbars").checked;
    var granyes = document.getElementById('granlines').checked;
    var coastys = document.getElementById('coastline').checked;
    var gridyes = document.getElementById('gridlines').checked;
    var hash1 = '#' +
                'date='  + yyyymmdd +
                '/zoom=' + mapview.getZoom() + 
                '/lat='  + lat + 
                '/lon='  + lon +
                '/tc='   + trueyes +
                '/l2='   + l2pryes +
                '/sens=' + sensval +
                '/proj=' + projval +
                '/algo=' + algoval +
                '/prod=' + prodval +
                '/ave='  + timeaveval +
                '/cbar=' + cbaryes +
                '/gran=' + granyes + 
                '/coast='+ coastys +
                '/grid=' + gridyes;
    if(sensval==="GOCI") { hash1 = hash1 +  '/hr=' + GOCIhour; }

    var state1 = {
        day:    yyyymmdd,
        hour:   GOCIhour,
        zoom:   mapview.getZoom(),
        center: mapview.getCenter(),
        sensor:      sensval,
        algorithm:   algoval,
        product:     prodval,
        timeave:     timeaveval,
        colorbar:    cbaryes,
        granules:    granyes,
        coastlines:  coastys,
        grid:        gridyes
    }

    window.history.replaceState(state1, 'map', hash1);
    if(granyes===true) updateGranules();

    document.getElementById('lookup').innerHTML = "";
    if( (granyes===true) || (trueyes===true) || (l2pryes===false) ) {
        lookupenabled = false; 
    }
    else {
        lookupenabled = true;
    }
};

map.on('moveend', updatePermalink);

///////////////////////////////////////////////////////////////////////////////////////////
//  sensor dropdown box change
///////////////////////////////////////////////////////////////////////////////////////////
var sensSelect = $('#sens_select');
sensSelect.on('change', function() {
    updateTrueColor();
    updateProducts();
    updatePermalink();   
});

///////////////////////////////////////////////////////////////////////////////////////////
//  projection dropdown box change
///////////////////////////////////////////////////////////////////////////////////////////
var projSelect = $('#proj_select');
projSelect.on('change', function() {
    updateProjection();
    updateTrueColor();
    updateProducts();
    updatePermalink();
});

///////////////////////////////////////////////////////////////////////////////////////////
//  algorithm dropdown box change
///////////////////////////////////////////////////////////////////////////////////////////
var algoSelect = $('#algo_select');
algoSelect.on('change', function() {
    updateProducts();
    updatePermalink();   
});


///////////////////////////////////////////////////////////////////////////////////////////
//  product selection change
///////////////////////////////////////////////////////////////////////////////////////////
var prodSelect = $('#prod_select');
prodSelect.on('change', function() {
    updateProducts();
    updatePermalink();   
    updateLookupArr();
});

///////////////////////////////////////////////////////////////////////////////////////////
//  color bar selection change
///////////////////////////////////////////////////////////////////////////////////////////
var colorbarSelect = $('#colorbars');
colorbarSelect.on('change', function() {
    updateColorbar();
    updatePermalink();   
});

///////////////////////////////////////////////////////////////////////////////////////////
//  true color checkbox change
///////////////////////////////////////////////////////////////////////////////////////////
var truecolorSelect = $('#truecolor');
truecolorSelect.on('change', function() {
    updateTrueColor();
    updatePermalink();   
});

///////////////////////////////////////////////////////////////////////////////////////////
//  L2 product checkbox change
///////////////////////////////////////////////////////////////////////////////////////////
var l2productSelect = $('#l2product');
l2productSelect.on('change', function() {
    prodTile.setVisible(this.checked);
    updatePermalink();   
    updateColorbar();
});

///////////////////////////////////////////////////////////////////////////////////////////
//  coastlines checkbox change
///////////////////////////////////////////////////////////////////////////////////////////
var coastlinesSelect = $('#coastline');
coastlinesSelect.on('change', function() {
    coastLayer.setVisible(this.checked);
    updatePermalink();   
    window.focus();
});

///////////////////////////////////////////////////////////////////////////////////////////
//  gridlines checkbox change
///////////////////////////////////////////////////////////////////////////////////////////
var gridlinesSelect = $('#gridlines');
gridlinesSelect.on('change', function() {
    gridLayer.setVisible(this.checked);
    updatePermalink();
    window.focus();
});

///////////////////////////////////////////////////////////////////////////////////////////
var next8daySelect = $('#next8day');
next8daySelect.on('click', function() {
    setnextnextday();
    return false;
});

///////////////////////////////////////////////////////////////////////////////////////////
var nextdaySelect = $('#nextday');
nextdaySelect.on('click', function() {
    setnextday();
    return false;
});

///////////////////////////////////////////////////////////////////////////////////////////
var prevdaySelect = $('#prevday');
prevdaySelect.on('click', function() {
    setprevday();
    return false;
});

///////////////////////////////////////////////////////////////////////////////////////////
var prev8daySelect = $('#prev8day');
prev8daySelect.on('click', function() {
    setprevprevday();
    return false;
});


///////////////////////////////////////////////////////////////////////////////////////////
var nextdSelect = $('#nextd');
nextdSelect.on('click', function() {
    setnextday();
    return false;
});

///////////////////////////////////////////////////////////////////////////////////////////
var prevdSelect = $('#prevd');
prevdSelect.on('click', function() {
    setprevday();
    return false;
});

///////////////////////////////////////////////////////////////////////////////////////////
var nextmonthSelect = $('#nextmonth');
nextmonthSelect.on('click', function() {
    setnextmonth();
    return false;
});

///////////////////////////////////////////////////////////////////////////////////////////
var prevmonthSelect = $('#prevmonth');
prevmonthSelect.on('click', function() {
    setprevmonth();
    return false;
});

///////////////////////////////////////////////////////////////////////////////////////////
var nextyearSelect = $('#nextyear');
nextyearSelect.on('click', function() {
    setnextyear();
    return false;
});

///////////////////////////////////////////////////////////////////////////////////////////
var prevyearSelect = $('#prevyear');
prevyearSelect.on('click', function() {
    setprevyear();
    return false;
});


///////////////////////////////////////////////////////////////////////////////////////////
function setprevday() {
    var ndays = 1;
    var newtime = cDate.getTime() - ndays*86400000;
    if(newtime < mintime) return;
    cDate = new Date(cDate.getTime() - ndays*86400000);
    if(projectionNumber==4326){
        var center = mapview.getCenter();
        center[0] += ndays*360.0;
        mapview.setCenter(center);
    }
    updatePermalink();   
    trueSource.refresh();
    if(projectionNumber!=4326) updateProducts();
};

function setnextday() {
    var ndays = 1;
    var tDate = new Date();
    var maxtime = tDate.getTime();
    var newtime = cDate.getTime() + ndays*86400000;
    if(newtime > maxtime) {
      ndays = Math.round( (maxtime - cDate.getTime())/86400000 );
    }
    cDate = new Date(cDate.getTime() + ndays*86400000);
    if(projectionNumber==4326){
        var center = mapview.getCenter();
        center[0] -= ndays*360.0;
        mapview.setCenter(center);
    }
    updatePermalink();   
    trueSource.refresh();
    if(projectionNumber!=4326) updateProducts();
};

function setprevprevday() {
    var ndays = 8;
    var newtime = cDate.getTime() - ndays*86400000;
    if(newtime < mintime) {
      ndays = Math.round( (cDate.getTime() - mintime)/86400000 );
    }
    cDate = new Date(cDate.getTime() - ndays*86400000);
    if(projectionNumber==4326){
        var center = mapview.getCenter();
        center[0] += ndays*360.0;
        mapview.setCenter(center);
    }
    updatePermalink();   
    trueSource.refresh();
    if(projectionNumber!=4326) updateProducts();
};

function setnextnextday() {
    var ndays = 8;
    var tDate = new Date();
    var maxtime = tDate.getTime();
    var newtime = cDate.getTime() + ndays*86400000;
    if(newtime > maxtime) {
      ndays = Math.round( (maxtime - cDate.getTime())/86400000 );
    }
    cDate = new Date(cDate.getTime() + ndays*86400000);
    if(projectionNumber==4326){
        var center = mapview.getCenter();
        center[0] -= ndays*360.0;
        mapview.setCenter(center);
    }
    updatePermalink();   
    trueSource.refresh();
    if(projectionNumber!=4326) updateProducts();
};

function setprevmonth() {
    month = cDate.getMonth() + 0;
    var ndays;
    switch(month){
        case 2:
           if( (year % 4) == 0 ) { ndays = 29; } else { ndays = 28; }
           break;
        case 4:
        case 6:
        case 9: 
        case 11:
           ndays = 30;
           break;
        default:
           ndays = 31;
           break;
    }
    var iday = cDate.getDate();
    if (ndays<iday) { ndays = iday; }

    var newtime = cDate.getTime() - ndays*86400000;
    if(newtime < mintime) {
      ndays = Math.round( (cDate.getTime() - mintime)/86400000 );
    }
    cDate = new Date(cDate.getTime() - ndays*86400000);
    if(projectionNumber==4326){
        var center = mapview.getCenter();
        center[0] += ndays*360.0;
        mapview.setCenter(center);
    }
    updatePermalink();   
    trueSource.refresh();
    if(projectionNumber!=4326) updateProducts();
};

function setnextmonth() {
    year = cDate.getFullYear();
    month = cDate.getMonth() + 1;
    var ndays, ndays1;
    switch(month){
        case 2:
           if( (year % 4) == 0 ) { ndays = 29; } else { ndays = 28; }
           break;
        case 4:
        case 6:
        case 9:
        case 11:
           ndays = 30;
           break;
        default:
           ndays = 31;
           break;
    }
    switch(month+1){
        case 2:
           if( (year % 4) == 0 ) { ndays1 = 29; } else { ndays1 = 28; }
           break;
        case 4:
        case 6:
        case 9:
        case 11:
           ndays1 = 30;
           break;
        default:
           ndays1 = 31;
           break;
    }
    var iday = cDate.getDate();
    if (ndays1<iday) { ndays -= (iday - ndays1); }

    var tDate = new Date();
    var maxtime = tDate.getTime();
    var newtime = cDate.getTime() + ndays*86400000;
    if(newtime > maxtime) {
      ndays = Math.round( (maxtime - cDate.getTime())/86400000 );
    }
    cDate = new Date(cDate.getTime() + ndays*86400000);
    if(projectionNumber==4326){
        var center = mapview.getCenter();
        center[0] -= ndays*360.0;
        mapview.setCenter(center);
    }
    updatePermalink();
    trueSource.refresh();
    if(projectionNumber!=4326) updateProducts();
};

function setprevyear() {
    year = cDate.getFullYear();
    var ndays = 365;
    var dayofyear = dateToDayOfYear(cDate);
    if (((year % 4)==0) && (dayofyear > 60)) { ndays = 366; }
    if (((year % 4)==1) && (dayofyear < 60)) { ndays = 366; }
    var newtime = cDate.getTime() - ndays*86400000;
    if(newtime < mintime) {
      ndays = Math.round( (cDate.getTime() - mintime)/86400000 );
    }
    cDate = new Date(cDate.getTime() - ndays*86400000);
    if(projectionNumber==4326){
        var center = mapview.getCenter();
        center[0] += ndays*360.0;
        mapview.setCenter(center);
    }
    updatePermalink();
    trueSource.refresh();
    if(projectionNumber!=4326) updateProducts();
};

function setnextyear() {
    year = cDate.getFullYear();
    var ndays = 365;
    var dayofyear = dateToDayOfYear(cDate);
    if (((year % 4)==0) && (dayofyear <= 60)) { ndays = 366; }
    if (((year % 4)==3) && (dayofyear >= 60)) { ndays = 366; }
    var tDate = new Date();
    var maxtime = tDate.getTime();
    var newtime = cDate.getTime() + ndays*86400000;
    if(newtime > maxtime) {
      ndays = Math.round( (maxtime - cDate.getTime())/86400000 );
    }
    cDate = new Date(cDate.getTime() + ndays*86400000);
    if(projectionNumber==4326){
        var center = mapview.getCenter();
        center[0] -= ndays*360.0;
        mapview.setCenter(center);
    }
    updatePermalink();
    trueSource.refresh();
    if(projectionNumber!=4326) updateProducts();
};


///////////////////////////////////////////////////////////////////////////////////////////
//  time average radio buttons change
///////////////////////////////////////////////////////////////////////////////////////////
for (var radioCounter = 0 ; radioCounter < document.getElementsByName('timeave').length; radioCounter++) {
    document.getElementsByName('timeave')[radioCounter].onclick = function() {
        updateProducts();
        updatePermalink();   
    }
}
///////////////////////////////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////////////////////////////
//  granule boundaries layer highlight and label display
///////////////////////////////////////////////////////////////////////////////////////////
var granLinesSelect = $('#granlines');
granLinesSelect.on('change', function() {
    if (this.checked === true) {
        granLayer.setVisible(true);
        featureOverlay.setVisible(true);
    }
    else {
        granLayer.setVisible(false);
        document.getElementById('granuleindicator').innerHTML = '';
        featureOverlay.setVisible(false);
        popup_overlay.setPosition(undefined);
        popup_closer.blur();
    }
    updatePermalink();   
});


var featureOverlay = new ol.layer.Vector({
    source: new ol.source.Vector({
        wrapX : false
    }),
    map: map,
    style: new ol.style.Style({
        stroke: new ol.style.Stroke({
            color: '#f00',
            width: 1
        }),
        fill: new ol.style.Fill({
            color: 'rgba(255,0,0,0.1)'
        })
    })
});


var highlight;
var faetureid;
var featureURL;
var displayFeatureInfo = function(pixel) {

    var feature = map.forEachFeatureAtPixel(pixel, function(feature, layer) {
        return feature;
    });

    var info = document.getElementById('granuleindicator');
    if ( (feature) && (featureOverlay.getVisible() && (feature.getId().length > 0) ) ) {
        var sensorplatform=sensor;
        if(sensor=="VIIRS")   sensorplatform = "VIIRS SNPP";
        if(sensor=="VIIRSJ1") sensorplatform = "VIIRS NOAA-20";
        if(sensor=="OLCI") sensorplatform = "OLCI Sentinel-3A";
        info.innerHTML = sensorplatform + " " + feature.get('name') + " UTC";
        featureid      = feature.getId();
        featureURL     = feature.get('L2URL_bmw');
        featureURL1    = feature.get('L1URL_EUMETSAT');
        featureURL2    = feature.get('L2URL_EUMETSAT');
    } 
    else {
        info.innerHTML = '';
        featureid      = '';
        featureURL     = '';
        featureURL1    = '';
        featureURL2    = '';
    }
    if ( (feature !== highlight) ) {
        if ( (highlight) && (highlight.getId().length > 0) ) {
            featureOverlay.getSource().removeFeature(highlight);
        }
        if ( (feature) && (feature.getId().length > 0) ){
            featureOverlay.getSource().addFeature(feature);
        }
        highlight = feature;
    }
};

map.on('pointermove', function(evt) {
    if (evt.dragging) {
        document.getElementById('lookup').innerHTML = "";
        return;
    }

    var pixel = map.getEventPixel(evt.originalEvent);
    displayFeatureInfo(pixel);

    var oevt = evt.originalEvent;
    var cv = oevt.target;
    if (oevt.target.tagName.toLowerCase() === "canvas") {
        var data = cv.getContext('2d').getImageData(Math.round(1.0*oevt.clientX*cv.width/window.innerWidth), Math.round(1.0*oevt.clientY*cv.width/window.innerWidth), 1, 1).data;
        if( (lookupenabled===true) && (lookupupdated===true) ) updateLookup(oevt.clientX, oevt.clientY, data[0], data[1], data[2], oevt.target.width);
    }
    else {
        document.getElementById('lookup').innerHTML = "";
    }
    
});


$("#map").on("mouseleave", function(ev)
{ 
   var lookuptxt = document.getElementById('lookup');
   lookuptxt.innerHTML = "";
});


map.on('click', function(evt) {
    displayFeatureInfo(evt.pixel);
});

map.on('singleclick', function(evt) {
    var coordinate = evt.coordinate;
    var l2name;
    if(featureid!=""){

        if(featureURL) {
            l2name = featureURL.substring(featureURL.lastIndexOf("/") + 1);
            popup_content.innerHTML = '<p>Download L2 MSL12 NIR-SCI data from NOAA CoastWatch FTP:</p><a href="' + featureURL + '">' + l2name + '</a>';
            popup_overlay.setPosition(coordinate);
        }
        if((featureURL1)||(featureURL2)) {
            popup_content.innerHTML = '';
            if(featureURL1) {
                l2name = featureURL1.substring(featureURL1.lastIndexOf("/") + 1);
                popup_content.innerHTML = popup_content.innerHTML + '<p>Download <a href="' + featureURL1 + '">EUMETSAT L1 data tar file</a> from NOAA CoastWatch FTP</p>';
            }
            if(featureURL2) {
                l2name = featureURL2.substring(featureURL2.lastIndexOf("/") + 1);
                popup_content.innerHTML = popup_content.innerHTML + '<p>Download <a href="' + featureURL2 + '">EUMETSAT L2 data tar file</a> from NOAA CoastWatch FTP</p>';
            }
            popup_overlay.setPosition(coordinate);
        }
    }
});


$(document).ready(function(){

    updateTrueColor();
    updateProducts();
    updateLookupArr();
    updatePermalink();   

    if (document.getElementById('l2product').checked === true)
        prodTile.setVisible(true);
    else
        prodTile.setVisible(false);


    if (document.getElementById('granlines').checked === true)
        granLayer.setVisible(true);
    else
        granLayer.setVisible(false);


    if (document.getElementById('coastline').checked === true)
        coastLayer.setVisible(true);
    else
        coastLayer.setVisible(false);


    if (document.getElementById('gridlines').checked === true)
        gridLayer.setVisible(true);
    else
        gridLayer.setVisible(false);

    map.updateSize();

    window.addEventListener("keydown", function(e){ 
          var ekeyCode = e.keyCode;
          switch(ekeyCode) {
              case 37:
              case 38: 
              case 39:
              case 40:
               //   $('#map').trigger(e);
                  break;
              case 188: // "less" - prev day
                  $('#prevd').trigger('click');
                  break;
              case 190: // "more" - next day
                  $('#nextd').trigger('click');
                  break;
              case 219: // [ - prev month
                  $('#prevmonth').trigger('click');
                  break;
              case 221: // ] - next month
                  $('#nextmonth').trigger('click');
                  break;
              case 57: // 9 - prev year
                  $('#prevyear').trigger('click');
                  break;
              case 48: // 0 - next year
                  $('#nextyear').trigger('click');
                  break;
              case 36: // Home - today
                  $('#nextyear').trigger('click');
                  $('#nextyear').trigger('click');
                  $('#nextyear').trigger('click');
                  $('#nextyear').trigger('click');
                  $('#nextyear').trigger('click');
                  break;
              case 33: // PageUp  - zoom in
              case 61: // =
              case 187: // =
                  $(".ol-zoom-in").trigger('click');
                  break;
              case 34: // PageDown - zoom out
                  $(".ol-zoom-out").trigger('click');
                  break;
              case 71: // g - granules
                  $('#granlines').trigger('click');
                  break;
              case 84: // t - true color
                  $('#truecolor').trigger('click');
                  break;
              case 83: // s - coastlines / shorelines
                  $('#coastline').trigger('click');
                  break;
              case 66: // b - color bar
                  $('#colorbars').trigger('click');
                  break;
              case 68: // d - daily
                  document.getElementById("daily").checked = true;
                  $('#daily').trigger('click');
                  break; 
              case 56: // 8 - 8_day
                  $("#8_day").prop("checked", true);
                  $('#8_day').trigger('click');
                  break;
              case 77: // m - monthly
                  $("#monthly").prop("checked", true); 
                  $('#monthly').trigger('click');
                  break;
              case 67: // c - climatology
                  $("#climatology").prop("checked", true);
                  $('#climatology').trigger('click');
                  break;
              case 79: // o - OC products
                  $('#l2product').trigger('click');
                  break;
              case 81: // q - swap landmask and bathymetry
                  if(urlTemplateLand!=urlTemplateMask) urlTemplateLand = urlTemplateMask; else urlTemplateLand = urlTemplateBath;
                  landSource.refresh();
                  break;
              case 82: // r - gridlines
                  $('#gridlines').trigger('click');
                  break;
              case 86: // v - VIIRS
                  $("#sens_select").val("VIIRS");
                  updateTrueColor();
                  updateProducts();
                  updatePermalink();   
                  break;
              case 74: // j - VIIRS-J1
                  $("#sens_select").val("VIIRSJ1");
                  updateTrueColor();
                  updateProducts();
                  updatePermalink();
                  break;
              case 69: // e - OLCI
                  $("#sens_select").val("OLCI");
                  updateTrueColor();
                  updateProducts();
                  updatePermalink();   
                  break;
              case 75: // k - GOCI
                  $("#sens_select").val("GOCI");
                  updateTrueColor();
                  updateProducts();
                  updatePermalink();   
                  break;
              default:
                  break;

          }
          window.focus();
    });
}); 


</script>
</body>
</html>

