// defaults
var lat = 31.57;
var lng = 48.99;
var zoom = 6;

// sat colors
var colors = ["#FF0000", "#00FF00", "#0000FF", "#FFFF00", 
              "#FF00FF", "#00FFFF", "#FF8800", "#FF0088",
              "#00FF88", "#0088FF", "#8800FF", "#88FF00"];


var map;
var dish;
var pnt;
var center;
var map_type;
var ip_city;
var sats = [];
var p_sats = [];

var step_map = [];
var steps = 20;
var pi = Math.PI;

function create_marker(point) {
	var ic = new GIcon();
	ic.image = 'satfinder/dpIcon2.png';
	ic.iconSize = new GSize(46, 50);
	ic.iconAnchor = new GPoint(12, 35);
	ic.infoWindowAnchor = new GPoint(22, 20);
	ic.shadow = 'satfinder/dpIcon2_shadow.png';
        ic.shadowSize = new GSize(55, 50);

	var marker = new GMarker(point, ic);
	return marker;
}

function parse_params (h){
  if (h)  {
    if (h.charAt(0) == "#")    {
      h = h.substr(1);
    }
    var pars = h.split ("&");
    for (var i = 0; i < pars.length; i++)     {
      var pair = pars[i].split("=",2);
      if (pair.length==2)
      {
        if (pair[0]=="x") { lat=parseFloat(pair[1]); }
        if (pair[0]=="y") { lng=parseFloat(pair[1]); }
        if (pair[0]=="z") { zoom=parseFloat(pair[1]); }
        if (pair[0]=="m") { map_type=parseFloat(pair[1]); }
        if (pair[0]=="d") { 
          var coord = pair[1].split(",",2);
          if (coord.length==2) {
            pnt=new GLatLng(coord[1], coord[0]);
          }
        }
        if (pair[0]=="s") {
          p_sats=pair[1].split(",");
        }
      }
    }
  } else {
         if (geocoder) {
            geocoder.getLatLng(
            ip_city,
            function(point) {
               if (point) {
                  map.setCenter(point, map.getZoom());
			click_map(dish, point);
               }
            });
         }

}
}

function sort_sats (a, b)
{
  return a.lat - b.lat;
}

function draw_sats () {
    var menu = document.getElementById("menu");
    var html = "<table style='width: 100%'>";
    for (var i = 0; i < sats.length; i++) {
      o = sats[i];
      html += "<tr";

      var elev = 0;
      if (pnt)      {
        elev = gc.elevation(o.lat);
        var pol = gc.polarization(o.lat);

        elev = Math.round(elev*10)/10.0;
        pol = Math.round(pol*10)/10.0;
        html +=
         " title=\"elevation: "+elev+"; polarization="+pol+"\"";
      }
      
      html += "><td>" + "<input type=\"checkbox\" value=\"" + i +  "\" onclick=\"clk(this);\"";

      if (o.marker) { html += "checked"; }
      html += " /></td><td>";
      if (elev<0) {
        html += "<font color=\"#afafaf\">"+o.slat+"</font>";
      } else {
        html += o.slat;
      }
      html += 
         " <a href=\"" + o.url +  "\" target=\"info\">" + 
         "<font color=\"" + o.color + "\">" +     o.name + "</font>" +
         "</a></td><td style='text-align: right'><div class='box0' style='background-color: "+o.color+"'></div></td></tr>\n";
    }
	html+='</table>';
    menu.innerHTML = html;
}

function fixFloat(x){
   if(x==undefined||x==''){x=0;}
   str = x+'';
   ind = str.indexOf('.');
   if(ind==-1)return str+".0000";
   return str.substring(0,ind+5);
}

function load_sats (){
  GDownloadUrl("satfinder/sat.xml", function(data, responseCode) {
      var xml = GXml.parse(data);
      var sat = xml.documentElement.getElementsByTagName("satellite");

      for (var i = 0; i < sat.length; i++) {
        var o = new Object;
        o.lat = parseFloat(sat[i].getAttribute("lon"));
        o.name = sat[i].getAttribute("name");
        o.url = sat[i].getAttribute("url");
        o.pol = sat[i].getAttribute("pol");
// alert (name + ",. " + color);

        o.slat = lat;
        o.marker = null;
        o.marker2 = null;
        o.marker3 = null;
        if (o.lat >= 0) {
          o.slat = o.lat + "E/" + o.pol;
        } else {
          o.slat = 0 - o.lat;
          o.slat += "W/" + o.pol;
        }

        sats.push (o);
      }
      
      sats.sort (sort_sats);

      for (var i=0; i<sats.length; ++i)
      {
        sats[i].color = colors[ i % colors.length ];
        for (var j=0; j<p_sats.length; ++j)
        {
          if (sats[i].lat == p_sats[j])
          {
            calc_sat_bearing (pnt, i);
          }
        }
      }
      
      draw_sats ();
      
  });
}

function set_address_line () {
  var h = "x="+center.lng()+"&y="+center.lat()+"&z="+zoom+
    "&m="+map_type;
  if (pnt) {
    h += "&d=" + pnt.lng() + "," + pnt.lat();
  }
  if (p_sats.length > 0)
  {
    h += "&s=" + p_sats.join();
  }

  location.hash = h;
    
}

function load() {
  if (GBrowserIsCompatible()) {
    // calc sin map
    for (var s=0; s<=steps; s++) 
    { step_map[s] = 1-Math.cos(s*pi/2/steps); }
    
    parse_params (location.hash);
    
    var opts = new Object;
    opts.draggableCursor = "crosshair";
    map = new GMap2(document.getElementById("map"), opts);
    map.addControl(new GLargeMapControl());
//    map.addControl(new GMapTypeControl());
    map.addControl(new GScaleControl());
	map.enableScrollWheelZoom();

	map.addControl(new TextualZoomControl(map));
	map.addControl(new TextLink(map));
	map.addControl(new TextLink2(map));

    map.setCenter(new GLatLng(lng, lat), zoom, G_HYBRID_MAP);
    
    if (pnt) {
      gc = new GC(pnt);
      dish = create_marker(pnt);
      var coord = document.getElementById("coords");
      coord.innerHTML = fixFloat(pnt.lat()) + ", " + fixFloat(pnt.lng());
      map.addOverlay (dish);
    }

    GEvent.addListener(map, "moveend", function() {
          center = map.getCenter();
          set_address_line ();      
    });

    GEvent.addListener(map, "zoomend", function(oldl,newl) {
          zoom = newl;
          set_address_line ();      
    });

    GEvent.addListener(map, "maptypechanged", function() {
          map_type = map.getCurrentMapType().getName(true);
          set_address_line ();      
    });

    GEvent.addListener(map, "click", function (marker, point) {click_map(marker, point)});

    load_sats ();
    center = map.getCenter();
    zoom = map.getZoom ();
    map_type = map.getCurrentMapType().getName(true);
    set_address_line ();      
  }
  else
  {
    alert ("Unsupported browser version. Use recent IE/Firefox/Opera...");
  }
}
function click_map (marker, point) {
	if (! marker){
		if (dish) { map.clearOverlays (); }
		pnt = point;
		gc = new GC(pnt);
		dish = create_marker(point);
		var coord = document.getElementById("coords");
		coord.innerHTML = fixFloat(pnt.lat()) + ", " + fixFloat(pnt.lng());
		map.addOverlay (dish);
		set_address_line ();
		for (var i = 0; i < sats.length; i++) {
			if (sats[i].marker) {
				calc_sat_bearing (pnt, i);          
			}
		}
		draw_sats ();
	} else {
		var coord = document.getElementById("coords");
		coord.innerHTML = fixFloat(point.lat()) + ", " + fixFloat(point.lng());
		dish.setLatLng(point);
		pnt = point;
		map.clearOverlays();
		delete gc;
		gc = new GC(pnt);
		map.addOverlay (dish);
		gc.gc_distance(pnt);
		set_address_line ();
		for (var i = 0; i < sats.length; i++) {
			if (sats[i].marker) {
				calc_sat_bearing (point, i);          
			}
		}
		draw_sats ();
	}
}
var rad_in_deg = 2*Math.PI/360.0;
function deg2rad (x) { return x * rad_in_deg; }
function rad2deg (x) { return x / rad_in_deg; }
function mod(x,y) { return x%y; }
function sqr(x) { return x*x; }

// great circles
function GC (pnt)
{
  this.lat = deg2rad(pnt.lat());
  this.lon = deg2rad(pnt.lng());

  this.lat_cos = Math.cos(this.lat);
  this.lat_sin = Math.sin(this.lat);
  this.lat_tan = Math.tan(this.lat);

  this.lon_cos = Math.cos(this.lon);
  this.lon_sin = Math.sin(this.lon);
  this.lon_tan = Math.tan(this.lon);

  this.lat_cos_lon_cos = this.lat_cos * this.lon_cos;
  this.lat_cos_lon_sin = this.lat_cos * this.lon_sin;
}

GC.prototype.elevation = function (deg_sat_lon)
{
  var sat_lon = deg2rad(deg_sat_lon); 

  var tmp1 = this.lat_cos;
  var tmp2 = Math.cos(this.lon-sat_lon);
  var elev = Math.atan2(
          (6.612 * tmp1 * tmp2 - 1),
          (6.612*Math.sqrt(1-(sqr(tmp1*tmp2))))
      );
  return rad2deg(elev);
}


GC.prototype.polarization = function (deg_sat_lon)
{
  var sat_lon = deg2rad(deg_sat_lon); 
  
  var pol = -Math.atan( Math.sin(this.lon-sat_lon)/this.lat_tan );
  return rad2deg(pol);
}

GC.prototype.gc_distance = function (pnt) {
  var lat=deg2rad(pnt.lat()), 
      lon=deg2rad(pnt.lng()); 

  var d = 2 * Math.asin(
        Math.sqrt(
          sqr(Math.sin((this.lat-lat)/2)) +
          this.lat_cos*Math.cos(lat)*
          sqr(Math.sin((this.lon-lon)/2))
        )
      );
  return d;
}

GC.prototype.perp_point = function (deg_sat_lon, d)
{
  var sat_lon = deg2rad(deg_sat_lon);

  var tc = mod(
      Math.atan2(Math.sin(this.lon-sat_lon),
                 -this.lat_sin*Math.cos(this.lon-sat_lon)), 2*pi);
  tc += pi/2;
  if (tc > pi) tc -= pi;

  var lat = Math.asin( this.lat_sin * Math.cos(d) +
                       this.lat_cos * Math.sin(d) * Math.cos(tc) );
  var dlon = Math.atan2( Math.sin(tc) * Math.sin(d) * this.lat_cos,
                         Math.cos(d)-this.lat_sin*Math.sin(lat) );
  var lon = mod(this.lon-dlon+pi, 2*pi) - pi;


  return new GLatLng(rad2deg(lat),rad2deg(lon));
}

GC.prototype.set_distance = function (pnt)
{
  this.distance_to = this.gc_distance (pnt);
}

GC.prototype.gc = function (pnt, f)
{
  var A, B, x, y, z, lat, lon, d;
  var lat2=deg2rad(pnt.lat()), 
      lon2=deg2rad(pnt.lng());

  if (Math.abs(this.lat+lat2) < 0.001 && Math.abs(this.lon-lon2) > pi-0.001)
    return new GLatLng(0,0);

  if (Math.abs(this.lat-lat2) < 0.001 && Math.abs(this.lon-lon2) < 0.001)
    return new GLatLng(0,0);

  d = this.distance_to;
  A = Math.sin((1-f)*d)/Math.sin(d);
  B = Math.sin(f*d)/Math.sin(d);
  x = A*this.lat_cos_lon_cos + B*Math.cos(lat2)*Math.cos(lon2);
  y = A*this.lat_cos_lon_sin + B*Math.cos(lat2)*Math.sin(lon2);
  z = A*this.lat_sin + B*Math.sin(lat2);

  lat = Math.atan2(z, Math.sqrt(x*x+y*y));
  lon = Math.atan2(y, x);

  return new GLatLng(rad2deg(lat),rad2deg(lon));
}

function calc_sat_bearing (pnt, i)
{
  var f, ipnt;
  var sat_points = new Array;
 
  gc.set_distance ( new GLatLng(0,sats[i].lat) );

  for (f = 0; f < step_map.length; f++) {
    ipnt = gc.gc (new GLatLng(0,sats[i].lat), step_map[f]);
    sat_points.push (ipnt);
  }
  sat_points.push (new GLatLng(0,sats[i].lat));

  sats[i].marker = new GPolyline(sat_points, sats[i].color, 4);
  map.addOverlay(sats[i].marker);

  var pp = gc.perp_point(sats[i].lat, pi/500);

  sat_points = new Array;
  for (f = 0; f < step_map.length; f+=2) {
    ipnt = gc.gc (pp, step_map[f]);
    sat_points.push (ipnt);
  }
  sat_points.push (pp);
  sats[i].marker2 = new GPolyline(sat_points, sats[i].color, 1);
  map.addOverlay(sats[i].marker2);

  pp = gc.perp_point(sats[i].lat, -pi/500);
  sat_points = new Array;
  for (f = 0; f < step_map.length; f+=2) {
    ipnt = gc.gc (pp, step_map[f]);
    sat_points.push (ipnt);
  }

  sat_points.push (pp);
  sats[i].marker3 = new GPolyline(sat_points, sats[i].color, 1);
  map.addOverlay(sats[i].marker3);

}

function clk(o)
{
  var i = parseInt(o.value);
  var val = sats[i].lat;
  var chk = o.checked;

  if (dish)
  {
    if (chk)
    {
      calc_sat_bearing (pnt, i);
      
      var found = false;
      for (var i=0; i<p_sats.length && !found; ++i)
      {
        if (p_sats[i] == val) { found = true; }
      }

      if (! found) { p_sats.push (val); }
    }
    else
    {
      map.removeOverlay(sats[i].marker);
      sats[i].marker = null;
      map.removeOverlay(sats[i].marker2);
      sats[i].marker2 = null;
      map.removeOverlay(sats[i].marker3);
      sats[i].marker3 = null;
      for (var i=0; i<p_sats.length && !found; ++i)
      {
        if (p_sats[i] == val) { p_sats.splice (i,1); --i; }
      }
    }
    set_address_line ();      
  }
  else
  {
    o.checked = false;
  }
}