PageRenderTime 58ms CodeModel.GetById 15ms app.highlight 37ms RepoModel.GetById 1ms app.codeStats 0ms

/webportal/src/main/java/org/ala/spatial/analysis/web/AddToolSitesBySpeciesComposer.java

http://alageospatialportal.googlecode.com/
Java | 575 lines | 459 code | 84 blank | 32 comment | 120 complexity | 0d9d5ab4fa2105ea40cfd5a9ab664623 MD5 | raw file
  1package org.ala.spatial.analysis.web;
  2
  3import au.com.bytecode.opencsv.CSVReader;
  4import au.org.emii.portal.composer.MapComposer;
  5import au.org.emii.portal.menu.MapLayer;
  6import au.org.emii.portal.menu.MapLayerMetadata;
  7import au.org.emii.portal.util.LayerUtilities;
  8import java.io.StringReader;
  9import java.net.URL;
 10import java.net.URLEncoder;
 11import java.util.ArrayList;
 12import java.util.HashSet;
 13import java.util.List;
 14import org.ala.spatial.data.Facet;
 15import org.ala.spatial.data.Query;
 16import org.ala.spatial.util.CommonData;
 17import org.ala.spatial.data.QueryField;
 18import org.ala.spatial.data.QueryUtil;
 19import org.ala.spatial.data.BiocacheQuery;
 20import org.ala.spatial.data.UploadQuery;
 21import org.ala.spatial.exception.NoSpeciesFoundException;
 22import org.ala.spatial.sampling.SimpleRegion;
 23import org.ala.spatial.sampling.SimpleShapeFile;
 24import org.ala.spatial.util.SelectedArea;
 25import org.ala.spatial.util.Util;
 26import org.apache.commons.httpclient.HttpClient;
 27import org.apache.commons.httpclient.methods.GetMethod;
 28import org.apache.commons.httpclient.methods.PostMethod;
 29import org.zkoss.zhtml.Filedownload;
 30import org.zkoss.zk.ui.Executions;
 31import org.zkoss.zk.ui.event.Event;
 32import org.zkoss.zul.Checkbox;
 33import org.zkoss.zul.Combobox;
 34
 35/**
 36 *
 37 * @author ajay
 38 */
 39public class AddToolSitesBySpeciesComposer extends AddToolComposer {
 40
 41    Checkbox chkOccurrenceDensity;
 42    Checkbox chkSpeciesDensity;
 43    Checkbox chkSitesBySpecies;
 44    Combobox cbMovingAverageSize;
 45
 46    @Override
 47    public void afterCompose() {
 48        super.afterCompose();
 49
 50        this.selectedMethod = "Points To Grid";
 51        this.totalSteps = 3;
 52
 53        this.loadAreaLayers();
 54        this.loadSpeciesLayers(true);
 55        this.updateWindowTitle();
 56
 57    }
 58
 59    @Override
 60    public void onLastPanel() {
 61        System.out.println("**** On last step ****");
 62        super.onLastPanel();
 63        //this.updateName("My Prediction model for " + rgSpecies.getSelectedItem().getLabel());
 64        //this.updateName(getMapComposer().getNextAreaLayerName("Sites By Species"));
 65    }
 66
 67    @Override
 68    public boolean onFinish() {
 69        //super.onFinish();
 70
 71        if (!hasEstimated && !isUserLoggedIn()) {
 72            checkEstimate();
 73            return false;
 74        }
 75
 76        Query query = getSelectedSpecies();
 77        if (query == null) {
 78            getMapComposer().showMessage("There is a problem selecting the species.  Try to select the species again", this);
 79            return false;
 80        }
 81
 82        if (searchSpeciesACComp.hasValidItemSelected()) {
 83            getMapComposer().mapSpeciesFromAutocompleteComponent(searchSpeciesACComp, getSelectedArea(), getGeospatialKosher());
 84        } else if (query != null && rgSpecies.getSelectedItem() != null && rgSpecies.getSelectedItem().getValue().equals("multiple")) {
 85            getMapComposer().mapSpecies(query, "Species assemblage", "species", 0, LayerUtilities.SPECIES, null, -1, MapComposer.DEFAULT_POINT_SIZE, MapComposer.DEFAULT_POINT_OPACITY, MapComposer.nextColour());
 86        }
 87
 88        return runsitesbyspecies();
 89    }
 90    
 91    Query query = null;
 92    SelectedArea sa = null;
 93    
 94    private void setupData() throws Exception {
 95        if (query == null) {
 96            sa = getSelectedArea();
 97            query = QueryUtil.queryFromSelectedArea(getSelectedSpecies(), sa, false, getGeospatialKosher());
 98        }
 99    }
100
101    @Override
102    public long getEstimate() {
103        try {
104            
105            setupData();
106            
107            String ma = "9";
108            if (cbMovingAverageSize.getSelectedItem() == null) {
109                String txt = cbMovingAverageSize.getValue();
110                for (int i = 0; i < cbMovingAverageSize.getItemCount(); i++) {
111                    if (txt != null && txt.equalsIgnoreCase(cbMovingAverageSize.getItemAtIndex(i).getLabel())) {
112                        ma = (String) cbMovingAverageSize.getItemAtIndex(i).getValue();
113                        break;
114                    }
115                }
116            } else {
117                ma = (String) cbMovingAverageSize.getSelectedItem().getValue();
118            }
119            int movingAverageSize = Integer.parseInt(ma);
120            if (movingAverageSize % 2 == 0 || movingAverageSize <= 0 || movingAverageSize >= 16) {
121                getMapComposer().showMessage("Moving average size " + movingAverageSize + " is not valid.  Must be odd and between 1 and 15.", this);
122                return -1;
123            }
124
125            if (!chkOccurrenceDensity.isChecked()
126                    && !chkSitesBySpecies.isChecked()
127                    && !chkSpeciesDensity.isChecked()) {
128                getMapComposer().showMessage("Must select at least one output; Sites by species, Occurrence density or Species richness.", this);
129                return -1;
130            }
131
132            Double gridResolution = dResolution.getValue();
133            //SelectedArea sa = getSelectedArea();
134            SimpleRegion sr = SimpleShapeFile.parseWKT(sa.getWkt());
135            //query = QueryUtil.queryFromSelectedArea(getSelectedSpecies(), sa, false, getGeospatialKosher());
136            int occurrenceCount = query.getOccurrenceCount();
137            int boundingboxcellcount = (int) ((sr.getBoundingBox()[1][0] - sr.getBoundingBox()[0][0])
138                    * (sr.getBoundingBox()[1][1] - sr.getBoundingBox()[0][1])
139                    / (gridResolution * gridResolution));
140
141            System.out.println("SitesBySpecies for " + occurrenceCount + " occurrences in up to " + boundingboxcellcount + " grid cells.");
142
143            if (boundingboxcellcount > settingsSupplementary.getValueAsInt("sitesbyspecies_maxbbcells")) {
144                //getMapComposer().showMessage("Too many potential output grid cells.  Reduce by at least " + String.format("%.2f",100* (1-boundingboxcellcount / (double)settingsSupplementary.getValueAsInt("sitesbyspecies_maxbbcells"))) + "% by decreasing area or increasing resolution.", this);
145                getMapComposer().showMessage("Too many output grid cells: Decrease area or increase grid size.", this);
146                return -1;
147            }
148
149            if (occurrenceCount > settingsSupplementary.getValueAsInt("sitesbyspecies_maxoccurrences")) {
150                getMapComposer().showMessage("Too many occurrences for the selected species in this area.  " + occurrenceCount + " occurrences found, must be less than " + settingsSupplementary.getValueAsInt("sitesbyspecies_maxoccurrences"), this);
151                return -1;
152            }
153
154            StringBuffer sbProcessUrl = new StringBuffer();
155            sbProcessUrl.append(CommonData.satServer + "/ws/sitesbyspecies/estimate?");
156
157            sbProcessUrl.append("speciesq=").append(URLEncoder.encode(QueryUtil.queryFromSelectedArea(query, sa, false, getGeospatialKosher()).getQ(), "UTF-8"));
158
159            sbProcessUrl.append("&gridsize=" + URLEncoder.encode(String.valueOf(gridResolution), "UTF-8"));
160            sbProcessUrl.append("&bs=" + URLEncoder.encode(((BiocacheQuery) query).getBS(), "UTF-8"));
161
162            if (chkOccurrenceDensity.isChecked()) {
163                sbProcessUrl.append("&occurrencedensity=1");
164            }
165            if (chkSpeciesDensity.isChecked()) {
166                sbProcessUrl.append("&speciesdensity=1");
167            }
168            if (chkSitesBySpecies.isChecked()) {
169                sbProcessUrl.append("&sitesbyspecies=1");
170            }
171
172            sbProcessUrl.append("&movingaveragesize=" + ma);
173
174            String areaSqKm = "0";
175            if (sa.getMapLayer() != null && sa.getMapLayer().getData("area") != null) {
176                areaSqKm = (String) sa.getMapLayer().getData("area");
177            } else {
178                areaSqKm = String.format("%,.2f", Util.calculateArea(sa.getWkt()) / 1000000.0);
179            }
180            sbProcessUrl.append("&areasqkm=" + areaSqKm);
181
182
183            HttpClient client = new HttpClient();
184            PostMethod get = new PostMethod(sbProcessUrl.toString());
185
186            String area = null;
187            if (sa.getMapLayer() != null && sa.getMapLayer().getData("envelope") != null) {
188                area = "ENVELOPE(" + (String) sa.getMapLayer().getData("envelope") + ")";
189            } else {
190                area = sa.getWkt();
191            }
192            if (getSelectedArea() != null) {
193                get.addParameter("area", area);
194            }
195            get.addParameter("qname", query.getName());
196
197            get.addRequestHeader("Accept", "text/plain");
198
199            int result = client.executeMethod(get);
200            String estimate = get.getResponseBodyAsString();
201
202            return Long.valueOf(estimate);
203            
204        } catch (Exception e) {
205            System.out.println("Unable to get estimates");
206            e.printStackTrace(System.out);
207        }
208
209        return -1;
210    }
211
212    public boolean runsitesbyspecies() {
213        try {
214            
215            setupData();
216            
217            String ma = "9";
218            if (cbMovingAverageSize.getSelectedItem() == null) {
219                String txt = cbMovingAverageSize.getValue();
220                for (int i = 0; i < cbMovingAverageSize.getItemCount(); i++) {
221                    if (txt != null && txt.equalsIgnoreCase(cbMovingAverageSize.getItemAtIndex(i).getLabel())) {
222                        ma = (String) cbMovingAverageSize.getItemAtIndex(i).getValue();
223                        break;
224                    }
225                }
226            } else {
227                ma = (String) cbMovingAverageSize.getSelectedItem().getValue();
228            }
229            int movingAverageSize = Integer.parseInt(ma);
230            if (movingAverageSize % 2 == 0 || movingAverageSize <= 0 || movingAverageSize >= 16) {
231                getMapComposer().showMessage("Moving average size " + movingAverageSize + " is not valid.  Must be odd and between 1 and 15.", this);
232                return false;
233            }
234
235            if (!chkOccurrenceDensity.isChecked()
236                    && !chkSitesBySpecies.isChecked()
237                    && !chkSpeciesDensity.isChecked()) {
238                getMapComposer().showMessage("Must select at least one output; Sites by species, Occurrence density or Species richness.", this);
239                return false;
240            }
241
242            Double gridResolution = dResolution.getValue();
243            //SelectedArea sa = getSelectedArea();
244            SimpleRegion sr = SimpleShapeFile.parseWKT(sa.getWkt());
245            //Query query = QueryUtil.queryFromSelectedArea(getSelectedSpecies(), sa, false, getGeospatialKosher());
246            int occurrenceCount = query.getOccurrenceCount();
247            int boundingboxcellcount = (int) ((sr.getBoundingBox()[1][0] - sr.getBoundingBox()[0][0])
248                    * (sr.getBoundingBox()[1][1] - sr.getBoundingBox()[0][1])
249                    / (gridResolution * gridResolution));
250
251            System.out.println("SitesBySpecies for " + occurrenceCount + " occurrences in up to " + boundingboxcellcount + " grid cells.");
252
253            if (boundingboxcellcount > settingsSupplementary.getValueAsInt("sitesbyspecies_maxbbcells")) {
254                //getMapComposer().showMessage("Too many potential output grid cells.  Reduce by at least " + String.format("%.2f",100* (1-boundingboxcellcount / (double)settingsSupplementary.getValueAsInt("sitesbyspecies_maxbbcells"))) + "% by decreasing area or increasing resolution.", this);
255                getMapComposer().showMessage("Too many output grid cells: Decrease area or increase grid size.", this);
256                return false;
257            }
258
259            if (occurrenceCount > settingsSupplementary.getValueAsInt("sitesbyspecies_maxoccurrences")) {
260                getMapComposer().showMessage("Too many occurrences for the selected species in this area.  " + occurrenceCount + " occurrences found, must be less than " + settingsSupplementary.getValueAsInt("sitesbyspecies_maxoccurrences"), this);
261                return false;
262            }
263
264            StringBuffer sbProcessUrl = new StringBuffer();
265            sbProcessUrl.append(CommonData.satServer + "/ws/sitesbyspecies?");
266
267            sbProcessUrl.append("speciesq=").append(URLEncoder.encode(QueryUtil.queryFromSelectedArea(query, sa, false, getGeospatialKosher()).getQ(), "UTF-8"));
268
269            sbProcessUrl.append("&gridsize=" + URLEncoder.encode(String.valueOf(gridResolution), "UTF-8"));
270            sbProcessUrl.append("&bs=" + URLEncoder.encode(((BiocacheQuery) query).getBS(), "UTF-8"));
271
272            if (chkOccurrenceDensity.isChecked()) {
273                sbProcessUrl.append("&occurrencedensity=1");
274            }
275            if (chkSpeciesDensity.isChecked()) {
276                sbProcessUrl.append("&speciesdensity=1");
277            }
278            if (chkSitesBySpecies.isChecked()) {
279                sbProcessUrl.append("&sitesbyspecies=1");
280            }
281
282            sbProcessUrl.append("&movingaveragesize=" + ma);
283
284            String areaSqKm = "0";
285            if (sa.getMapLayer() != null && sa.getMapLayer().getData("area") != null) {
286                areaSqKm = (String) sa.getMapLayer().getData("area");
287            } else {
288                areaSqKm = String.format("%,.2f", Util.calculateArea(sa.getWkt()) / 1000000.0);
289            }
290            sbProcessUrl.append("&areasqkm=" + areaSqKm);
291
292
293            HttpClient client = new HttpClient();
294            PostMethod get = new PostMethod(sbProcessUrl.toString());
295
296            String area = null;
297            if (sa.getMapLayer() != null && sa.getMapLayer().getData("envelope") != null) {
298                area = "ENVELOPE(" + (String) sa.getMapLayer().getData("envelope") + ")";
299            } else {
300                area = sa.getWkt();
301            }
302            if (getSelectedArea() != null) {
303                get.addParameter("area", area);
304            }
305            get.addParameter("qname", query.getName());
306
307            get.addRequestHeader("Accept", "text/plain");
308
309            int result = client.executeMethod(get);
310            pid = get.getResponseBodyAsString();
311
312            openProgressBar();
313
314            StringBuffer sbParams = new StringBuffer();
315
316            this.setVisible(false);
317
318            try {
319                String extras = "";
320                extras += "gridsize=" + String.valueOf(gridResolution);
321                extras += "|occurrencedensity=1";
322                extras += "|speciesdensity=1";
323                extras += "|sitesbyspecies=1";
324                extras += "|movingaveragesize=" + ma;
325
326                if (query instanceof BiocacheQuery) {
327                    BiocacheQuery bq = (BiocacheQuery) query;
328                    extras = bq.getWS() + "|" + bq.getBS() + "|" + bq.getFullQ(false) + "|" + extras;
329                    remoteLogger.logMapAnalysis("species to grid", "Tool - Species to Grid", area, bq.getLsids(), "", pid, extras, "STARTED");
330                } else if (query instanceof UploadQuery) {
331                    remoteLogger.logMapAnalysis("species to grid", "Tool - Species to Grid", area, ((UploadQuery) query).getQ(), "", pid, extras, "STARTED");
332                } else {
333                    remoteLogger.logMapAnalysis("species to grid", "Tool - Species to Grid", area, "", "", pid, extras, "STARTED");
334                }
335            } catch (Exception e) {
336                e.printStackTrace();
337            }
338
339            return true;
340        } catch (Exception e) {
341            System.out.println("SitesBySpecies error: ");
342            e.printStackTrace(System.out);
343            getMapComposer().showMessage("Unknown error.", this);
344        }
345        return false;
346    }
347
348    @Override
349    public void loadMap(Event event) {
350        try {
351            if (chkOccurrenceDensity.isChecked()) {
352                String mapurl = CommonData.geoServer + "/wms?service=WMS&version=1.1.0&request=GetMap&layers=ALA:odensity_" + pid + "&styles=odensity_" + pid + "&FORMAT=image%2Fpng";
353                String legendurl = CommonData.geoServer
354                        + "/wms?REQUEST=GetLegendGraphic&VERSION=1.0.0&FORMAT=image/png&WIDTH=10&HEIGHT=1"
355                        + "&LAYER=ALA:odensity_" + pid
356                        + "&STYLE=odensity_" + pid;
357
358                System.out.println(legendurl);
359
360//                String layername = tToolName.getValue();
361                String layername = getMapComposer().getNextAreaLayerName("Occurrence Density");
362                getMapComposer().addWMSLayer(pid + "_odensity", layername, mapurl, (float) 0.5, null, legendurl, LayerUtilities.ODENSITY, null, null);
363                MapLayer ml = getMapComposer().getMapLayer(pid + "_odensity");
364                ml.setData("pid", pid + "_odensity");
365                String infoUrl = CommonData.satServer + "/output/sitesbyspecies/" + pid + "/odensity_metadata.html";
366                MapLayerMetadata md = ml.getMapLayerMetadata();
367                if (md == null) {
368                    md = new MapLayerMetadata();
369                    ml.setMapLayerMetadata(md);
370                }
371                md.setMoreInfo(infoUrl + "\nOccurrence Density\npid:" + pid);
372                md.setId(Long.valueOf(pid));
373
374                //perform intersection on user uploaded layers so you can facet on this layer
375                getMapComposer().addAnalysisLayerToUploadedCoordinates(pid + "_odensity", layername);
376            }
377
378            if (chkSpeciesDensity.isChecked()) {
379                String mapurl = CommonData.geoServer + "/wms?service=WMS&version=1.1.0&request=GetMap&layers=ALA:srichness_" + pid + "&styles=srichness_" + pid + "&FORMAT=image%2Fpng";
380                String legendurl = CommonData.geoServer
381                        + "/wms?REQUEST=GetLegendGraphic&VERSION=1.0.0&FORMAT=image/png&WIDTH=10&HEIGHT=1"
382                        + "&LAYER=ALA:srichness_" + pid
383                        + "&STYLE=srichness_" + pid;
384
385                System.out.println(legendurl);
386
387//                String layername = tToolName.getValue();
388                String layername = getMapComposer().getNextAreaLayerName("Species Richness");
389                getMapComposer().addWMSLayer(pid + "_srichness", layername, mapurl, (float) 0.5, null, legendurl, LayerUtilities.SRICHNESS, null, null);
390                MapLayer ml = getMapComposer().getMapLayer(pid + "_srichness");
391                ml.setData("pid", pid + "_srichness");
392                String infoUrl = CommonData.satServer + "/output/sitesbyspecies/" + pid + "/srichness_metadata.html";
393                MapLayerMetadata md = ml.getMapLayerMetadata();
394                if (md == null) {
395                    md = new MapLayerMetadata();
396                    ml.setMapLayerMetadata(md);
397                }
398                md.setMoreInfo(infoUrl + "\nSpecies Richness\npid:" + pid);
399                md.setId(Long.valueOf(pid));
400
401                //perform intersection on user uploaded layers so you can facet on this layer
402                getMapComposer().addAnalysisLayerToUploadedCoordinates(pid + "_srichness", layername);
403            }
404
405            // set off the download as well
406            String fileUrl = CommonData.satServer + "/ws/download/" + pid;
407            Filedownload.save(new URL(fileUrl).openStream(), "application/zip", "sites_by_species.zip");
408        } catch (Exception ex) {
409            System.out.println("Error generating download for prediction model:");
410            ex.printStackTrace(System.out);
411        }
412
413        this.detach();
414    }
415
416    void openProgressBar() {
417        ProgressWCController window = (ProgressWCController) Executions.createComponents("WEB-INF/zul/AnalysisProgress.zul", getMapComposer(), null);
418        window.parent = this;
419        window.start(pid, "Points to Grid");
420        try {
421            window.doModal();
422        } catch (Exception e) {
423            e.printStackTrace();
424        }
425    }
426
427    String getJob(String type) {
428        try {
429            StringBuffer sbProcessUrl = new StringBuffer();
430            sbProcessUrl.append(CommonData.satServer + "/ws/jobs/").append(type).append("?pid=").append(pid);
431
432            System.out.println(sbProcessUrl.toString());
433            HttpClient client = new HttpClient();
434            GetMethod get = new GetMethod(sbProcessUrl.toString());
435
436            get.addRequestHeader("Accept", "text/plain");
437
438            int result = client.executeMethod(get);
439            String slist = get.getResponseBodyAsString();
440            System.out.println(slist);
441            return slist;
442        } catch (Exception e) {
443            e.printStackTrace();
444        }
445        return "";
446    }
447
448    /**
449     * get CSV of speciesName, longitude, latitude in [0] and
450     *
451     * @param selectedSpecies
452     * @param area
453     * @return
454     */
455    private String[] getSpeciesData(Query query) throws NoSpeciesFoundException {
456        if (query instanceof UploadQuery) {
457            //no sensitive records in upload
458            ArrayList<QueryField> fields = new ArrayList<QueryField>();
459            String lsidFieldName = query.getSpeciesIdFieldName();
460            QueryField qf = null;
461            if (lsidFieldName != null) {
462                qf = new QueryField(query.getSpeciesIdFieldName());
463                qf.setStored(true);
464                fields.add(qf);
465            }
466            double[] points = query.getPoints(fields);
467            StringBuilder sb = null;
468            if (points != null) {
469                sb = new StringBuilder();
470                for (int i = 0; i < points.length; i += 2) {
471                    if (sb.length() == 0) {
472                        //header
473                        sb.append("species,longitude,latitude");
474                    }
475                    sb.append("\nspecies,").append(points[i]).append(",").append(points[i + 1]);
476                }
477            }
478
479            String[] out = {((sb == null) ? null : sb.toString()), null};
480            return out;
481        } else {
482            //identify sensitive species records
483            List<String[]> sensitiveSpecies = null;
484            try {
485                String sensitiveSpeciesRaw = new BiocacheQuery(null, null, "sensitive:[* TO *]", null, false, getGeospatialKosher()).speciesList();
486                CSVReader csv = new CSVReader(new StringReader(sensitiveSpeciesRaw));
487                sensitiveSpecies = csv.readAll();
488                csv.close();
489            } catch (Exception e) {
490                e.printStackTrace();
491            }
492            HashSet<String> sensitiveSpeciesFound = new HashSet<String>();
493            HashSet<String> sensitiveLsids = new HashSet<String>();
494
495            //add to 'identified' sensitive list
496            try {
497                CSVReader csv = new CSVReader(new StringReader(query.speciesList()));
498                List<String[]> fullSpeciesList = csv.readAll();
499                csv.close();
500                for (int i = 0; i < fullSpeciesList.size(); i++) {
501                    String[] sa = fullSpeciesList.get(i);
502                    for (String[] ss : sensitiveSpecies) {
503                        if (sa != null && sa.length > 4
504                                && ss != null && ss.length > 4
505                                && sa[4].equals(ss[4])) {
506                            sensitiveSpeciesFound.add(ss[4] + "," + ss[1] + "," + ss[3]);
507                            sensitiveLsids.add(ss[4]);
508                            break;
509                        }
510                    }
511                }
512            } catch (Exception e) {
513                e.printStackTrace();
514            }
515
516            //remove sensitive records that will not be LSID matched
517            Query maxentQuery = query.newFacet(new Facet("sensitive", "[* TO *]", false), false);
518            ArrayList<QueryField> fields = new ArrayList<QueryField>();
519            String lsidFieldName = maxentQuery.getSpeciesIdFieldName();
520            QueryField qf = null;
521            if (lsidFieldName != null) {
522                qf = new QueryField(maxentQuery.getSpeciesIdFieldName());
523                qf.setStored(true);
524                fields.add(qf);
525            }
526            double[] points = maxentQuery.getPoints(fields);
527            StringBuilder sb = null;
528            if (points != null) {
529                sb = new StringBuilder();
530                for (int i = 0; i < points.length; i += 2) {
531                    boolean isSensitive = false;
532                    if (qf != null) {
533                        String lsid = qf.getAsString(i / 2);
534                        isSensitive = sensitiveLsids.contains(lsid);
535                    }
536                    if (!isSensitive) {
537                        if (sb.length() == 0) {
538                            //header
539                            sb.append("species,longitude,latitude");
540                        }
541                        sb.append("\nspecies,").append(points[i]).append(",").append(points[i + 1]);
542                    }
543                }
544            }
545
546            //collate sensitive species found, no header
547            StringBuilder sen = new StringBuilder();
548            for (String s : sensitiveSpeciesFound) {
549                sen.append(s).append("\n");
550            }
551
552            String[] out = {((sb == null) ? null : sb.toString()), (sen.length() == 0) ? null : sen.toString()};
553            return out;
554        }
555    }
556
557    @Override
558    void fixFocus() {
559        switch (currentStep) {
560            case 1:
561                rgArea.setFocus(true);
562                break;
563            case 2:
564                if (rSpeciesSearch.isChecked()) {
565                    searchSpeciesACComp.getAutoComplete().setFocus(true);
566                } else {
567                    rgSpecies.setFocus(true);
568                }
569                break;
570            case 3:
571                dResolution.setFocus(true);
572                break;
573        }
574    }
575}