//\/////
//\  somi5.js - You may not remove or change this notice.
//\  Do not sell this as your own work or remove this copyright notice.
//\
//\  Credit given (and copyright statements maintained) where code
//\  used directly or modified from other sources.
//\  
//\  This software is Copyright © 2008 The Regents of the University of
//\  California. All Rights Reserved.
//\  
//\  Permission to use, copy, modify, and distribute this software and its
//\  documentation for educational, research and non-profit purposes,
//\  without fee, and without a written agreement is hereby granted, provided
//\  that the above copyright notice, this paragraph and the following three
//\  paragraphs appear in all copies.
//\  
//\  Permission to incorporate this software into commercial products may be
//\  obtained by contacting
//\  Technology Transfer Office
//\  9500 Gilman Drive, Mail Code 0910
//\  University of California
//\  La Jolla, CA 92093-0910
//\  (858) 534-5815
//\  invent@ucsd.edu
//\  
//\  This software program and documentation are copyrighted by The Regents of the
//\  University of California. The software program and documentation are
//\  supplied "as is", without any accompanying services from The Regents.
//\  The Regents does not warrant that the operation of the program will be
//\  uninterrupted or error-free. The end-user understands that the program was
//\  developed for research purposes and is advised not to rely exclusively on
//\  the program for any reason.
//\  
//\  IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO
//\  ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
//\  CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
//\  OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
//\  EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF
//\  THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF
//\  CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
//\  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
//\  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//\  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND
//\  THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
//\  PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
//\  MODIFICATIONS.
//\  
//\/////

//////////////////////////////////////////////////
//  SOMI 5 functions for use with OpenLayers    //
//  Created by Ian June, 2008                   //
//  Sections adapted from SOMI*.js (SOMI 4)     //
//////////////////////////////////////////////////


        // SOMI objects and global variables for tracking 
        // current map/toolbox options. Set defaults here
        var somi = new Object();
        var somiBasket = new Object();
        var tree;
        var layersContent = '';
        var printMapContent = '';
        var queryContent = '';
        var quickNavContent = '';
        var supportContent = '';
        var velocitiesContent = '';
        // OpenLayers global variables
        var map;
        var scaleBar;
        var selFeatures;

        // Map scales
        somi.scales = ['111000000','55000000','28000000','14000000','7000000','3000000','2000000','865000','433000','216000','108000','54000','27000','14000'];

        // Create toolboxes, set defaults
        somi.tools = {
          layers: {content: layersContent},
          printMap: {content: printMapContent},
          query: {basket: somiBasket, basketModTime: 0, content: queryContent, layer: '', layers: [], mode: '', modes: ['info','add','remove'], infoResult: [] },
          quickNav: {content: quickNavContent, mode: '', lonDD: '', latDD: '', lonDMSd: '', lonDMSm: '', lonDMSs: '', latDMSd: '', latDMSm: '', latDMSs: ''},
          support: {content: supportContent},
          velocities: {activeVel: 'none', content: velocitiesContent, layers: {
            'sopacNAM':{name: 'SOPAC North America', hArrow:'off',hExag:'3',hEllipse:'off',hLabel:'off',vArrow:'off',vExag:'3',vEllipse:'off',vLabel:'off'}, 
            'sopacPAC':{name: 'SOPAC Pacific', hArrow:'off',hExag:'3',hEllipse:'off',hLabel:'off',vArrow:'off',vExag:'3',vEllipse:'off',vLabel:'off'}, 
            'reasonNAM':{name: 'REASoN North America', hArrow:'off',hExag:'3',hEllipse:'off',hLabel:'off',vArrow:'off',vExag:'3',vEllipse:'off',vLabel:'off'},
            'reasonPAC':{name: 'REASoN Pacific', hArrow:'off',hExag:'3',hEllipse:'off',hLabel:'off',vArrow:'off',vExag:'3',vEllipse:'off',vLabel:'off'},
            'jplNAM':{name: 'JPL North America', hArrow:'off',hExag:'3',hEllipse:'off',hLabel:'off',vArrow:'off',vExag:'3',vEllipse:'off',vLabel:'off'},
            'jplPAC':{name: 'JPL Pacific', hArrow:'off',hExag:'3',hEllipse:'off',hLabel:'off',vArrow:'off',vExag:'3',vEllipse:'off',vLabel:'off'},
            'pboSNF':{name: 'PBO Snarf', hArrow:'off',hExag:'3',hEllipse:'off',hLabel:'off',vArrow:'off',vExag:'3',vEllipse:'off',vLabel:'off'} }
          }
        }

        // Handler ("dragQuery") for shift key + mouse drag
        // Default OL behavior for a shift key + mouse drag
        // is to zoom in. In add/remove mode we use the box
        // bounds to query features.
        var dragQuery = new OpenLayers.Control();
        OpenLayers.Util.extend(dragQuery, {
          draw: function () {
            // this Handler.Box will intercept the shift-mousedown
            // before Control.MouseDefault gets to see it
            this.handler = new OpenLayers.Handler.Box(dragQuery,
            {"done": this.notice},
            {keyMask: OpenLayers.Handler.MOD_SHIFT});},
          notice: function (bounds) {
            var ll = map.getLonLatFromPixel(new OpenLayers.Pixel(bounds.left, bounds.bottom));
            var ur = map.getLonLatFromPixel(new OpenLayers.Pixel(bounds.right, bounds.top));
            boxQuery(ll.lon.toFixed(4)+"+"+ll.lat.toFixed(4)+"+"+ur.lon.toFixed(4)+"+"+ur.lat.toFixed(4));}
        });

        // Additional map options that don't need to be
        // set in each map page
        // Set feature highlighting styles
        OpenLayers.Feature.Vector.style['default']['fillOpacity'] = 0.3;
        OpenLayers.Feature.Vector.style['default']['pointRadius'] = 7;
        OpenLayers.Feature.Vector.style['default']['strokeWidth'] = 2;
        // Prevent the occasional pink map tile
        OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3;
        // Instead of pink tiles for failed data, draw transparent
        OpenLayers.Util.onImageLoadErrorColor = "transparent";

        // Functions
        function registerMapEvents() {
          map.events.register('click', map, function(e) {
            // User has clicked once in the map
            // If Query is the selected toolbox complete the request
            var sTB = document.getElementById('selectedTB');
            if (sTB.options[sTB.selectedIndex].value == 'query') {
              var qLayer = somi.tools.query.layer;            
              var qMode = somi.tools.query.mode;
              if (qLayer == '' || qLayer == 'select') {
                alert('Please select a Query Layer from the toolbox.');
              } else if (qMode == '' || qMode == 'select') {
                alert('Please select a Query Mode from the toolbox.');
              } else if (document.getElementById('featureInfo') != undefined) {
                document.getElementById('featureInfo').innerHTML = "Loading...";              
                var clicked = map.getLonLatFromPixel(e.xy);
                var lon = clicked.lon;
                var lat = clicked.lat;              
                var url = somi.map+'&mode=query&qlayer='+somi.tools.query.layer+'&mapxy='+lon+'+'+lat;
                OpenLayers.loadURL(url, '', map, function (response) {
                  if (response.responseText.search('no results') > -1) {                  
                    // User has clicked map and selected nothing
                    document.getElementById('featureInfo').innerHTML = 'No features selected';
                  } else {
                    parseResponse(response, "click");
                  }
                });
              }
            }
          });
          map.events.register('moveend', map, function(e) { 
            // Triggered after a drag, pan, or zoom completes
            // Enter new coordinates/scale in Quick Nav toolbox
            updateQuickNavFields();
            // If we are in a portal save the user's state
            if (typeof saveSOMI_State == 'function') saveSOMI_State(); 
          });
          map.events.register('changelayer', map, function(e) { 
            // Triggered after layer toggled
            // If we are in a portal save the user's state
            if (typeof saveSOMI_State == 'function') saveSOMI_State();
          });
          try {            
            OpenLayers.Event.stop(e);
          } catch (e) { 
            // No event to stop at the moment, do nothing
          }
        }

        function loadToolbox (tb) {
          if (tb == 'select') {
            document.getElementById('toolboxContent').innerHTML = '';
          } else {
            // Layers
            layersContent =     '<div id="treeHouse" align="center"><div id="tree" align="left" style="height:250px; width:200px;"></div></div><br>';
            somi.tools.layers.content = layersContent;

            // Query
            queryContent =      '<center>';
            queryContent +=      '<span><b>Layer:</b></span><br>';        
            queryContent +=      '<select type="pulldown" id="targetLayer" name="targetLayer" onChange="somi.tools.query.layer = this.options[this.selectedIndex].value;">';
            queryContent +=      '<option value="select">Select Layer';
            // If user has already selected options select them
            // in the toolbox again
            for (var i=0; i < somi.tools.query.layers.length; i++) {
              if (somi.tools.query.layer == somi.tools.query.layers[i]) {
                queryContent += '<option id="' + somi.tools.query.layers[i] + '" value="' + somi.tools.query.layers[i] + '" selected>' + somi.tools.query.layers[i];
              } else {
                queryContent += '<option id="' + somi.tools.query.layers[i] + '" value="' + somi.tools.query.layers[i] + '">' + somi.tools.query.layers[i];
              }
            }
            queryContent +=      '</select><br><br>';
            queryContent +=      '<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>Mode:</b>&nbsp;&nbsp;<a href="javascript:void(0);" style="color: red; font-size: 10pt; text-decoration: none" onmouseover="return overlib(\'<center><b>To draw a box:</b><br>Hold the Shift key down.<br><br><b>Info mode:</b><br>Box is extent to zoom to.<br><br><b>Add/Remove mode:</b><br>Box is extent of features to add/remove.</center>\', OFFSETX, 10, WIDTH, 150, FGCOLOR, \'#FFFF33\');" onmouseout="return nd();">Tip</a></span><br>';
            queryContent +=      '<select type="pulldown" name="queryMode" onChange="somi.tools.query.mode=this.options[this.selectedIndex].value; updateDragHandler();">';
            queryContent +=      '  <option value="select">Select Mode';
            for (var i=0; i < somi.tools.query.modes.length; i++) {
              if (somi.tools.query.mode == somi.tools.query.modes[i]) {
                queryContent += '<option id="' + somi.tools.query.modes[i] + '" value="' + somi.tools.query.modes[i] + '" selected>' + somi.tools.query.modes[i];
              } else {
                queryContent += '<option id="' + somi.tools.query.modes[i] + '" value="' + somi.tools.query.modes[i] + '">' + somi.tools.query.modes[i];
              }
            }
            queryContent +=      '</select><br><br>';
            queryContent +=      '<span><b>Basket:</b></span><br>';
            queryContent +=      '<select type="pulldown" id="queryBasket" name="queryBasket" onChange="if (somi.tools.query.basket[this.options[this.selectedIndex].value] != undefined) { document.getElementById(\'featureInfo\').innerHTML = somi.tools.query.basket[this.options[this.selectedIndex].value].displayTable; for (var key in selFeatures.features) { if (selFeatures.features[key].fid != undefined && this.options[this.selectedIndex].value.substring(0,10) == selFeatures.features[key].fid.substring(0,10)) {selFeatures.features[key].style = OpenLayers.Util.applyDefaults({fillColor: \'red\', pointRadius: 9},OpenLayers.Feature.Vector.style[\'default\']); selFeatures.drawFeature(selFeatures.features[key]);} else {selFeatures.features[key].style = OpenLayers.Util.applyDefaults({fillColor: \'orange\', pointRadius: 7},OpenLayers.Feature.Vector.style[\'default\']); selFeatures.drawFeature(selFeatures.features[key]); } } }">';
            queryContent +=      '<option value="savedItems">Saved Items';
            var items = 0;
            for (var key in somi.tools.query.basket) {
              items += 1;
              if (items > 0) {
                var fName;
                if (key.length <= 10) {
                  fName = key;
                } else {
                  fName = key.substring(0,10) + '...';
                }
                queryContent += '<option value="' + key + '">' + fName;
              }
            }
            queryContent +=      '</select><br><br>';
            queryContent +=      '<span><b>Feature Info:</b></span>';
            queryContent +=      '<div id="featureInfo"></div>';
            queryContent +=      '</center>';
            somi.tools.query.content = queryContent;

            // Quick Nav
            quickNavContent =   '<center>'
            quickNavContent +=  '<span><b>Coordinate Type:</b></span><br>';        
            quickNavContent +=  '<select type="pulldown" id="quickNavSelect" name="quickNavSelect" onChange="somi.tools.quickNav.mode=this.options[this.selectedIndex].value; updateQuickNav();"><br>';
            quickNavContent +=  '  <option value="select">Select coordinate type';
            quickNavContent +=  '  <option value="dd">Decimal Degrees';
            quickNavContent +=  '  <option value="dms">Degrees Minutes Seconds';
            quickNavContent +=  '</select><br><br>';
            quickNavContent +=  '<div id="quickNavInput"></div>';
            quickNavContent +=  '</center>';
            somi.tools.quickNav.content = quickNavContent;

            // Print Map
            printMapContent =   '<center>';
            printMapContent +=  '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>Print:</b>&nbsp;&nbsp;<a href="javascript:void(0);" style="color: red; font-size: 10pt; text-decoration: none" onmouseover="return overlib(\'<center><b>Known bug:</b><br>Panning the map before printing may cause the image to not match your map.<br><br><b>Solution:</b><br>After panning the map switch between base layers or zoom levels, and then print.</center>\', OFFSETX, 10, WIDTH, 150, FGCOLOR, \'#FFFF33\');" onmouseout="return nd();">Tip</a><br><input type="button" id="printMap" name="printMap" value="Print Map" onClick="this.disabled=true; document.getElementById(\'printStatus\').innerHTML = \'Printing your map...<br><br>\'; printMap();"><br><br>';
            printMapContent +=  '<div id="printStatus"></div></center>';
            somi.tools.printMap.content = printMapContent;

            // Support
            supportContent =      '<center>';
            supportContent +=     '<font face="Arial,Helvetica,SanSerif" size=-1>For help with using SOMI, making feature requests, and reporting bugs please go to the <a href="http://troy.ucsd.edu/ubbcgi/ultimatebb.cgi?category=7" target="_blank" style="text-decoration:none">SOMI forums</a>.</font><br><br>';
            supportContent +=     '</center>';
            somi.tools.support.content = supportContent;

            // Velocities
            velocitiesContent =   '<center>';
            velocitiesContent +=  '<span><b>Data Source:</b></span><br>';        
            velocitiesContent +=  '<select type="pulldown" id="velocitiesSource" name="velocitiesSource" onChange="updateVelocityOptions();"><br>';
            for (var key in somi.tools.velocities.layers) {
              if (key == somi.tools.velocities.activeVel) {
                velocitiesContent +=  '  <option value="' + key  + '" selected> ' + somi.tools.velocities.layers[key].name;
              } else {
                velocitiesContent +=  '  <option value="' + key  + '"> ' + somi.tools.velocities.layers[key].name;
              }
            }
            velocitiesContent +=  '</select><br><br>';
            velocitiesContent +=  '<b>Options:</b><br>';
            velocitiesContent +=  '<table>';

            // Horizontal
            velocitiesContent +=  ' <tr>';
            velocitiesContent +=  ' <td align="left" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1>Horizontal Comp:&nbsp;</font></td>';
            velocitiesContent +=  ' <td align="center" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1><select type="pulldown" name="velhArrow" id="velhArrow">';
            if (somi.tools.velocities.activeVel != "none" && somi.tools.velocities.layers[somi.tools.velocities.activeVel].hArrow == "on") {
              velocitiesContent += '<option value="off">off<option value="on" selected>on';
            } else {
              velocitiesContent += '<option value="off" selected>off<option value="on">on';
            }
            velocitiesContent += '  </select></font></td></tr>';

            velocitiesContent += '  <tr>';
            velocitiesContent += '   <td align="left" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1>Horizontal Exag:&nbsp;</font></td>';
            velocitiesContent += '   <td align="center" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1><select type="pulldown" name="velhExag" id="velhExag">';
            // Currently using six exag. values
            for (var i = 1; i <= 6; i++) {
              if (somi.tools.velocities.activeVel != "none") {
                if (i == somi.tools.velocities.layers[somi.tools.velocities.activeVel].hExag) {
                  velocitiesContent += '<option value="' + i + '" selected>' + i;
                } else {
                  velocitiesContent += '<option value="' + i + '">' + i;
                }
              } else {     
                if (i == 3) {
                  velocitiesContent += '<option value="' + i + '" selected>' + i;
                } else {
                  velocitiesContent += '<option value="' + i + '">' + i;
                }
              }
            }
            velocitiesContent += '  </select></font></td></tr>';

            velocitiesContent += '  <tr>';
            velocitiesContent += '   <td align="left" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1>Horizontal Ellip:&nbsp;</font></td>';
            velocitiesContent += '   <td align="center" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1><select type="pulldown" name="velhEllipse" id="velhEllipse">';
            if (somi.tools.velocities.activeVel != "none" && somi.tools.velocities.layers[somi.tools.velocities.activeVel].hEllipse == "on") {
              velocitiesContent += '<option value="off">off<option value="on" selected>on';
            } else {
              velocitiesContent += '<option value="off" selected>off<option value="on">on';
            }
            velocitiesContent += '  </select></font></td></tr>';

            velocitiesContent +=  ' <tr>';
            velocitiesContent +=  ' <td align="left" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1>Horizontal Values:&nbsp;</font></td>';
            velocitiesContent +=  ' <td align="center" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1><select type="pulldown" name="velhLabel" id="velhLabel">';
            if (somi.tools.velocities.activeVel != "none" && somi.tools.velocities.layers[somi.tools.velocities.activeVel].hLabel == "on") {
              velocitiesContent += '<option value="off">off<option value="on" selected>on';
            } else {
              velocitiesContent += '<option value="off" selected>off<option value="on">on';
            }
            velocitiesContent +=  ' </select></font></td></tr>';

            velocitiesContent +=  ' <br>';

            // Vertical
            velocitiesContent +=  ' <tr>';
            velocitiesContent +=  ' <td align="left" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1>Vertical Comp:&nbsp;</font></td>';
            velocitiesContent +=  ' <td align="center" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1><select type="pulldown" name="velvArrow" id="velvArrow">';
            if (somi.tools.velocities.activeVel != "none" && somi.tools.velocities.layers[somi.tools.velocities.activeVel].vArrow == "on") {
              velocitiesContent += '<option value="off">off<option value="on" selected>on';
            } else {
              velocitiesContent += '<option value="off" selected>off<option value="on">on';
            }
            velocitiesContent += '  </select></font></td></tr>';

            velocitiesContent += '  <tr>';
            velocitiesContent += '   <td align="left" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1>Vertical Exag:&nbsp;</font></td>';
            velocitiesContent += '   <td align="center" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1><select type="pulldown" name="velvExag" id="velvExag">';
            // Currently using six exag. values
            for (var i = 1; i <= 6; i++) {
              if (somi.tools.velocities.activeVel != "none") {
                if (i == somi.tools.velocities.layers[somi.tools.velocities.activeVel].vExag) {
                  velocitiesContent += '<option value="' + i + '" selected>' + i;
                } else {
                  velocitiesContent += '<option value="' + i + '">' + i;
                }
              } else {
                if (i == 3) {
                  velocitiesContent += '<option value="' + i + '" selected>' + i;
                } else {
                  velocitiesContent += '<option value="' + i + '">' + i;
                }
              }
            }
            velocitiesContent += '  </select></font></td></tr>';

            velocitiesContent += '  <tr>';
            velocitiesContent += '   <td align="left" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1>Vertical Ellip:&nbsp;</font></td>';
            velocitiesContent += '   <td align="center" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1><select type="pulldown" name="velvEllipse" id="velvEllipse">';
            if (somi.tools.velocities.activeVel != "none" && somi.tools.velocities.layers[somi.tools.velocities.activeVel].vEllipse == "on") {
              velocitiesContent += '<option value="off">off<option value="on" selected>on';
            } else {
              velocitiesContent += '<option value="off" selected>off<option value="on">on';
            }
            velocitiesContent +=  ' </select></font></td></tr>';

            velocitiesContent +=  ' <tr>';
            velocitiesContent +=  ' <td align="left" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1>Vertical Values:&nbsp;</font></td>';
            velocitiesContent +=  ' <td align="center" bgcolor=#FFFFFF valign=bottom><font face="Arial,Helvetica,SanSerif" size=-1><select type="pulldown" name="velvLabel" id="velvLabel">';
            if (somi.tools.velocities.activeVel != "none" && somi.tools.velocities.layers[somi.tools.velocities.activeVel].vLabel == "on") {
              velocitiesContent += '<option value="off">off<option value="on" selected>on';
            } else {
              velocitiesContent += '<option value="off" selected>off<option value="on">on';
            }
            velocitiesContent += ' </select></font></td></tr>';
            velocitiesContent +=  '</table>';
            velocitiesContent += '<br><input type="button" value="Refresh" onClick="drawVelocity();"><br><br>'
            velocitiesContent +=  '</center>';
            somi.tools.velocities.content = velocitiesContent;

            // Update toolbox content, select drop-down option if not selected
            document.getElementById('toolboxContent').innerHTML = somi.tools[tb].content;
            document.getElementById(tb+'TB').selected = true;
            if (tb == 'layers') createLayerTree();
          }
        }        

        function updateDragHandler () {
          if (somi.tools.query.mode == 'info' || somi.tools.query.mode == 'select') {
            dragQuery.deactivate();
          } else {
            dragQuery.activate();
          }
        }

        function boxQuery (bounds) {
          // Lookup feature(s)
          var url = somi.map+'&mode=nquery&mapext='+bounds+'&qlayer='+somi.tools.query.layer+'&qitem=id';
          OpenLayers.loadURL(url, '', map, function(response) {
            if (response.responseText.search('no results') > -1) {
              // User has drawn a box that selected nothing
              document.getElementById('featureInfo').innerHTML = 'No features selected';
            } else {
              parseResponse(response, "box");
            }
          });
        }

        function createLayerTree () {
          // Reference local blank image for tree
          Ext.BLANK_IMAGE_URL = '/lib/extern/mapfish/MapFish-1.1/client/mfbase/ext/resources/images/default/s.gif';

          // Model array to be created and then submitted to layer tree
          var layerTreeModel = [{text: "Base Layers", expanded: true, children: []}, {text: "Overlays", expanded: true, children: []}];
          // Check all layers' visibility
          for (var layer in map.layers) {
            var layerRef = map.layers[layer];
            if (layerRef.visibility != undefined) {
              if (layerRef.isBaseLayer) {
                layerTreeModel[0]["children"].push({text: layerRef.name, checked: layerRef.visibility, layerName: layerRef.name});
              } else {
                // Overlays
                if (layerRef.displayInLayerSwitcher) {
                  layerTreeModel[1]["children"].push({text: layerRef.name, checked: layerRef.visibility, layerName: layerRef.name});
                }
              }
            }
          }
          tree = new mapfish.widgets.LayerTree({map: map, el: 'tree', model: layerTreeModel});
          tree.render();
        }

        function parseResponse (response, mode) {
          var numFeatures = 0;
          var features = response.responseText;
          var feat = features.split('---');
          for (var i = 0; i < feat.length; i += 1) {
            // Only consider valid features
            if (feat[i].length > 10) { 
              numFeatures += 1;
              // Convert to string
              var f = feat[i] + '';
              var attributes = f.split('|');
              var lon = attributes[0];
              var lat = attributes[1];
              var name = attributes[2];
              var displayTable = attributes[3];
              // Create new feature object
              var feature = {lon: lon, lat: lat, name: name, displayTable: displayTable};
              // Portal functionality: infoResult array tracks
              // most recently queried feature in info mode
              if (somi.tools.query.mode == "info") {
                somi.tools.query.infoResult[0] = {name: feature.name, layer: somi.tools.query.layer, lon: feature.lon, lat: feature.lat, displayTable: feature.displayTable};
              }
              if (mode == "click" || (mode == "box" && numFeatures == 1)) {
                // This is a single feature result so display
                // its attributes in the Query toolbox
                document.getElementById('featureInfo').innerHTML = feature.displayTable;
              } else {
                // Multiple features selected
                document.getElementById('featureInfo').innerHTML = 'Multiple features selected' 
              }
              // Every response is sent to updateBasket,
              // which updates according to query mode
              updateBasket(feature);
            }
          }
        }

        function updateBasket (feature) {
          // Update SOMI and HTML baskets
          var basket = somi.tools.query.basket;
          var d = new Date;
          var userBasket = document.getElementById('queryBasket');
          if (somi.tools.query.mode == 'add') {
            if (basket[feature.name] != undefined) {
              // Feature has already been added, skip it
            } else {
              basket[feature.name] = {name: feature.name, layer: somi.tools.query.layer, lon: feature.lon, lat: feature.lat, displayTable: feature.displayTable};
              somi.tools.query.basketModTime = d.getTime();
              // Reduce feature name length if necessary for pulldown
              var fName;
              if (feature.name.length <= 10) {
                fName = feature.name;
              } else {
                fName = feature.name.substring(0,10) + '...'; 
              }
              userBasket.options[userBasket.options.length] = new Option(fName, feature.name);
              // Highlight feature
              var highlight = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(basket[feature.name].lon, basket[feature.name].lat));
              highlight.fid = feature.name; 
              selFeatures.addFeatures(highlight);
            }
          } else if (somi.tools.query.mode == 'remove') {
            if (basket[feature.name] != undefined) {
              // Remove highlight
              for (var key in selFeatures.features) {
                if (selFeatures.features[key].fid == feature.name) {
                  selFeatures.removeFeatures(selFeatures.features[key]); 
                  //selFeatures.destroyFeatures(selFeatures.features[key]); 
                  //selFeatures.redraw();
                }
              }
              // Remove feature from SOMI basket
              delete basket[feature.name];
              somi.tools.query.basketModTime = d.getTime();
              // Update HTML basket in Query toolbox
              for (var i = 1; i < userBasket.options.length; i += 1) { 
                if (userBasket.options[i].value == feature.name) {
                  userBasket.remove(i);
                }
              }
            }
          }
        }

        function updateQuickNav () {
          // Display DD/DMS fields depending upon user's choice
          scaleRefreshHTML = '<select type="pulldown" id="qn_scale"><option value="select">Select scale';
          for (var i=0; i< somi.scales.length; i++) {
            if (i == map.getZoom()) {
              scaleRefreshHTML += '<option id="qns' + i + '" value="' + i + '" selected>' + somi.scales[i];
            } else {
              scaleRefreshHTML += '<option id="qns' + i + '" value="' + i + '">' + somi.scales[i];
            }
          }
          scaleRefreshHTML += '</select><br><br><input type="button" value="Refresh" onClick="quickNavTo();"><br><br>';
          if (somi.tools.quickNav.mode == 'dd') {
            document.getElementById('quickNavInput').innerHTML = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>Lon:</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>Lat:</b>&nbsp;&nbsp;&nbsp;<a href="javascript:void(0);" style="color: red; font-size: 10pt; text-decoration: none" onmouseover="return overlib(\'<center><b>West and South coordinates:</b><br>Enter a negative degree value.</center>\', OFFSETX, 10, WIDTH, 150, FGCOLOR, \'#FFFF33\');" onmouseout="return nd();">Tip</a><br><input type="text" value="' + somi.tools.quickNav.lonDD + '" size=4 maxlength=20 id="qn_londd" name="londd" onchange="" onfocus="">&nbsp;&nbsp;<input type="text" value="' + somi.tools.quickNav.latDD + '" size=4 maxlength=20 id="qn_latdd" name="latdd" onchange="" onfocus="" onblur=""><br><br><center><b>Scale:</b></center>';
            document.getElementById('quickNavInput').innerHTML += scaleRefreshHTML;
          } else if (somi.tools.quickNav.mode == 'dms') {
            document.getElementById('quickNavInput').innerHTML = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>Lon:</b>&nbsp;&nbsp;&nbsp;<a href="javascript:void(0);" style="color: red; font-size: 10pt; text-decoration: none" onmouseover="return overlib(\'<center><b>West and South coordinates:</b><br>Enter a negative degree value.</center>\', OFFSETX, 10, WIDTH, 150, FGCOLOR, \'#FFFF33\');" onmouseout="return nd();">Tip</a><br><input type="text" value="' + somi.tools.quickNav.lonDMSd + '" size=4 maxlength=20 id="qn_lond" name="lond" onchange="" onfocus="" onblur="">&nbsp;&nbsp;<input type="text" value="' + somi.tools.quickNav.lonDMSm + '" size=4 maxlength=20 id="qn_lonm" name="lonm" onchange="" onfocus="" onblur="">&nbsp;&nbsp;<input type="text" value="' + somi.tools.quickNav.lonDMSs + '" size=4 maxlength=20 id="qn_lons" name="lons" onchange="" onfocus="" onblur=""<br><br><b>Lat:</b><br><input type="text" value="' + somi.tools.quickNav.latDMSd + '" size=4 maxlength=20 id="qn_latd" name="latd" onchange="" onfocus="" onblur="">&nbsp;&nbsp;<input type="text" value="' + somi.tools.quickNav.latDMSm + '" size=4 maxlength=20 id="qn_latm" name="latm" onchange="" onfocus="" onblur="">&nbsp;&nbsp;<input type="text" value="' + somi.tools.quickNav.latDMSs + '" size=4 maxlength=20 id="qn_lats" name="lats" onchange="" onfocus="" onblur=""<br><br><b>Scale:</b><br>';
            document.getElementById('quickNavInput').innerHTML += scaleRefreshHTML;
          } else {
            document.getElementById('quickNavInput').innerHTML = '';
          }
        }

        function quickNavTo () {
          // Re-center map at coordinates provided
          if (somi.tools.quickNav.mode == 'dd') { 
            var lon = document.getElementById('qn_londd').value;
            var lat = document.getElementById('qn_latdd').value;
          } else if (somi.tools.quickNav.mode == 'dms') {
            // DMS to DD conversion: http://en.wikipedia.org/wiki/Geographic_coordinate_conversion
            var lond = parseInt(document.getElementById('qn_lond').value);
            var lonm = parseInt(document.getElementById('qn_lonm').value);
            var lons = parseInt(document.getElementById('qn_lons').value);
            if (lond < 0) {
              // West coordinate, process mins/secs accordingly
              var lon = lond - ((lonm*60 + lons)/3600);
            } else { 
              var lon = lond + ((lonm*60 + lons)/3600);
            }
            var latd = parseInt(document.getElementById('qn_latd').value);
            var latm = parseInt(document.getElementById('qn_latm').value);
            var lats = parseInt(document.getElementById('qn_lats').value);
            if (latd < 0) {
              // South coordinate, process mins/secs accordingly
              var lat = latd - ((latm*60 + lats)/3600);
            } else { 
              var lat = latd + ((latm*60 + lats)/3600);
            }
          }
          // Check for valid coordinates and update map accordingly
          if (lon < -180 || lon > 180 || lat < -90 || lat > 90) {
            alert("Please enter a longitude value between -180 and 180, and a latitude value between -90 and 90.");
          } else {
            // Find zoom level closest to user-selected scale
            var zoom = document.getElementById('qn_scale').value;
            map.setCenter(new OpenLayers.LonLat(lon,lat),zoom);
          }
        }

        function refreshLayer(layer) {
          // Set the refresh interval in the individual page
          layer.mergeNewParams({rand: Math.random()});
          //layer.moveTo(layer.map.getExtent(), true);
        }

        function printMap() {
          var printURL = 'http://geomap.ucsd.edu/lib/printMap.php';
          var size = map.getSize();
          // is a scale bar in the map?
          if (scaleBar != null) {
            // do something
          }
          // go through all layers, and collect a list of objects
          // each object is a tile's URL and the tile's pixel location relative to the viewport
          var tiles = [];
          for (layername in map.layers) {
            var layer = map.layers[layername];
            if (typeof layer != "object") continue;
            // if the layer isn't visible at this range or is turned off, skip it
            if (!layer.getVisibility()) continue;
            if (!layer.calculateInRange()) continue;
            
            // iterate through grid's tiles, collecting each tile's extent and pixel location
            for (tilerow in layer.grid) {
              for (tilei in layer.grid[tilerow]) {
                var tile = layer.grid[tilerow][tilei];
                if (tile.bounds == undefined) continue;
                var url = layer.getURL(tile.bounds);
                var position = tile.position;
                var opacity = layer.opacity ? parseInt(100*layer.opacity) : 100;
                tiles[tiles.length] = {url:url, x:position.x, y:position.y, opacity:opacity};
//log.debug("tiles url: " + url + " x: "  + position.x + " y: " + position.y + " opac: " + opacity);  
              }
            }
          }

          // pj, 08/12/2009: if prototype.js is being used, stringify does not work correctly.  
          // use Object.toJSON in this case
          // var tiles_json = JSON.stringify(tiles);
          var tiles_json =  Object.toJSON? Object.toJSON(tiles) :  JSON.stringify(tiles);
          var windowArgs = 'width=' + (size.w+20) + ',height=' + (size.h+20) + ',status=yes,menubar=yes,resizable=yes,scrollbars=yes,screenX=0,screenY=0,top=0,left=0';
          // hand off the list to our server-side script, open new window with image result
          // disable the Print Map button to prevent multiple clicks, then re-enable upon completion
          OpenLayers.Request.POST({url:printURL, data:OpenLayers.Util.getParameterString({width:size.w, height:size.h, tiles:tiles_json}), headers:{"Content-Type":"application/x-www-form-urlencoded"}, callback:function(request){document.getElementById('printStatus').innerHTML=''; document.getElementById('printMap').disabled=false; var newWin=window.open(request.responseText,'_blank',windowArgs); if(!newWin)alert('Printed map image was blocked. Please disable pop-up blocking for this site.');}});
        }

        function setQueryLayer (qLayer) {
          // 'cgps','rtgps','quakes', etc
          // Valid target layers set in html page:
          // somi.tools.query.layers = ['cgps','rtgps','quakes'];
          somi.tools.query.layer = qLayer;
          try {
            document.getElementById(qLayer).selected = true;
          } catch (e) {
            // Query toolbox is not open, do nothing
          }
        }

        function setQueryMode (qMode) {
          // 'add','info','remove'
          somi.tools.query.mode = qMode;
          updateDragHandler();
          try {
            document.getElementById(qMode).selected = true;
          } catch (e) {
            // Query toolbox is not open, do nothing
          }
        }

        function updateQuickNavFields () {
          // Map dragged, panned, or zoomed
          // Calculate new map center coordinates
          var m = map.getCenter();
          // Decimal degrees as strings
          var dLon = m.lon +'';
          var dLat = m.lat +'';
          var ddLon;
          var ddLat;
          somi.tools.quickNav.lonDD = dLon;
          somi.tools.quickNav.latDD = dLat;
          // Degrees minutes seconds - lon
          var ind = dLon.indexOf(".");
          if (ind == -1) {
            // Integer value
            var mmLon = 0;
            var ssLon = 0;
            var intgr = parseInt(dLon);
            if (intgr >= 180) {
              ddLon = intgr - 360;
            } else if (intgr <= -180) {
              ddLon = intgr + 360;
            } else {
              ddLon = intgr;
            };
          } else {
            // Decimal value
            intPart = dLon.substring(0,ind);
            decPart = dLon.substring(ind);
            intFloat = parseFloat(intPart);
            decFloat = parseFloat(decPart);
            if (intFloat >= 180) {
              ddLon = intFloat - 360;
            } else if (intFloat <= -180) {
              ddLon = intFloat + 360;
            } else {
              ddLon = intFloat;
            }
            var mmLon = parseInt(decFloat * 60);
            mmFull = (decFloat * 60)+'';
            mmInd = mmFull.indexOf(".");
            if (mmInd == -1) { 
              // No seconds
              var ssLon = 0;
            } else {
              mmDecPart = mmFull.substring(mmInd);
              var ssLon = parseInt(mmDecPart * 60);
            }
          }
          somi.tools.quickNav.lonDMSd = ddLon;
          somi.tools.quickNav.lonDMSm = mmLon;
          somi.tools.quickNav.lonDMSs = ssLon;

          // Degrees minutes seconds - lat
          var ind = dLat.indexOf(".");
          if (ind == -1) {
            // Integer value
            var mmLat = 0;
            var ssLat = 0;
            var intgr = parseInt(dLat);
            if (intgr >= 90) {
              ddLat = intgr - 180;
            } else if (intgr <= -90) {
              ddLat = intgr + 180;
            } else {
              ddLat = intgr;
            };
          } else {
            // Decimal value
            intPart = dLat.substring(0,ind);
            decPart = dLat.substring(ind);
            intFloat = parseFloat(intPart);
            decFloat = parseFloat(decPart);
            if (intFloat >= 90) {
              ddLat = intFloat - 180;
            } else if (intFloat <= -90) {
              ddLat = intFloat + 180;
            } else {
              ddLat = intFloat;
            }
            var mmLat = parseInt(decFloat * 60);
            mmFull = (decFloat * 60)+'';
            mmInd = mmFull.indexOf(".");
            if (mmInd == -1) { 
              // No seconds
              var ssLat = 0;
            } else {
              mmDecPart = mmFull.substring(mmInd);
              var ssLat = parseInt(mmDecPart * 60);
            }
          }
          somi.tools.quickNav.latDMSd = ddLat;
          somi.tools.quickNav.latDMSm = mmLat;
          somi.tools.quickNav.latDMSs = ssLat;

          // Update QN fields if toolbox open
          var z = map.getZoom();
          var scaleOption = 'qns' + z;
          if (somi.tools.quickNav.mode == 'dd') { 
            if (document.getElementById('qn_londd')) {
              document.getElementById('qn_londd').value = somi.tools.quickNav.lonDD;
              document.getElementById('qn_latdd').value = somi.tools.quickNav.latDD;
              document.getElementById(scaleOption).selected = true;
            }
          } else if (somi.tools.quickNav.mode == 'dms') {
            if (document.getElementById('qn_lond')) {
              document.getElementById('qn_lond').value = somi.tools.quickNav.lonDMSd;
              document.getElementById('qn_lonm').value = somi.tools.quickNav.lonDMSm;
              document.getElementById('qn_lons').value = somi.tools.quickNav.lonDMSs;
              document.getElementById('qn_latd').value = somi.tools.quickNav.latDMSd;
              document.getElementById('qn_latm').value = somi.tools.quickNav.latDMSm;
              document.getElementById('qn_lats').value = somi.tools.quickNav.latDMSs;
              document.getElementById(scaleOption).selected = true;
            }
          }
        }

        function drawVelocity (defaultOptions) {
          var somiVels = somi.tools.velocities;
          var velArray = [];
          var velLayer;
          // Velocity layer names ('hArrow', etc)
          var velNames = [];
          for (var lyr in map.layers) {
            if (map.layers[lyr].name == 'Velocities') velLayer = lyr;
          }
          if (defaultOptions != undefined) {
            // Page is turning on velocities by default
            // Default options should be passed as nested array:
            // { 'layer ('sopacNAM',etc)' : { attribute ('hArrow','hExag',etc) : value ('on','5',etc) } }
            for (var i in defaultOptions) { 
              for (var v in somiVels.layers) { 
                if (i == v) {
                  // Update SOMI and HTML with options
                  somiVels.activeVel = i;
                  for (var attr in defaultOptions[i]) { 
                    somiVels.layers[v][attr] = defaultOptions[i][attr];
                    if (document.getElementById("vel" + attr)) {
                      document.getElementById("vel" + attr) = defaultOptions[i][attr];
                    }
                  }
                  for (var attr in somiVels.layers[v]) { 
                    // Format options as shapefile names for OL
                    var currenthExag = somiVels.layers[v].hExag;
                    var currentvExag = somiVels.layers[v].vExag;
                    if (somiVels.layers[v][attr] == "on") {
                      velNames[velNames.length] = attr;
                      if (attr.substring(0,1) == "h") {
                        // Horizontal option
                        velArray[velArray.length] = attr + "_" + v  + "_" + currenthExag;
                      } else {
                        // Vertical option
                        velArray[velArray.length] = attr + "_" + v  + "_" + currentvExag;
                      }
                    }
                  }
                }
              }
            }
          } else {
            // User has set velocity options and clicked Refresh
            // Update somi global vels array and merge new params
            // Velocity names are "nahArrow3", "pacvEllipse6", etc
            currentVel = document.getElementById("velocitiesSource").value;
            if (!map.layers[velLayer].getVisibility()) {
              // User has not activated the Velocities layer in the map
              alert("Please turn on the Velocities layer in the map.");
            }
            var currenthExag = document.getElementById("velhExag").value;
            var currentvExag = document.getElementById("velvExag").value;
            // Re-draw velocities layer with selected options
            for (var attr in somiVels.layers[currentVel]) {
              if (attr != "name") {
                if (document.getElementById("vel" + attr).value == "on") {
                  somiVels.layers[currentVel][attr] = 'on';
                  velNames[velNames.length] = attr;
                  if (attr.substring(0,1) == "h") {
                    // Horizontal option
                    velArray[velArray.length] = attr + "_" + currentVel  + "_" + currenthExag;
                  } else {
                    // Vertical option
                    velArray[velArray.length] = attr + "_" + currentVel  + "_" + currentvExag;
                  }
                } else if (document.getElementById("vel" + attr).value == "off") {
                  somiVels.layers[currentVel][attr] = 'off';
                } else {
                  // Exaggeration value
                  somiVels.layers[currentVel][attr] = document.getElementById("vel" + attr).value;
                }
              }
            }
          }

          // Move ellipses under arrows
          for (var i=0; i < velNames.length; i++) {
            if (velNames[i].search('Ellipse') > -1) {
              var ellipseLyr = velNames[i];
              velNames.splice(i,1);
              velNames.splice(0,0,ellipseLyr);
            }
          }

          // Velocities map file
          var mF = map.layers[velLayer].url.split('=')
          // String of shapefile names
          velShapes = velArray.join(',');
          // Submit user-selected layers to server for inclusion in map
          OpenLayers.Request.POST({url:'http://geomap.ucsd.edu/lib/updateVelocities.php', data: OpenLayers.Util.getParameterString({mapFile: mF[1], layers:velShapes}), headers:{"Content-Type":"application/x-www-form-urlencoded"},
            callback: function(request) {
              if (request.status == 200) {
                // Have to merge random number here as well
                // If options stay same but velocity changes, layer name
                // is still 'hArrow' etc so OL won't immediately refresh
                map.layers[velLayer].mergeNewParams({layers: velNames, rand: Math.random()});
              } else {
                alert('Error updating velocities.');
              }  
            }
          });
        }

        function updateVelocityOptions () {
          // User has selected a velocity layer in the toolbox
          // Update velocities toolbox options with current/previously chosen values
          var somiVels = somi.tools.velocities;
          var currentVel = document.getElementById("velocitiesSource").value;
          somiVels.activeVel = currentVel;
          for (var attr in somiVels.layers[currentVel]) {
            if (attr != "name") {
              if (somiVels.layers[currentVel][attr] == "on") {
                document.getElementById("vel" + attr).value = "on";
              } else if (somiVels.layers[currentVel][attr] == "off") {
                document.getElementById("vel" + attr).value = "off";
              } else {
                // Exaggeration value
                document.getElementById("vel" + attr).value = somiVels.layers[currentVel][attr];
              }
            }
          }
        }
