package com.algobase.map;

import java.io.File;
import java.util.Iterator;
import java.util.Vector;
import java.util.Stack;

import android.os.Handler;

import android.content.Context;
import android.content.res.Resources;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Typeface;
import android.location.Location;

import com.algobase.stracks.sTracksRoot;

import com.algobase.share.geo.Geometry;
import com.algobase.share.maps.*;


public class MapOverlay implements MyMapView.IMapOverlay 
{
    static final int EARTH_RADIUS = 6371000;

    float dpi;

    Vector<Location> vec_course;
    Vector<Location> vec_course_simple;

    Vector<Location> vec_track;
    Vector<Location> vec_track_simple;

    Vector<Location> vec_breaks;
    Vector<Location> vec_wpoints;
    Vector<String>   vec_wpoint_names;
    Vector<Location> vec_calibration_points;

    Bitmap  homeBitmap = null;
    Bitmap  wpBitmap = null;

    String language = "English";

    String selected_tile;

    File srtm3_folder;

    Location current_point;
    Location current_track_point;

    Location home_point = null;
    Location course_point = null;

    Location last_loc;

    Paint   paint;

    Path arrow_path;
    Path path;
    
    //IMapView map_view;
    MyMapView map_view;

    boolean locked = false;
    boolean show_srtm3_tiles = false;

    boolean invalid = false;

    boolean show_waypoints = true;
    boolean show_compass = false;

    double accuracy;
    double lat_min;
    double lat_max;
    double lon_min;
    double lon_max;

    boolean stopped = false;
    boolean animate_points;

    boolean srtm3_points = false;
    boolean show_calibration_points = false;

    boolean draw_bounding_box = false;

    // dp units
    float track_width;
    float course_width;
    float node_width;

    int track_color;
    int course_color;

    int simplify_bound = 1000;
    float simplify_eps = 25;

    boolean simplify_running = false;


    public void writeLog(String txt) {}
    public void showToast(String txt) {}


    private void simplify(final Vector<Location> vec_trk,
                          final Vector<Location> vec_trk_simple)
    { 
        if (simplify_running) return;

        final int sz = vec_trk.size();

        if (sz < 3) return;

        final Location[] track =  new Location[sz];

        synchronized(vec_trk) { 
          vec_trk.toArray(track);
          vec_trk.clear();
        }

        new Thread() {
          public void run() { 
           simplify_running = true;
           int n = Geometry.DouglasPeucker(track,vec_trk_simple,simplify_eps);
           writeLog(String.format("Overlay Simplify: %d --> %d",sz,n));
           map_view.postInvalidate(); 
           simplify_running = false;
          }
        }.start();

    }

    public void unlock() { 
      //showToast("unlock overlay");
      locked = false; 
      map_view.postInvalidate(); 
     }

    public void lock() { 
      //showToast("lock overlay");
      locked = true; 
    }

    public boolean isLocked() { return locked; }

    @Override
    public void invalidate() { 
     invalid = true; 
    }

    @Override
    public boolean isInvalid() { return invalid; }

    @Override
    public void setMapView(MyMapView mview) { map_view = mview; }


    public MapOverlay(Context context) 
    { 
      dpi = context.getResources().getDisplayMetrics().densityDpi;

      vec_track = new Vector<Location>();
      vec_track_simple = new Vector<Location>();
      vec_breaks = new Vector<Location>();
      vec_wpoints = new Vector<Location>();
      vec_wpoint_names = new Vector<String>();
      vec_calibration_points = new Vector<Location>();

      vec_course = new Vector<Location>();
      vec_course_simple = new Vector<Location>();

      current_point = null;
      current_track_point = null;
     
      accuracy = 0;
      last_loc = null;

      animate_points = true;
      track_width = 5.5f;
      course_width = 8;
      node_width = 6;

      track_color = Color.RED;
      course_color = Color.BLUE;

      lon_min = +180;
      lon_max = -180;
      lat_min =  +90;
      lat_max =  -90;

      paint = new Paint();
      paint.setDither(true);
      paint.setAntiAlias(true);
      paint.setColor(Color.RED);
      paint.setStyle(Paint.Style.STROKE);
      paint.setStrokeJoin(Paint.Join.ROUND);
      paint.setStrokeCap(Paint.Cap.ROUND);
      paint.setStyle(Paint.Style.STROKE);
      paint.setStrokeWidth(1);

      float d = 1.1f * track_width * (dpi/160f);

      path = new Path();
      arrow_path = new Path();

      arrow_path.moveTo( -1*d,    0);
      arrow_path.lineTo( -2*d,  2*d);
      arrow_path.lineTo(  2*d,    0);
      arrow_path.lineTo( -2*d, -2*d);
      arrow_path.close();

     }


    public void reset_bounding_box()
    { lon_min = +180;
      lon_max = -180;
      lat_min =  +90;
      lat_max =  -90;
     }

    public void reset()
    { current_point = null;
      current_track_point = null;
      last_loc = null;
      vec_track.clear();
      vec_track_simple.clear();
      vec_breaks.clear();
      vec_calibration_points.clear();
      reset_bounding_box();

      vec_course.clear();
      vec_course_simple.clear();

      vec_wpoints.clear();
      vec_wpoint_names.clear();
     }

    public void clear_track()  
    { current_point = null;
      current_track_point = null;
      last_loc = null;
      vec_track.clear();  
      vec_track_simple.clear(); 
      vec_breaks.clear();
      vec_calibration_points.clear();
      reset_bounding_box();
     }

    public void clear_course() { 
       vec_course.clear(); 
       vec_course_simple.clear();
    }

    public void clear_breaks() { vec_breaks.clear(); }

    public void clear_wpoints() 
    { vec_wpoints.clear(); 
      vec_wpoint_names.clear(); 
     }

    public void clear_srtm3_points() { vec_calibration_points.clear(); }

    public void set_animation(boolean b)    { animate_points = b; }
    public void set_srtm3_points(boolean b) { srtm3_points = b; }

    public void set_selected_tile(String tile) { selected_tile = tile; }

    public void set_srtm3_folder(File file) { srtm3_folder = file; }

    public void set_calibration_points(boolean b) 
    { show_calibration_points = b; }

    public void set_simplify_bound(int n) { simplify_bound = n; }
    public int  get_simplify_bound() { return simplify_bound; }

    public void set_simplify_eps(float eps) { simplify_eps = eps; }
    public float get_simplify_eps() { return simplify_eps; }

    public int  get_track_length() { 
         return vec_track.size() + vec_track_simple.size(); 
    }

    public int  get_course_length() { 
         return vec_course.size() + vec_course_simple.size(); 
    }

    public void set_track_width(int w) { track_width = 0.5f * w; }
    public void set_track_color(int c) { track_color = c; }
    public void set_node_width(int w)  { node_width = 0.5f * w; }

    public void set_course_width(int w) { course_width = 0.5f * w; }
    public void set_course_color(int c) { course_color = c; }

    public boolean get_animation()    { return animate_points; }
    public boolean get_srtm3_points() { return srtm3_points; }
    public boolean get_calibration_points() { return show_calibration_points; }

    public int get_track_width() { return (int)(2*track_width); }
    public int get_node_width()  { return (int)(2*node_width); }
    public int get_track_color() { return track_color; }

    public int get_course_width() { return (int)(2*course_width); }
    public int get_course_color() { return course_color; }

    public void    set_show_waypoints(boolean b) { show_waypoints = b; }
    public boolean get_show_waypoints() { return show_waypoints; }

    public void    set_show_compass(boolean b) { show_compass = b; }
    public boolean get_show_compass(boolean b) { return show_compass; }

    public void set_show_srtm3_tiles(boolean b) { 
      show_srtm3_tiles = b; 
      if (b) map_view.setZoom(9);
    }
 

    public void zoomToSRTM3() 
    {  
      //showToast("zoomToSRTM3");

      File[] files = srtm3_folder.listFiles();

      if (files.length == 0) return;

      double srtm3_lat_min = +90;
      double srtm3_lat_max = -90;
      double srtm3_lon_min = +180;
      double srtm3_lon_max = -180;

      for(int i=0; i<files.length; i++)
      { String fname = files[i].getName();

        if (!fname.endsWith(".hgt.zip")) continue;

        String tile = fname.replace(".hgt.zip","");

        int lat = Integer.parseInt(tile.substring(1,3)); 
        if (tile.substring(0,1).equals("S")) lat = -lat;
        int lon = Integer.parseInt(tile.substring(4,7)); 
        if (tile.substring(3,4).equals("W")) lon = -lon;

        if (lon < srtm3_lon_min) srtm3_lon_min = lon;
        if (lon+1 > srtm3_lon_max) srtm3_lon_max = lon+1;
        if (lat < srtm3_lat_min) srtm3_lat_min = lat;
        if (lat+1 > srtm3_lat_max) srtm3_lat_max = lat+1;
      }

      showToast(String.format("[%.0f --- %.0f] x [%.0f --- %.0f]",
                srtm3_lon_min,srtm3_lon_max,srtm3_lat_min,srtm3_lat_max));

      //double d = 1;
      double d = 0.5;

      map_view.zoomToFit(srtm3_lat_min-d,srtm3_lon_min-d,
                         srtm3_lat_max+d,srtm3_lon_max+d);
    }



    public void zoomToPath() 
    {  
      if (show_srtm3_tiles)
      { zoomToSRTM3();
        return;
       }

      if (vec_track.isEmpty() && vec_course.isEmpty()
                              && vec_track_simple.isEmpty() 
                              && vec_course_simple.isEmpty()) 
        { if (current_point != null)
          { // zoom to current point and reset rotation
            map_view.setAnimFinish( new Runnable() {
               public void run() { map_view.setRotationAnim(0); }
            }, 100);

            map_view.animateTo(current_point,15);
           }
        }
      else
        map_view.zoomToFit(lat_min,lon_min,lat_max,lon_max);
    }


    public void setHome(Location loc) { home_point = loc; }

    public void setHomeBitmap(Bitmap bmp) { homeBitmap = bmp; }

    public void setWaypointBitmap(Bitmap bmp) { wpBitmap = bmp; }

    public void setCoursePoint(Location loc) { course_point = loc; }


    public void setCenter(Location loc, boolean anim)
    { if (loc == null) return;
      double lat = loc.getLatitude();
      double lon = loc.getLongitude();
      if (anim)
      { float heading = map_view.getHeading();
        if (show_compass)
           map_view.setCenter(lat,lon);
        else
           map_view.animateTo(lat,lon,-1,heading);
       }
      else
        map_view.setCenter(lat,lon);
    }


    public Location getPoint() { return current_point; }


    public void setPoint(Location loc, boolean anim)
    {
      if (loc == null || map_view == null) return;

      current_point = loc;
      accuracy = loc.getAccuracy();

      if (!locked && anim && animate_points 
                          && loc.distanceTo(map_view.getCenter()) > 3) { 
        if (show_compass)
          map_view.setCenterSilent(loc);
        else
          map_view.animateTo(loc);
       }

    }


    public void addPoint(Vector<Location> vec, Location loc, 
                                               boolean update_bounds,
                                               boolean anim)
    { 
      if (vec != vec_wpoints) {
        // ignore positions close to last location of vec
        if (!vec.isEmpty() && loc.distanceTo(vec.lastElement()) < 1) return;
      }

      double lat = loc.getLatitude();
      double lon = loc.getLongitude();

      if (update_bounds)
      { if (lon < lon_min) lon_min = lon;
        if (lat < lat_min) lat_min = lat;
        if (lon > lon_max) lon_max = lon;
        if (lat > lat_max) lat_max = lat;
       }

      synchronized(vec) {
          vec.add(loc);
      }

      if (!locked && anim && animate_points) 
      { float heading = map_view.getHeading();
        if (show_compass)
          map_view.setCenter(lat,lon);
        else
          map_view.animateTo(lat,lon,-1,heading);
       }
    }
    

    public void addTrackPoint(Location loc)
    { 
      if (loc == null) { 
        // should never happen
        return;
      }

      current_track_point = loc;

      addPoint(vec_track,loc,true,true);

      accuracy = 0;
      current_point = null;

      if (simplify_bound > 0 && vec_track.size() >= simplify_bound) {
        simplify(vec_track,vec_track_simple);
      }

      invalidate();
    }


    public void finishTrack() { 
      invalidate();
      if (simplify_bound > 0 && vec_track.size() > 100)
        simplify(vec_track,vec_track_simple);
      zoomToPath();
    }


    public void addCoursePoint(Location loc) {
      addPoint(vec_course,loc,true,false); 
      if (simplify_bound > 0 && vec_course.size() >= simplify_bound) {
        simplify(vec_course,vec_course_simple);
      }
      invalidate();
    }


    public void addBreak(Location loc) { 
      addPoint(vec_breaks,loc,true,false); 
      invalidate();
    }

    public void addWayPoint(String name, Location loc, boolean anim)
    { vec_wpoint_names.add(name);
      addPoint(vec_wpoints,loc,false,anim);
     }

    public void addCalibrationPoint(Location loc) { 
      addPoint(vec_calibration_points,loc,false,false);
      invalidate();
     }



    public void drawAccuracyDisk(Canvas canvas, Location loc)
    { 
      if (loc == null) return;

      Point p = new Point();
      map_view.toPixels(loc,p);

      float acc = (float)accuracy;
      float r = map_view.metersToEquatorPixels(acc);
      r /= Math.cos(Math.toRadians(loc.getLatitude()));

      if (r < 12) return;

      if (map_view.isSatellite())
         //paint.setARGB(48,255,255,64);
         paint.setARGB(48,255,255,96);
      else
         //paint.setARGB(32,64,64,255);
         paint.setARGB(32,96,96,255);

      paint.setStyle(Paint.Style.FILL);
      canvas.drawCircle(p.x, p.y, r, paint);
      
      if (map_view.isSatellite())
         //paint.setARGB(255,255,255,64);
         paint.setARGB(255,255,255,96);
      else
         //paint.setARGB(255,64,64,255);
         paint.setARGB(255,96,96,255);

      paint.setStyle(Paint.Style.STROKE);
      paint.setStrokeWidth(1);

      canvas.drawCircle(p.x, p.y,r,paint);
    }
    
    public void drawBitmap(Canvas canvas, int x, int y, Bitmap bmp, 
                                                        boolean use_filter)
    {
      int w = bmp.getWidth();
      int h = bmp.getHeight();

      float[] f;

      if (map_view.isSatellite())
          f = new float[] {2.5f, 0,    0,    0, 0, 
                           0,    2.5f, 0,    0, 0, 
                           0,    0,    1.0f, 0, 0, 
                           0,    0,    0,    1, 0};
      else
/*
          f = new float[] {0.5f, 0,    0,    0,    0, 
                           0,    0,    0,    0,    0, 
                           0,    0,    2.5f, 0,    0, 
                           0,    0,    0,    0.5f, 0};
*/
          f = new float[] {0,    0,    0,    0,    0, 
                           0,    0,    0,    0,    0, 
                           0,    0,    1,    0,    0, 
                           0,    0,    0,    0.75f, 0};

      ColorMatrixColorFilter filter = 
                              new ColorMatrixColorFilter(new ColorMatrix(f));

      Paint paint = new Paint();
      paint.setColorFilter(filter);

      if (use_filter)
        canvas.drawBitmap(bmp, x-w/2, y-h/2, paint);
      else
        canvas.drawBitmap(bmp, x-w/2, y-h/2, null);
    }
    
    public void drawArrow(Canvas canvas, Location loc1, Location loc2, int clr)
    { Point p = new Point();
      map_view.toPixels(loc1,p);
      Point q = new Point();
      map_view.toPixels(loc2,q);
      paint.setColor(clr);
      paint.setStrokeWidth(5);
      canvas.drawLine(p.x,p.y,q.x,q.y,paint);

      //if (arrow) 
      { float d = 2*node_width*(dpi/160f);
        drawArrowShape(canvas,p,q,d);
       }
    }
      
      
    
    public void drawPoint(Canvas canvas,Location loc,int clr,boolean crosshairs)
    {    	
      if (loc == null) return;

      Point p = new Point();
      map_view.toPixels(loc,p);

      int w = (int)(0.5f + node_width * (dpi/160f));

      if (crosshairs && !show_compass)
      { 
        int d = 5000;

  
        if (map_view.isSatellite())
          paint.setColor(Color.WHITE);
        else
          paint.setColor(0x80707070);

        paint.setStrokeWidth(dpi/160);
        paint.setStyle(Paint.Style.STROKE);

        canvas.save();
        canvas.translate(p.x,p.y);
        canvas.drawLine(w,0,d,0,paint);
        canvas.drawLine(-w,0,-d,0,paint);
        canvas.drawLine(0,w,0,d,paint);
        canvas.drawLine(0,-w,0,-d,paint);
        canvas.restore();
      }

      paint.setColor(clr);
      paint.setStyle(Paint.Style.FILL);
      canvas.drawCircle(p.x, p.y, w, paint);
    
      if (map_view.isSatellite())
        paint.setColor(Color.WHITE);
      else
        paint.setColor(Color.BLACK);

      paint.setStrokeWidth(1);
      paint.setStyle(Paint.Style.STROKE);
      canvas.drawCircle(p.x, p.y, w, paint);
    }
    

    public void drawArrowShape(Canvas canvas, float px, float py, 
                                              float qx, float qy, float off) 
    {
      float phi = (float)(Math.atan2(qy - py, qx - px) * 180/Math.PI);

      double dx = qx - px;
      double dy = qy - py;
      double d = Math.hypot(dx,dy);
      qx = px + (float)((d-off)*dx/d);
      qy = py + (float)((d-off)*dy/d);

      paint.setStyle(Paint.Style.FILL);

      canvas.save();
      canvas.translate(qx,qy);
      canvas.rotate(phi);
      canvas.drawPath(arrow_path,paint);
      canvas.restore();
    }

    
    
    public void drawArrowShape(Canvas canvas, Point p, Point q,float off) 
    { if (p == null || q == null) return;
      drawArrowShape(canvas,p.x,p.y,q.x,q.y,off);
    }


   void drawTile(Canvas canvas, String tile, boolean highlighted)
   { 
     if (tile==null) return;

     if (tile.equals("")) return;

     int lat = Integer.parseInt(tile.substring(1,3)); 
     if (tile.substring(0,1).equals("S")) lat = -lat;
     int lon = Integer.parseInt(tile.substring(4,7)); 
     if (tile.substring(3,4).equals("W")) lon = -lon;

     Path tile_path = new Path();

     Point p = new Point();
     map_view.toPixels(lat,lon,p);
     tile_path.moveTo(p.x,p.y);

     Point q = new Point();
     map_view.toPixels(lat,lon+1,q);
     tile_path.lineTo(q.x,q.y);

     int width = q.x - p.x;

     map_view.toPixels(lat+1,lon+1,p);
     tile_path.lineTo(p.x,p.y);

     map_view.toPixels(lat+1,lon,p);
     tile_path.lineTo(p.x,p.y);

     tile_path.close();

     paint.setStyle(Paint.Style.FILL);
     paint.setARGB(100,150,150,150);
     if (highlighted) paint.setARGB(128,255,0,0);
     canvas.drawPath(tile_path,paint);
  
     //paint.setStrokeWidth(3);
     paint.setStrokeWidth(2);
     paint.setStyle(Paint.Style.STROKE);
     paint.setColor(Color.BLUE);
     canvas.drawPath(tile_path,paint);

     map_view.toPixels(lat+0.5,lon+0.5,p);

     paint.setStyle(Paint.Style.FILL);
     paint.setTextAlign(Align.CENTER);
     paint.setTextSize((int)(width/4.5f));
     //paint.setColor(Color.YELLOW);
     paint.setColor(Color.rgb(255,255,128));
     canvas.drawText(tile,p.x,p.y,paint);
   }

    public void drawSRTM3(Canvas canvas) 
    {
      double Lat[] = new double[2];
      double Lon[] = new double[2];

      map_view.windowCoords(Lat,Lon);

      double span = Lon[1] - Lon[0];

      if (span < 0.5 || span > 50) return;

      int lon1 = (int)Math.floor(Lon[0] + 0.5) - 1;
      int lat1 = (int)Math.floor(Lat[0] + 0.5) - 1;
      int lon2 = (int)Math.floor(Lon[1] + 0.5) + 1;
      int lat2 = (int)Math.floor(Lat[1] + 0.5) + 1;

      int sz = (1 + lat2-lat1) + (1 + lon2-lon1);

      float[]  coords = new float[8*sz];

      int n = 0;
      Point p = new Point();

      for(double lat=lat1; lat <= lat2; lat++) 
      { map_view.toPixels(lat,lon1,p);
        coords[n++] = p.x;
        coords[n++] = p.y;
        map_view.toPixels(lat,lon2,p);
        coords[n++] = p.x;
        coords[n++] = p.y;
       }

      for(double lon=lon1; lon <= lon2; lon++) 
      { map_view.toPixels(lat1,lon,p);
        coords[n++] = p.x;
        coords[n++] = p.y;
        map_view.toPixels(lat2,lon,p);
        coords[n++] = p.x;
        coords[n++] = p.y;
       }

      paint.setARGB(128,32,32,32);

      if (span < 10)
       paint.setStrokeWidth(3);
      else
      if (span < 20)
        paint.setStrokeWidth(2);
      else
        paint.setStrokeWidth(1);

      canvas.drawLines(coords,0,n,paint);

      File[] files = srtm3_folder.listFiles();
      for(int i=0; i<files.length; i++)
      { String fname = files[i].getName();
        if (fname.endsWith(".hgt.zip"))
        { String tile = fname.replace(".hgt.zip","");
          drawTile(canvas,tile,false);
         }
       }

      drawTile(canvas,selected_tile,true);
    }



    public void drawGrid(Canvas canvas, double sec) 
    {
      double Lat[] = new double[2];
      double Lon[] = new double[2];
      map_view.windowCoords(Lat,Lon);

      double lon1 = Lon[0];
      double lon2 = Lon[1];
      double lat1 = Lat[0];
      double lat2 = Lat[1];

      double dlon = (lon2 - lon1);
      double dlat = (lat2 - lat1);

      lon1 -= dlon;
      lon2 += dlon;
      lat1 -= dlat;
      lat2 += dlat;


      //double d = 1200; // 3sec
      double d = 3600/sec;  // points per degree

      //float pix = 12;
      float pix = map_view.getMapWidth()/100;
      float max_lines = 4*pix;

      if (map_view.isSatellite())
        paint.setARGB(255,255,255,200);
      else
        paint.setARGB(128,64,64,64);

      paint.setStrokeWidth((int)(0.5 +pix/2.5));

      if (lat2 > lat1 && lon2 > lon1 &&
          (lat2-lat1)/d < max_lines  && (lon2-lon1)/d < 2*max_lines)
      { 
        lon1 = Math.floor(d*lon1+0.5)/d;
        lat1 = Math.floor(d*lat1+0.5)/d;

        int n = (int)(2 + d*(lat2-lat1)) * (int)(2 + d*(lon2-lon1));

        float[]  coords = new float[8*n];
        int i = 0;
        Point p = new Point();
        for(double lat=lat1; lat <= lat2; lat+=1/d) {
          for(double lon=lon1; lon <= lon2; lon+=1/d)
          { map_view.toPixels(lat,lon,p);
            coords[i++] = p.x-pix; coords[i++] = p.y;
            coords[i++] = p.x+pix; coords[i++] = p.y;
            coords[i++] = p.x;   coords[i++] = p.y-pix;
            coords[i++] = p.x;   coords[i++] = p.y+pix;
           }
        }

       canvas.drawLines(coords,0,i,paint);

       if (current_point != null)
       { // show closest srtm3 location
         double lat = current_point.getLatitude();
         double lon = current_point.getLongitude();

         lon = Math.floor(1200*lon+0.5)/1200.0;
         lat = Math.floor(1200*lat+0.5)/1200.0;

         map_view.toPixels(lat,lon,p);
         paint.setColor(Color.RED);
         //paint.setStrokeWidth(pix/2);
         //canvas.drawCircle(p.x,p.y,1.5f*pix,paint);
         canvas.drawLine(p.x-pix,p.y,p.x+pix,p.y,paint);
         canvas.drawLine(p.x,p.y-pix,p.x,p.y+pix,paint);
       }
     }

   }


    public void drawPath(Canvas canvas, Vector<Location> vec, 
                         int clr, float width, boolean arrow)
    {
      int w = (int)(0.5f + width * (dpi/160f));

      //Path  path = new Path();
      path.rewind();

      Point prev_p = null;
      Point p = null;

/*
      float pts[] = new float[2*vec.size()];
      int n = 0;
*/

      synchronized(vec)
      { Iterator<Location> itr = vec.iterator();
        while(itr.hasNext())
        { Location loc = itr.next();
  
          p = new Point();
          map_view.toPixels(loc,p);
  
          if (prev_p == null) { 
             path.moveTo(p.x,p.y);
             //pts[n++] = p.x;
             //pts[n++] = p.y;
            }
          else
          { if (p.x == prev_p.x && p.y == prev_p.y) continue;
            path.lineTo(p.x,p.y);         
            //pts[n++] = p.x;
            //pts[n++] = p.y;
           }
  
          if (itr.hasNext()) prev_p = p;
        }
      }
  
  
        paint.setColor(clr);
        paint.setStrokeWidth(w);
        paint.setStyle(Paint.Style.STROKE);
  
  
        double lon[] = new double[2];
        double lat[] = new double[2];
        map_view.windowCoords(lat,lon);
  
        canvas.drawPath(path,paint);
  
  /*
        if (lat[1]-lat[0] < 0.02)
        { paint.setStrokeWidth(2*w);
          paint.setColor(Color.GREEN);
          canvas.drawPoints(pts,0,n,paint);
         }
  */

        //if (p.equals(prev_p))  showToast("p == prev_p");
  
        if (arrow) drawArrowShape(canvas,prev_p,p,0);
  
   }


   public void drawPoints(Canvas canvas, Vector<Location> vec, int clr)
   {
      if (vec.isEmpty()) return;

      Point p = new Point();

      int w = (int)(0.5f + node_width * (dpi/160f));

    synchronized(vec)
    { Iterator<Location> itr = vec.iterator();
      while(itr.hasNext())
      { Location loc = itr.next();
        map_view.toPixels(loc,p);

        paint.setStrokeWidth(2);
        if (map_view.isSatellite())
          paint.setColor(Color.WHITE);
        else
          paint.setColor(clr);

        paint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(p.x, p.y, w, paint);
    
        paint.setColor(Color.BLACK);
        paint.setStrokeWidth(1);
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(p.x, p.y, w, paint);
      }
     }
    }


    private void draw_compass_rose(Canvas canvas)
    {
      int map_width = map_view.getMapWidth();

      int buf_width = map_view.getBufferWidth();
      int buf_height = map_view.getBufferHeight();

      float x = buf_width/2;
      float y = buf_height/2;


      float r = 0.4f * map_width;

      canvas.save();
      canvas.translate(x,y);

      if (map_view.isSatellite())
         paint.setARGB(64,255,255,64);
      else
         paint.setARGB(32,64,64,255);

      paint.setStyle(Paint.Style.FILL);
      canvas.drawCircle(0,0,r,paint);
      
      if (map_view.isSatellite())
        paint.setARGB(255,255,255,255);
      else
        paint.setARGB(128,0,0,0);

      float d = 0.75f*r;
      paint.setStrokeWidth(5);
      canvas.drawLine(-d,0,d,0,paint);
      canvas.drawLine(0,-d,0,d,paint);
      drawArrowShape(canvas,0,0,-d, 0,0);
      drawArrowShape(canvas,0,0, d, 0,0);
      drawArrowShape(canvas,0,0, 0,-d,0);
      drawArrowShape(canvas,0,0, 0, d,0);


      if (map_view.isSatellite())
        paint.setARGB(255,255,255,255);
      else
        paint.setARGB(192,0,0,0);

      paint.setStyle(Paint.Style.STROKE);
      paint.setStrokeWidth(2);
      canvas.drawCircle(0,0,r,paint);

      int ts = map_width/18;

      paint.setStyle(Paint.Style.FILL);
      paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
      paint.setTextAlign(Align.CENTER);
      paint.setTextSize(ts);

      canvas.rotate(0);
      canvas.drawText("N",0,-r+ts,paint);
      canvas.rotate(90);

      if (language.equals("Deutsch"))
        canvas.drawText("O",0,-r+ts,paint);
      else
        canvas.drawText("E",0,-r+ts,paint);

      canvas.rotate(90);
      canvas.drawText("S",0,-r+ts,paint);
      canvas.rotate(90);
      canvas.drawText("W",0,-r+ts,paint);
      canvas.restore();
    }
      
    

    @Override
    public void draw(Canvas canvas)
    { 
      //showToast("map_overlay.draw");

      invalid = false;

      if (canvas == null) return;

      if (show_srtm3_tiles) drawSRTM3(canvas);

      if (show_compass) draw_compass_rose(canvas);

      float d = 1.1f * track_width * (dpi/160f);

      arrow_path.rewind();
      arrow_path.moveTo( -1*d,    0);
      arrow_path.lineTo( -2*d,  2*d);
      arrow_path.lineTo(  2*d,    0);
      arrow_path.lineTo( -2*d, -2*d);
      arrow_path.close();

      if (srtm3_points && map_view.getZoomLevel() > 15) drawGrid(canvas,3);


      if (home_point != null)
      { 
        if (homeBitmap != null) 
        { Point p = new Point();
          map_view.toPixels(home_point,p);
          drawBitmap(canvas,p.x,p.y,homeBitmap,true);
         }
        else
        { float save = node_width;
          node_width *= 1.25f;
          drawPoint(canvas,home_point,0x807080ff,false);
          node_width = save;
         }
      }


      if (course_point != null) 
      { 

        Location current_p = current_point;
        if (current_p == null) current_p = current_track_point;

        if (current_p != null) 
        { 
          Point p = new Point();
          map_view.toPixels(current_p,p);

          Point q = new Point();
          map_view.toPixels(course_point,q);

          double pd = Math.hypot(p.x-q.x,p.y-q.y); // pix distance

          if (pd > 30) 
            drawPoint(canvas,course_point,0xff00c800,false);

          if (pd > 120) 
            drawArrow(canvas,current_p,course_point,0xff00c800);
         }

       }


      if (show_srtm3_tiles) {
        if (current_point != null) 
           drawPoint(canvas,current_point,0x80c80000,false);
        return;
      }


      boolean arrow = true;
      int clr = track_color;

      if (current_point != null) 
      { // current_point defined by setPoint (not running)
        drawAccuracyDisk(canvas,current_point);
        drawPoint(canvas,current_point,0xfff00000,false);
        arrow = false;
       }


      if (!vec_course_simple.isEmpty()) 
        drawPath(canvas,vec_course_simple,course_color,course_width,false);

      if (!vec_course.isEmpty()) 
        drawPath(canvas,vec_course,course_color,course_width,false);


      if (!vec_track_simple.isEmpty()) 
        drawPath(canvas,vec_track_simple,clr,track_width,false);


      if (!vec_track.isEmpty()) 
        drawPath(canvas,vec_track,clr,track_width,arrow);


      // start point (red)
      Location start = null;
      if (!vec_track_simple.isEmpty()) 
          start = vec_track_simple.firstElement();
      else
        if (!vec_track.isEmpty()) 
          start = vec_track.firstElement();

      drawPoint(canvas,current_point,0x80c80000,false);

      // end point (red)
      Location end = null;
      if (!vec_track.isEmpty()) 
        end = vec_track.lastElement();
      else
        if (!vec_track_simple.isEmpty()) 
          end = vec_track_simple.lastElement();

      if (arrow)
        drawAccuracyDisk(canvas,end);
      else
        drawPoint(canvas,current_point,0x80c80000,false);



      // break points
      drawPoints(canvas,vec_breaks,0xffffff80); // yellow

      if (show_waypoints && wpBitmap != null && map_view.getZoomLevel() >= 10)
      { 
        int width = map_view.getMapWidth();
        int height = map_view.getMapHeight();

        //int text_sz = canvas.getWidth()/25;
        //int text_sz = width/40;

        int text_sz = height/40;

        Iterator<Location> itr = vec_wpoints.iterator();
        Iterator<String> itr2 = vec_wpoint_names.iterator();

        while (itr.hasNext())
        { 
          Location loc = itr.next();
          String name = itr2.next();

          if (name.equals("Home")) continue;

          if (home_point != null && home_point.distanceTo(loc) < 50) continue;

          Point p = new Point();
          map_view.toPixels(loc,p);

          drawBitmap(canvas, p.x, p.y-10, wpBitmap,false);

          if (map_view.getZoomLevel() > 13)
          { paint.setStyle(Paint.Style.FILL);
            paint.setTextAlign(Align.LEFT);
            paint.setTextSize(text_sz);
            if (map_view.isSatellite())
              paint.setColor(Color.YELLOW);
            else
              paint.setColor(Color.BLUE);
            canvas.drawText(name,p.x+text_sz/2,p.y-text_sz/3,paint);
          }
         }
       }


      if (show_calibration_points) {
       drawPoints(canvas,vec_calibration_points,0x6400c800); // green
      }


      if (draw_bounding_box)
      { 
        Path bb_path = new Path();
        Point p = new Point();

        map_view.toPixels(lat_min,lon_min,p);
        bb_path.moveTo(p.x,p.y);
        map_view.toPixels(lat_min,lon_max,p);
        bb_path.lineTo(p.x,p.y);
        map_view.toPixels(lat_max,lon_max,p);
        bb_path.lineTo(p.x,p.y);
        map_view.toPixels(lat_max,lon_min,p);
        bb_path.lineTo(p.x,p.y);
        map_view.toPixels(lat_min,lon_min,p);
        bb_path.lineTo(p.x,p.y);
  
        paint.setStrokeWidth(1);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.BLUE);
        canvas.drawPath(bb_path,paint);
      }

    }

/*
    @Override 
    public boolean onTouchEvent(MotionEvent event, MapView mapView)
    {
      if (event.getAction() == 1)
      { GeoPoint p = map_view.fromPixels((int)event.getX(), (int)event.getY());
        double lat = p.getLatitudeE6()/1E6;
        double lon = p.getLongitudeE6()/1E6;
        showToast(String.format("onTouch: %.6f  %.6f",lat,lon));
        return true;
       }
       return false;
     }
*/
     
    

/*
    @Override
    public boolean onTap(GeoPoint p, MapView v) 
    { double lat = p.getLatitudeE6()/1E6;
      double lon = p.getLongitudeE6()/1E6;
      showToast(String.format("onTap: %.6f  %.6f",lat,lon));
      return false;      
    }
*/

}
