Ephemeris = function(){}

Ephemeris.prototype.JulianDay = function(date){
  d = new Date();
  d.setTime(date.getTime())
  var year=d.getUTCFullYear();
  var month=d.getUTCMonth()+1;
  var day=d.getUTCDate();
  var calender="";

  if(month <= 2){
    var year = year - 1;
    var month = month + 12;
  } 

  var julian_day = Math.floor(365.25*(year+4716))+Math.floor(30.6001*(month+1))+day-1524.5;
  
  if (calender == "julian"){ 
    var transition_offset=0;
  }else if(calender == "gregorian"){
    var tmp = Math.floor(year/100);
    var transition_offset=2-tmp+Math.floor(tmp/4);
  }else if(julian_day<2299160.5){
    var transition_offset=0;
  }else{
    var tmp = Math.floor(year/100);
    var transition_offset=2-tmp+Math.floor(tmp/4);
  }
    var jd=julian_day+transition_offset;
    this.jd = jd;
    return jd
}


Ephemeris.prototype.GMST = function(date){
//load default values
  d = new Date();
  d.setTime(date.getTime())
  var hours=d.getUTCHours();
  var minutes=d.getUTCMinutes();
  var seconds=d.getUTCSeconds();
  var time_in_sec=hours*3600+minutes*60+seconds;
  var ephemeris = new Ephemeris()
  var jd = ephemeris.JulianDay(date);
  var rad=Math.PI/180;
  var deg=180/Math.PI;
  
//gmst at 0:00
  var t = (jd-2451545.0)/36525;
  var gmst_at_zero = (24110.5484 + 8640184.812866*t+0.093104*t*t+0.0000062*t*t*t)/3600;
  if(gmst_at_zero>24){gmst_at_zero=gmst_at_zero%24;}
  this.gmst_at_zero=gmst_at_zero;

//gmst at target time

  var gmst=gmst_at_zero+(time_in_sec * 1.00273790925)/3600;
/*
  //mean obliquity of the ecliptic
  e = 23+26.0/60+21.448/3600 -46.8150/3600*t -0.00059/3600*t*t +0.001813/3600*t*t*t;
  //nutation in longitude
  omega = 125.04452-1934.136261*t+0.0020708*t*t+t*t*t/450000;
  long1 = 280.4665 + 36000.7698*t;
  long2 = 218.3165 + 481267.8813*t;
  phai = -17.20*Math.sin(omega*rad)-(-1.32*Math.sin(2*long1*rad))-0.23*Math.sin(2*long2*rad) + 0.21*Math.sin(2*omega*rad);
  gmst =gmst + ((phai/15)*(Math.cos(e*rad)))/3600
*/
  if(gmst<0){gmst=gmst%24+24;}
  if(gmst>24){gmst=gmst%24;}
  this.gmst=gmst
  return gmst
}


Ephemeris.prototype.Sun = function(date){
  //load default values
  d = new Date();
  d.setTime(date.getTime())
  var year=d.getUTCFullYear();
  var hours=d.getUTCHours();
  var minutes=d.getUTCMinutes();
  var seconds=d.getUTCSeconds();
  var time_in_day=hours/24+minutes/1440+seconds/86400;
  
  var ephemeris = new Ephemeris()
  var jd = ephemeris.JulianDay(date);
  var rad=Math.PI/180;
  var deg=180/Math.PI;

  //ephemeris days from the epch J2000.0
  var t = (jd + time_in_day -2451545.0)/36525;
  //for test jd = 2448908.5
  //var t = (2448908.5 -2451545.0)/36525;// + time_in_day;

  //geometric_mean_longitude
  var mean_longitude = 280.46646 + 36000.76938*t + 0.0003032*t*t;
   if(mean_longitude<0){mean_longitude=mean_longitude%360+360;}
   if(mean_longitude>360){mean_longitude=mean_longitude%360;}

  //mean anomaly of the Sun
  var mean_anomaly =  357.52911+ 35999.05029*t + 0.0001537*t*t;
   if(mean_anomaly<0){mean_anomaly=mean_anomaly%360+360;}
   if(mean_anomaly>360){mean_anomaly=mean_anomaly%360;}

  //eccentricity of the Earth's orbit
  var eccentricity = 0.01678634 + 0.000042037*t + 0.0000001267*t*t;
  //Sun's equation of  the center
  c = (1.914602 - 0.004817*t + 0.000014*t*t)*Math.sin(mean_anomaly*rad);
  c =c+ (0.019993 - 0.000101*t)*Math.sin(2*mean_anomaly*rad);
  c =c+ 0.000289 *Math.sin(3*mean_anomaly*rad);
  //true longitude of the Sun
  var true_longitude = mean_longitude + c;
  //for more accuracy
  //true_longitude = true_longitude - 0.01397*(year - 2000);  
  //true anomary of the Sun
  var true_anomary = mean_anomaly + c;
  //radius vector, distance between center of the Sun and the Earth
  var radius = (1.000001018*(1-eccentricity*eccentricity))/(1 + eccentricity*Math.cos(true_anomary*rad));
  this.radius=radius;
  //apparent longitude
  w = 125.04 - 1934.136*t;
  apparent_longitude = true_longitude - 0.00569 - 0.00478 * Math.sin(w*rad);
  //obliquity of the ecliptio
  obliquity = 23+26.0/60+21.448/3600 -46.8150/3600*t -0.00059/3600*t*t +0.001813/3600*t*t*t; 
  //correction for apperent position of the sun 
  obliquity = obliquity+0.00256*Math.cos(w*rad);
  //right asantion of the Sun
  var ra = Math.atan2(Math.cos(obliquity*rad)*Math.sin(apparent_longitude*rad), Math.cos(apparent_longitude*rad))
  ra = ra *deg;
 if(ra<0){ra=ra+360;}
 if(ra>360){ra=ra%360;}
  this.ra=ra/15;
 //declination of the Sun
 var dec = Math.asin(Math.sin(obliquity*rad)*Math.sin(apparent_longitude*rad));
 this.dec=dec * deg;
 return this;
}

Terminator=function(date){
 this.date = date;
}

Terminator.prototype.generate = function(){
  date = this.date;
  var rad=Math.PI/180;
  var ephem = new Ephemeris();
  var sun = ephem.Sun(date);
  var sun_ra = sun.ra;
  var sun_dec = sun.dec;
  var gmst = ephem.GMST(date);
  //var longitude = longitude*-1;
  var sun_long = -(gmst*15 - sun_ra*15);
  if (sun_long>360){sun_long=sun_long%360};
  if (sun_long<0){sun_long=sun_long%360+360};
  var sun_lat = sun_dec;
  if(sun_lat>5){
    var polar_night_flag = "south";
  }else if(sun_lat<-5){
    var polar_night_flag = "north";    
  }else{
    var polar_night_flag = "none";
  }
  //document.getElementById('num').innerHTML = sun_long +  " | " + sun_lat +"<br>";

  var latitude_array1 = [];
  var latitude_array2 = [];
  var latitude_array3 = [];
  var latitude_array4 = [];
  var longitude_array1 = [];
  var longitude_array2 = [];
  var longitude_array3 = [];
  var longitude_array4 = [];
  var step = 1;
  for (i=90; i>= 0; i-=step){
    var delta_array = new Array();
    var delta_lat = Math.asin(Math.cos(sun_lat*rad)*Math.sin(i*rad))/rad;
    if(Math.abs(delta_lat)<85){
      var x = -Math.cos(sun_long*rad)*Math.sin(sun_lat*rad)*Math.sin(i*rad)-Math.sin(sun_long*rad)*Math.cos(i*rad);
      var y = -Math.sin(sun_long*rad)*Math.sin(sun_lat*rad)*Math.sin(i*rad)+Math.cos(sun_long*rad)*Math.cos(i*rad);
      var delta_long = Math.atan2(y,x)/rad;
      if(delta_long>360){delta_long=delta_long%360}
      if(delta_long<0){delta_long=delta_long%360+360}
      latitude_array1.push(delta_lat);
      longitude_array1.push(delta_long);
    }
  }
  for (i=360; i>= 270; i-=step){
    var delta_array = new Array();
    var delta_lat = Math.asin(Math.cos(sun_lat*rad)*Math.sin(i*rad))/rad;
    if(Math.abs(delta_lat)<85){
      var x = -Math.cos(sun_long*rad)*Math.sin(sun_lat*rad)*Math.sin(i*rad)-Math.sin(sun_long*rad)*Math.cos(i*rad);
      var y = -Math.sin(sun_long*rad)*Math.sin(sun_lat*rad)*Math.sin(i*rad)+Math.cos(sun_long*rad)*Math.cos(i*rad);
      var delta_long = Math.atan2(y,x)/rad
      if(delta_long>360){delta_long=delta_long%360}
      if(delta_long<0){delta_long=delta_long%360+360}
      latitude_array2.push(delta_lat);
      longitude_array2.push(delta_long);
    }
  }
  for (i=90; i<= 180;i+=step){
    var delta_array = new Array();
    var delta_lat = Math.asin(Math.cos(sun_lat*rad)*Math.sin(i*rad))/rad;
    if(Math.abs(delta_lat)<85){
      var x = -Math.cos(sun_long*rad)*Math.sin(sun_lat*rad)*Math.sin(i*rad)-Math.sin(sun_long*rad)*Math.cos(i*rad);
      var y = -Math.sin(sun_long*rad)*Math.sin(sun_lat*rad)*Math.sin(i*rad)+Math.cos(sun_long*rad)*Math.cos(i*rad);
      var delta_long = Math.atan2(y,x)/rad;
      if(delta_long>360){delta_long=delta_long%360}
      if(delta_long<0){delta_long=delta_long%360+360}
      latitude_array3.push(delta_lat);
      longitude_array3.push(delta_long);
    }
 }
  for (i=180; i<=270; i+=step){
    var delta_array = new Array();
    var delta_lat = Math.asin(Math.cos(sun_lat*rad)*Math.sin(i*rad))/rad;
     if(Math.abs(delta_lat)<85){
     var x = -Math.cos(sun_long*rad)*Math.sin(sun_lat*rad)*Math.sin(i*rad)-Math.sin(sun_long*rad)*Math.cos(i*rad);
      var y = -Math.sin(sun_long*rad)*Math.sin(sun_lat*rad)*Math.sin(i*rad)+Math.cos(sun_long*rad)*Math.cos(i*rad);
      var delta_long = Math.atan2(y,x)/rad;
      if(delta_long>360){delta_long=delta_long%360}
      if(delta_long<0){delta_long=delta_long%360+360}
      latitude_array4.push(delta_lat);
      longitude_array4.push(delta_long);
    }
  }

  this.sun_long = sun_long;
  this.sun_lat = sun_lat;  
  this.polar_night_flag = polar_night_flag;  
  if(sun_lat < 0){
    latitude_array4.reverse();
    latitude_array3.reverse();
    longitude_array4.reverse();
    longitude_array3.reverse();
    var latitude_array_west = latitude_array4.concat(latitude_array3);
    var longitude_array_west = longitude_array4.concat(longitude_array3);
    var latitude_array_east = latitude_array1.concat(latitude_array2);
    var longitude_array_east = longitude_array1.concat(longitude_array2);
  }else if(sun_lat > 0){
    var latitude_array_west = latitude_array3.concat(latitude_array4);
    var longitude_array_west = longitude_array3.concat(longitude_array4);
    latitude_array1.reverse();
    latitude_array2.reverse();
    longitude_array1.reverse();
    longitude_array2.reverse();
    var latitude_array_east = latitude_array2.concat(latitude_array1);
    var longitude_array_east = longitude_array2.concat(longitude_array1);
  }
  var night_latitude_array=latitude_array_east.concat(latitude_array_west);
  var night_longitude_array=longitude_array_east.concat(longitude_array_west);
  this.night_latitude_array=night_latitude_array;
  this.night_longitude_array=night_longitude_array;
  return this;
}


Terminator.prototype.show = function(map,boundary,night_shade){
  var terminator =this.generate();
//Search Split Point
  var night_longitude_array = terminator.night_longitude_array;
  var night_latitude_array = terminator.night_latitude_array;
  var polar_night_flag = terminator.polar_night_flag;  
  
  var t0=0, t1=0, t2=0, t3=0;t4=0; t5=0;
  var night_longitude_array_length=night_longitude_array.length;
  for (i = 0; i < night_longitude_array_length; i++) {  
    if(night_longitude_array[0]<night_longitude_array[i]){t0++}
    if(night_longitude_array[i]>0 &&night_longitude_array[i]<90){t1++}
    if(night_longitude_array[i]>90 &&night_longitude_array[i]<180){t2++}
    if(night_longitude_array[i]>180 &&night_longitude_array[i]<270){t3++}
    if(night_longitude_array[i]>270){t4++}  
  }

  if (night_longitude_array[0]>0 && night_longitude_array[0]<90){
    var night_id1 = t0-(t2+t3+t4)+1;
    var night_id2 = night_id1+t2;
    var night_id3 = night_id2+t3;
    var night_id4 = night_id3+t4;
    start_point="0to90";
  }else if(night_longitude_array[0]>90 && night_longitude_array[0]<180){
    if (night_longitude_array[night_longitude_array_length-1] >90 && night_longitude_array[night_longitude_array_length-1] <180){
    var night_id1 = t0-(t3+t4)+1;
}else{
    var night_id1 = t2;
    }
    var night_id2 = night_id1+t3;
    var night_id3 = night_id2+t4;
    var night_id4 = night_id3+t1;
    start_point="90to180";
  }else if(night_longitude_array[0]>180 && night_longitude_array[0]<270){
    if (night_longitude_array[night_longitude_array_length-1] >180 && night_longitude_array[night_longitude_array_length-1]<270){
      var night_id1 = t0-(t4)+1;
    }else{
    var night_id1 = t3;
    }
    var night_id2 = night_id1+t4;
    var night_id3 = night_id2+t1;
    var night_id4 = night_id3+t2;
    start_point="180to270";
  }else{
    var night_id1 = t0+1;
    var night_id2 = night_id1+t1;
    var night_id3 = night_id2+t2;
    var night_id4 = night_id3+t3;
    start_point="270to360";
  }
  this.t0 = t0;
  this.t1 = t1;
  this.t2 = t2;
  this.t3 = t3;
  this.t4 = t4;
  
//Split Night Longitude/Latitude Arrays
  var night_longitude_array1 = night_longitude_array.slice(0 , night_id1);
  var night_latitude_array1 = night_latitude_array.slice(0 , night_id1);

  var night_longitude_array2 = night_longitude_array.slice(night_id1,night_id2);
  var night_latitude_array2 = night_latitude_array.slice(night_id1,night_id2);
  
  var night_longitude_array3 = night_longitude_array.slice(night_id2,night_id3);
  var night_latitude_array3 = night_latitude_array.slice(night_id2,night_id3);

  var night_longitude_array4 = night_longitude_array.slice(night_id3,night_id4);
  var night_latitude_array4 = night_latitude_array.slice(night_id3,night_id4);

  var night_longitude_array5 = night_longitude_array.slice(night_id4);
  var night_latitude_array5 = night_latitude_array.slice(night_id4);



//Function for split on the Greenwich meridian
  var split_meridian = function(point1,point2){
    var  split_lat = night_latitude_array[point1] + (360-night_longitude_array[point1])*((night_latitude_array[point2] - night_latitude_array[point1])/(night_longitude_array[point2]+360 - night_longitude_array[point1]));
    return split_lat;
  }

//Function for split on the International Date Line
  var split_other = function(point1,point2,seed){
    var  split_lat = night_latitude_array[point1] + (seed- night_longitude_array[point1])*((night_latitude_array[point2] - night_latitude_array[point1])/((night_longitude_array[point2] - night_longitude_array[point1])));
    return split_lat;
  }


  if (start_point == "0to90"){
   night_longitude_array1.push(90);
   split_latitude1 = split_other(night_id1-1,night_id1,90)
  }else if(start_point == "90to180"){
    night_longitude_array1.push(180);
   split_latitude1 = split_other(night_id1-1,night_id1,180)
  }else if(start_point == "180to270"){
    night_longitude_array1.push(270);
   split_latitude1 = split_other(night_id1-1,night_id1,270)
  }else if(start_point == "270to360"){
    night_longitude_array1.push(0);
    split_latitude1 = split_meridian(night_id1-1,night_id1);
  }
    night_latitude_array1.push(split_latitude1);

    night_latitude_array2.unshift(split_latitude1);
    if (start_point == "0to90"){
      night_longitude_array2.unshift(90);
    }else if(start_point == "90to180"){
      night_longitude_array2.unshift(-180);
    }else if(start_point == "180to270"){
      night_longitude_array2.unshift(270);
    }else if(start_point == "270to360"){
      night_longitude_array2.unshift(0);
    }

  if (night_latitude_array3.length>0){
    if (start_point == "0to90"){
      night_longitude_array2.push(180);
      split_latitude2 = split_other(night_id2-1,night_id2,180)
      night_longitude_array3.unshift(-180);
    }else if(start_point == "90to180"){
      night_longitude_array2.push(270);
      split_latitude2 = split_other(night_id2-1,night_id2,270)
      night_longitude_array3.unshift(270);
    }else if(start_point == "180to270"){
      night_longitude_array2.push(360);
      split_latitude2 = split_meridian(night_id2-1,night_id2);
      night_longitude_array3.unshift(0);
    }else if(start_point == "270to360"){
      night_longitude_array2.push(90);
      split_latitude2 = split_other(night_id2-1,night_id2,90);
      night_longitude_array3.unshift(90);
    }
    night_latitude_array2.push(split_latitude2);
    night_latitude_array3.unshift(split_latitude2);
  }

  if (night_latitude_array4.length>0){
    if (start_point == "0to90"){
      night_longitude_array3.push(270);
      split_latitude3 = split_other(night_id3-1,night_id3,270)
      night_longitude_array4.unshift(270);
    }else if(start_point == "90to180"){
      night_longitude_array3.push(360);
      split_latitude3 = split_meridian(night_id3-1,night_id3)
      night_longitude_array4.unshift(0);
    }else if(start_point == "180to270"){
      night_longitude_array3.push(90);
      split_latitude3 = split_other(night_id3-1,night_id3,90);
      night_longitude_array4.unshift(90);
    }else if(start_point == "270to360"){
      night_longitude_array3.push(180);
      split_latitude3 = split_other(night_id3-1,night_id3,180);
      night_longitude_array4.unshift(-180);
    }
    night_latitude_array3.push(split_latitude3);
    night_latitude_array4.unshift(split_latitude3);
  }

  if (night_latitude_array5.length>1){
    if (start_point == "0to90"){
    night_longitude_array4.push(360);
    split_latitude4 = split_meridian(night_id4,night_id4+1)
    }else if(start_point == "90to180"){
    night_longitude_array4.push(90);
    split_latitude4 = split_other(night_id4,night_id4+1,90)
    }else if(start_point == "180to270"){
    night_longitude_array4.push(180);
    split_latitude4 = split_other(night_id4,night_id4+1,180)
    }else if(start_point == "270to360"){
    night_longitude_array4.push(270);
    split_latitude4 = split_other(night_id4,night_id4+1,270);
    }
    night_latitude_array4.push(split_latitude4);

    night_latitude_array5.unshift(split_latitude4);
    if (start_point == "0to90"){
      night_longitude_array5.unshift(0);
    }else if(start_point == "90to180"){
      night_longitude_array5.unshift(90);
    }else if(start_point == "180to270"){
      night_longitude_array5.unshift(-180);
    }else if(start_point == "270to360"){
      night_longitude_array5.unshift(270);
    }
  }


//Generate Porygon Array
  night_polyline_array1= [];
  night_polyline_array2= [];
  night_polyline_array3= [];
  night_polyline_array4= [];
  night_polyline_array5= [];
  night_polygon_array1 = [];
  night_polygon_array2 = [];
  night_polygon_array3 = [];
  night_polygon_array4 = [];
  night_polygon_array5 = [];
  
  if(polar_night_flag=="north"){
    var lat_limit = 85;
  }else if(polar_night_flag=="south"){
    var lat_limit = -85;
  }
  
  //Porygon1 
  var night_latitude_array1_length = night_latitude_array1.length;
  var night_longitude_array1_length = night_longitude_array1.length;
  
  if (night_latitude_array1_length>0){
  if(polar_night_flag!="none"){night_polygon_array1.push(new GLatLng(lat_limit,night_longitude_array1[0]));}
  night_polygon_array1.push(new GLatLng(night_latitude_array1[0],night_longitude_array1[0]));
  for (i = 0; i < night_latitude_array1_length; i++) {
    night_polygon_array1.push(new GLatLng(night_latitude_array1[i],night_longitude_array1[i]));    
    night_polyline_array1.push(new GLatLng(night_latitude_array1[i],night_longitude_array1[i]));    
  }
  night_polygon_array1.push(new GLatLng(night_latitude_array1[0],night_longitude_array1[night_longitude_array1.length-1]));
  if(polar_night_flag!="none"){night_polygon_array1.push(new GLatLng(lat_limit,night_longitude_array1[night_longitude_array1.length-1]));}
  night_polygon_array1.push(night_polygon_array1[0]);
  }
  if((night_latitude_array1[night_latitude_array1_length-1]==night_latitude_array1[night_latitude_array1_length-2])&&(night_longitude_array1[night_longitude_array1_length-1]!=night_longitude_array1[night_longitude_array1_length-2])){
      night_polyline_array1.pop();  
  }

  //Porygon2
  var night_latitude_array2_length = night_latitude_array2.length;
  var night_longitude_array2_length = night_longitude_array2.length;
  if (night_latitude_array2_length>0){
  if(polar_night_flag!="none"){night_polygon_array2.push(new GLatLng(lat_limit,night_longitude_array2[0]));}
    night_polygon_array2.push(new GLatLng(night_latitude_array1[0],night_longitude_array2[0]));
    for (i = 0; i < night_latitude_array2_length; i++) {
      night_polygon_array2.push(new GLatLng(night_latitude_array2[i],night_longitude_array2[i]));    
      night_polyline_array2.push(new GLatLng(night_latitude_array2[i],night_longitude_array2[i]));    
    }
    night_polygon_array2.push(new GLatLng(night_latitude_array1[0],night_longitude_array2[night_longitude_array2_length-1]));
  if(polar_night_flag!="none"){night_polygon_array2.push(new GLatLng(lat_limit,night_longitude_array2[night_longitude_array2.length-1]));}
    night_polygon_array2.push(night_polygon_array2[0]);
  }
  if((night_latitude_array2[night_latitude_array2_length-1]==night_latitude_array2[night_latitude_array2_length-2])&&(night_longitude_array2[night_longitude_array2_length-1]!=night_longitude_array2[night_longitude_array2_length-2])){
      night_polyline_array2.pop();  
  }
  if((night_latitude_array2[0]==night_latitude_array2[1])&&(night_longitude_array2[0]!=night_longitude_array2[1])){
      night_polyline_array2.shift();  
  }

  //Porygon3
  var night_latitude_array3_length = night_latitude_array3.length;
  var night_longitude_array3_length = night_longitude_array3.length;
  if (night_latitude_array3_length>0){
  if(polar_night_flag!="none"){night_polygon_array3.push(new GLatLng(lat_limit,night_longitude_array3[0]));}
    night_polygon_array3.push(new GLatLng(night_latitude_array1[0],night_longitude_array3[0]));
    for (i = 0; i < night_latitude_array3_length; i++) {
      night_polygon_array3.push(new GLatLng(night_latitude_array3[i],night_longitude_array3[i]));    
      night_polyline_array3.push(new GLatLng(night_latitude_array3[i],night_longitude_array3[i]));    
    }
    night_polygon_array3.push(new GLatLng(night_latitude_array1[0],night_longitude_array3[night_longitude_array3_length-1]));
  if(polar_night_flag!="none"){night_polygon_array3.push(new GLatLng(lat_limit,night_longitude_array3[night_longitude_array3.length-1]));}
    night_polygon_array3.push(night_polygon_array3[0]);
  }
  if((night_latitude_array3[night_latitude_array3_length-1]==night_latitude_array3[night_latitude_array3_length-2])&&(night_longitude_array3[night_longitude_array3_length-1]!=night_longitude_array3[night_longitude_array3_length-2])){
      night_polyline_array3.pop();  
  }
  if((night_latitude_array3[0]==night_latitude_array3[1])&&(night_longitude_array3[0]!=night_longitude_array3[1])){
      night_polyline_array3.shift();  
  }

  //Porygon4
  var night_latitude_array4_length = night_latitude_array4.length;
  var night_longitude_array4_length = night_longitude_array4.length;
  if (night_latitude_array4_length>0){
  if(polar_night_flag != "none"){night_polygon_array4.push(new GLatLng(lat_limit,night_longitude_array4[0]));}
    night_polygon_array4.push(new GLatLng(night_latitude_array1[0],night_longitude_array4[0]));
    for (i = 0; i < night_latitude_array4_length; i++) {
      night_polygon_array4.push(new GLatLng(night_latitude_array4[i],night_longitude_array4[i]));    
      night_polyline_array4.push(new GLatLng(night_latitude_array4[i],night_longitude_array4[i]));    
    }
    night_polygon_array4.push(new GLatLng(night_latitude_array1[0],night_longitude_array4[night_longitude_array4.length-1]));
  if(polar_night_flag!="none"){night_polygon_array4.push(new GLatLng(lat_limit,night_longitude_array4[night_longitude_array4.length-1]));}
    night_polygon_array4.push(night_polygon_array4[0]);
 }
  if((night_latitude_array4[night_latitude_array4_length-1]==night_latitude_array4[night_latitude_array4_length-2])&&(night_longitude_array4[night_longitude_array4_length-1]!=night_longitude_array4[night_longitude_array4_length-2])){
      night_polyline_array4.pop();  
  }
  if((night_latitude_array4[0]==night_latitude_array4[1])&&(night_longitude_array4[0]!=night_longitude_array4[1])){
      night_polyline_array4.shift();  
  }

  //Porygon5
  var night_latitude_array5_length = night_latitude_array5.length;
  var night_longitude_array5_length = night_longitude_array5.length;
  if (night_latitude_array5_length>1){
  if(polar_night_flag!="none"){night_polygon_array5.push(new GLatLng(lat_limit,night_longitude_array5[0]));}
    night_polygon_array5.push(new GLatLng(night_latitude_array1[0],night_longitude_array5[0]));
    for (i = 0; i < night_latitude_array5_length; i++) {
      night_polygon_array5.push(new GLatLng(night_latitude_array5[i],night_longitude_array5[i]));    
      night_polyline_array5.push(new GLatLng(night_latitude_array5[i],night_longitude_array5[i]));    
    }
  if(polar_night_flag!="none"){night_polygon_array5.push(new GLatLng(lat_limit,night_longitude_array5[night_longitude_array5.length-1]));}
    night_polygon_array5.push(night_polygon_array5[0]);
  }


if (night_shade){
  if (night_polygon_array1.length>0){
    night_polygon1 = new GPolygon(night_polygon_array1, "#000000",0.5, 0, "#000000", 0.5);
    map.addOverlay(night_polygon1);
  }
  
  if (night_polygon_array2.length>0){
    var night_polygon2 = new GPolygon(night_polygon_array2, "#000000",0.5, 0, "#000000", 0.5);
   map.addOverlay(night_polygon2);
  }
  
  if (night_polygon_array3.length>0){
    night_polygon3 = new GPolygon(night_polygon_array3, "#000000",0.5, 0, "#000000", 0.5);
    map.addOverlay(night_polygon3);
  }
  if (night_polygon_array4.length>0){
    night_polygon4 = new GPolygon(night_polygon_array4, "#000000",0.5, 0, "#000000", 0.5);
    map.addOverlay(night_polygon4);
  }
  if (night_polygon_array5.length>0){
    night_polygon5 = new GPolygon(night_polygon_array5, "#000000",0.5, 0, "#000000", 0.5);
    map.addOverlay(night_polygon5);
  }
}

if (boundary){
  var line_color = "#000000";
  var line_width = 2;
  var line_opacity = 0.5;
    night_polyline1 = new GPolyline(night_polyline_array1, line_color, line_width, line_opacity);
    map.addOverlay(night_polyline1);

  if (night_polyline_array2.length>0){
    var night_polyline2 = new GPolyline(night_polyline_array2, line_color, line_width, line_opacity);
    map.addOverlay(night_polyline2);
  }
  if (night_polyline_array3.length>0){
    night_polyline3 = new GPolyline(night_polyline_array3, line_color, line_width, line_opacity);
    map.addOverlay(night_polyline3);
  }
  if (night_polyline_array4.length>0){
    night_polyline4 = new GPolyline(night_polyline_array4, line_color, line_width, line_opacity);
    map.addOverlay(night_polyline4);
  }
  if (night_polyline_array5.length>0){
    night_polyline5 = new GPolyline(night_polyline_array5, line_color, line_width, line_opacity);
    map.addOverlay(night_polyline5);
  }

  }
}


TLE = function(){}

TLE.prototype.decoder = function(line1,line2){
  var orbital_elements={
    line_number_1 :   Number(line1.slice(0,0)),
    catalog_no_1 :  Number(line1.slice(2,6)),
    security_classification :  Number(line1.slice(7,7)),
    international_identification : Number(line1.slice(9,17)),
    epoch_year : Number(line1.slice(18,20)),
    epoch : Number(line1.substring(20,32)),
    first_derivative_mean_motion : Number(line1.substring(33,43)),
    second_derivative_mean_motion : Number(line1.substring(44,52)),
    bstar_mantissa: Number(line1.substring(53,59)),
    bstar_exponent : Number(line1.substring(59,61)),
    ephemeris_type :  Number(line1.substring(62,63)),
    element_number :  Number(line1.substring(64,68)),
    check_sum_1 :   Number(line1.substring(69,69)),
    line_number_2 :   Number(line1.slice(0,0)),
    catalog_no_2 :  Number(line2.slice(2,7)),
    inclination : Number(line2.substring(8,16)),
    right_ascension : Number(line2.substring(17,25)),
    eccentricity : Number(line2.substring(26,33)),
    argument_of_perigee : Number(line2.substring(34,42)),
    mean_anomaly : Number(line2.substring(43,51)),
    mean_motion : Number(line2.substring(52,63)),
    rev_number_at_epoch : Number(line2.substring(64,68)),
    check_sum_2 :   Number(line1.substring(68,69))
   }
  return orbital_elements;
}

TLE.prototype.elapsedTime = function(epoch_year,epoch,date){
  d = new Date();
  d.setTime(date.getTime())
  var year=d.getUTCFullYear();
  var month=d.getUTCMonth()+1;
  var day=d.getUTCDate();
  var hours=d.getUTCHours();
  var minutes=d.getUTCMinutes();
  var seconds=d.getUTCSeconds();
  var year2=epoch_year-1;
  var now_sec=Date.UTC(year, month-1, day, hours, minutes, seconds);
  var epoch_sec=Date.UTC(year2, 11, 31, 0, 0, 0)+(epoch*24*60*60*1000);
  var elapsed_time=(now_sec-epoch_sec)/(60*1000);
  return(elapsed_time);
}

SGP4=function(){}

SGP4.prototype.setConstant = function(orbital_elements){
  var torad = Math.PI/180;
  var e6a = 1.0e-6;
  var tothrd = 0.66666667;
  var xj2 = 1.082616e-3;
  var xj4 = -1.65597e-6;
  var xj3 = -0.253881e-5;
  var xke = 0.743669161e-1;
  var xkmper = 6378.135;
  var min_par_day = 1440.0;
  var ae = 1.0;
  var qo = ae +120.0/xkmper;
  var ck2 =5.413080e-4;
  var ck4 = 0.62098875e-6;
  var qoms2t = 1.88027916e-9;
  var s = 1.0+78.0/xkmper;
  var de2ra = 0.174532925e-1;
  var pi = 3.14159265;
  var pio2 = 1.57079633;
  var twopi = 6.2831853;
  var x3pio2 = 4.71238898;

  var epy = Number(orbital_elements["epoch_year"]);
  //epoch_year should be smaller than 2057.
  if(epy<57){var epoch_year=epy+2000}else{var epoch_year=epy+1900};
  var epoch = orbital_elements["epoch"];
  var bstar_mantissa = orbital_elements["bstar_mantissa"]*1e-5;
  var bstar_exponent = Number("1e" + orbital_elements["bstar_exponent"]);
  var xincl = orbital_elements["inclination"]*torad;
  var xnodeo = orbital_elements["right_ascension"]*torad;
  var eo = orbital_elements["eccentricity"]*1e-7;
  var omegao  = orbital_elements["argument_of_perigee"]*torad;
  var xmo = orbital_elements["mean_anomaly"]*torad;
  var xno  = orbital_elements["mean_motion"]*2.0*Math.PI/1440.0;
  var bstar = bstar_mantissa*bstar_exponent

  var a1 = Math.pow(xke/xno,(2.0/3.0));
  var cosio=Math.cos(xincl);
  var theta2=cosio*cosio;
  var x3thm1=3*theta2-1.0;
  var eosq=eo*eo;
  var betao2=1-eosq;
  var betao=Math.sqrt(betao2);
  var del1=1.5*ck2*x3thm1/(a1*a1*betao*betao2);
  var ao=a1*(1-del1*((1.0/3.0)+del1*(1.0+(134.0/81.0)*del1)));
  var delo=1.5*ck2*x3thm1/(ao*ao*betao*betao2);
  var xnodp=xno/(1.0+delo); //original_mean_motion
  var aodp=ao/(1.0-delo); //semi_major_axis

  var isimp=0;
  if ((aodp*(1.0-eo)/ae) < (220.0/xkmper+ae)){
    isimp=1;
  }

  var s4=s;
  var qoms24=qoms2t;
  var perige=(aodp*(1.0-eo)-ae)*xkmper;
  if (perige < 156.0){
    s4 = perige-78.0;
    if (perige <= 98.0){
      s4 = 20.0;
    }else{
      var qoms24=Math.pow(((120.0-s4)*ae/xkmper),4);
      s4 = s4/xkmper+ae;
	}
  }
  var pinvsq=1.0/(aodp*aodp*betao2*betao2);
  var tsi=1.0/(aodp-s4);
  var eta=aodp*eo*tsi;
  var etasq=eta*eta;
  var eeta=eo*eta;
  var psisq=Math.abs(1.0-etasq);
  var coef=qoms24*Math.pow(tsi,4);
  var coef1=coef/Math.pow(psisq,3.5);
  
  var c2=coef1*xnodp*(aodp*(1.0+1.5*etasq+eeta*(4.0+etasq))+0.75*ck2*tsi/psisq*x3thm1*(8.0+3.*etasq*(8.0+etasq)));
  var c1=bstar*c2;
  var sinio=Math.sin(xincl);
  var a3ovk2=-xj3/ck2*Math.pow(ae,3);
  var c3=coef*tsi*a3ovk2*xnodp*ae*sinio/eo;
  var x1mth2=1.0-theta2;
  var c4=2.0*xnodp*coef1*aodp*betao2*(eta*(2.0+0.5*etasq)+eo*(0.5+2.0*etasq)-2.0*ck2*tsi/(aodp*psisq)*(-3.0*x3thm1*(1.0-2.0*eeta+etasq*(1.5-0.5*eeta))+0.75*x1mth2*(2.0*etasq-eeta*(1.0+etasq))*Math.cos((2.0*omegao))));
  var c5=2.0*coef1*aodp*betao2*(1.0+2.75*(etasq+eeta)+eeta*etasq);

  var theta4=theta2*theta2;
  var temp1=3.0*ck2*pinvsq*xnodp;
  var temp2=temp1*ck2*pinvsq;
  var temp3=1.25*ck4*pinvsq*pinvsq*xnodp;
  var xmdot=xnodp+0.5*temp1*betao*x3thm1+0.0625*temp2*betao*(13.0-78.0*theta2+137.0*theta4);

  var x1m5th=1.0-5.0*theta2;
  var omgdot=-0.5*temp1*x1m5th+0.0625*temp2*(7.0-114.0*theta2+395.0*theta4)+temp3*(3.0-36.0*theta2+49.0*theta4);
  var xhdot1=-temp1*cosio;
  var xnodot=xhdot1+(0.5*temp2*(4.0-19.0*theta2)+2.0*temp3*(3.0-7.0*theta2))*cosio;
  var omgcof=bstar*c3*Math.cos(omegao);
  var xmcof=-tothrd*coef*bstar*ae/eeta;
  var xnodcf=3.5*betao2*xhdot1*c1;
  var t2cof=1.5*c1;
  var xlcof=0.125*a3ovk2*sinio*(3.0+5.0*cosio)/(1.0+cosio);
  var aycof=0.25*a3ovk2*sinio;
  var delmo=Math.pow((1.0+eta*Math.cos(xmo)),3);
  var sinmo=Math.sin(xmo);
  var x7thm1=7.*theta2-1.0;

  if (isimp != 1){
    var c1sq=c1*c1;
    var d2=4.*aodp*tsi*c1sq;
    var temp=d2*tsi*c1/3.0;
    var d3=(17.0*aodp+s4)*temp;
    var d4=0.5*temp*aodp*tsi*(221.0*aodp+31.*s4)*c1;
    var t3cof=d2+2.0*c1sq;
    var t4cof=0.25*(3.0*d3+c1*(12.0*d2+10.0*c1sq));
    var t5cof=0.2*(3.0*d4+12.0*c1*d3+6.0*d2*d2+15.*c1sq*(2.0*d2+c1sq));
  }  

//set accesser
  this.epoch_year=epoch_year;
  this.epoch=epoch;
  this.xmo = xmo;
  this.xmdot = xmdot;
  this.omegao = omegao;
  this.omgdot = omgdot;
  this.xnodeo = xnodeo;
  this.xnodot = xnodot;
  this.xnodcf = xnodcf
  this.bstar = bstar;
  this.t2cof = t2cof;
  this.omgcof = omgcof;
  this.isimp = isimp;
  this.xmcof = xmcof;
  this.eta = eta;
  this.delmo = delmo;
  this.c1 = c1;
  this.c4 = c4;
  this.c5 = c5;
  this.d2 = d2;
  this.d3 = d3;
  this.d4 = d4;
  this.sinmo = sinmo;
  this.t3cof = t3cof;
  this.t4cof = t4cof;
  this.t5cof = t5cof;
  this.aodp = aodp;
  this.eo = eo;
  this.xnodp = xnodp;
  this.xke = xke;
  this.xlcof = xlcof;
  this.aycof = aycof;
  this.x3thm1 = x3thm1;
  this.x1mth2 = x1mth2;
  this.xincl = xincl;
  this.cosio = cosio;
  this.sinio = sinio;
  this.e6a = e6a;
  this.ck2 = ck2;
  this.x7thm1 = x7thm1;
  this.xkmper = xkmper;
}

SGP4.prototype.calcPosition = function(date){
  var d = new Date();
  d.setTime(date.getTime());
  var torad = Math.PI/180;

//variable from SGP4.setConstant
  var xmo=this.xmo;
  var xmdot=this.xmdot;
  var omegao=this.omegao;
  var omgdot=this.omgdot;
  var xnodeo=this.xnodeo;
  var xnodot=this.xnodot;
  var xnodcf = this.xnodcf
  var bstar=this.bstar;
  var t2cof=this.t2cof;
  var omgcof=this.omgcof;
  var isimp=this.isimp;
  var xmcof=this.xmcof;
  var eta=this.eta;
  var delmo=this.delmo;
  var c1=this.c1;
  var c4=this.c4;
  var c5=this.c5;
  var d2=this.d2;
  var d3=this.d3;
  var d4=this.d4;
  var sinmo=this.sinmo;
  var t3cof=this.t3cof;
  var t4cof=this.t4cof;
  var t5cof=this.t5cof;
  var aodp=this.aodp;
  var eo=this.eo;
  var xnodp=this.xnodp;
  var xke=this.xke;
  var xlcof=this.xlcof;
  var aycof=this.aycof;
  var x3thm1=this.x3thm1;
  var x1mth2=this.x1mth2;
  var xincl=this.xincl;
  var cosio=this.cosio;
  var sinio=this.sinio;
  var e6a=this.e6a;
  var ck2=this.ck2;
  var x7thm1=this.x7thm1;
  var xkmper = this.xkmper;
  var epoch_year=this.epoch_year;
  var epoch=this.epoch;

  var ephemeris = new Ephemeris();
  var gmst = ephemeris.GMST(date);
  var gst = gmst*15;
  var tle = new TLE();
  var tsince = tle.elapsedTime(epoch_year,epoch,date);

  var xmdf=xmo+xmdot*tsince;
  var omgadf=omegao+omgdot*tsince;
  var xnoddf=xnodeo+xnodot*tsince;
  var omega=omgadf;
  var xmp=xmdf;
  var tsq=tsince*tsince;
  var xnode=xnoddf+xnodcf*tsq;
  var tempa=1.0-c1*tsince;
  var tempe=bstar*c4*tsince;
  var templ=t2cof*tsq;

  if (isimp != 1){
    var delomg=omgcof*tsince;
    var delm=xmcof*(Math.pow((1.0+eta*Math.cos(xmdf)),3)-delmo);
    var temp=delomg+delm;
    var xmp=xmdf+temp;
    var omega=omgadf-temp;
    var tcube=tsq*tsince;
    var tfour=tsince*tcube;
    var tempa=tempa-d2*tsq-d3*tcube-d4*tfour;
    var tempe=tempe+bstar*c5*(Math.sin(xmp)-sinmo);
    var templ=templ+t3cof*tcube+tfour*(t4cof+tsince*t5cof);
  }
  var a=aodp*tempa*tempa;
  var e=eo-tempe;
  var xl=xmp+omega+xnode+xnodp*templ;
  var beta=Math.sqrt(1.0-e*e);
  var xn=xke/Math.pow(a,1.5);

  // long period periodics
  var axn=e*Math.cos(omega);
  var temp=1.0/(a*beta*beta);
  var xll=temp*xlcof*axn;
  var aynl=temp*aycof;
  var xlt=xl+xll;
  var ayn=e*Math.sin(omega)+aynl;

  // solve keplers equation

  //var capu=Number(fmod2p(xlt-xnode));
  var capu = (xlt-xnode)%(2.0*Math.PI);
  var temp2=capu;
  for (i=1; i<=10; i++){
    var sinepw=Math.sin(temp2);
    var cosepw=Math.cos(temp2);
    var temp3=axn*sinepw;
    var temp4=ayn*cosepw;
    var temp5=axn*cosepw;
    var temp6=ayn*sinepw;
    var epw=(capu-temp4+temp3-temp2)/(1.0-temp5-temp6)+temp2;
  if (Math.abs(epw-temp2) <= e6a){
    break
  };
  temp2=epw;
}
     // short period preliminary quantities

  var ecose=temp5+temp6;
  var esine=temp3-temp4;
  var elsq=axn*axn+ayn*ayn;
  var temp=1.0-elsq;
  var pl=a*temp;
  var r=a*(1.0-ecose);
  var temp1=1.0/r;
  var rdot=xke*Math.sqrt(a)*esine*temp1;
  var rfdot=xke*Math.sqrt(pl)*temp1;
  var temp2=a*temp1;
  var betal=Math.sqrt(temp);
  var temp3=1.0/(1.0+betal);
  var cosu=temp2*(cosepw-axn+ayn*esine*temp3);
  var sinu=temp2*(sinepw-ayn-axn*esine*temp3);
  var u=Math.atan2(sinu,cosu);
  if (u<0){u+= 2* Math.PI;}
  var sin2u=2.0*sinu*cosu;
  var cos2u=2.0*cosu*cosu-1.;
  var temp=1.0/pl;
  var temp1=ck2*temp;
  var temp2=temp1*temp;

  // update for short periodics

  var rk=r*(1.0-1.5*temp2*betal*x3thm1)+0.5*temp1*x1mth2*cos2u;
  var uk=u-0.25*temp2*x7thm1*sin2u;
  var xnodek=xnode+1.5*temp2*cosio*sin2u;
  var xinck=xincl+1.5*temp2*cosio*sinio*cos2u;
  var rdotk=rdot-xn*temp1*x1mth2*sin2u;
  var rfdotk=rfdot+xn*temp1*(x1mth2*cos2u+1.5*x3thm1);

  // orientation vectors

  var sinuk=Math.sin(uk);
  var cosuk=Math.cos(uk);
  var sinik=Math.sin(xinck);
  var cosik=Math.cos(xinck);
  var sinnok=Math.sin(xnodek);
  var cosnok=Math.cos(xnodek);
  var xmx=-sinnok*cosik;
  var xmy=cosnok*cosik;
  var ux=xmx*sinuk+cosnok*cosuk;
  var uy=xmy*sinuk+sinnok*cosuk;
  var uz=sinik*sinuk;
  var vx=xmx*cosuk-cosnok*sinuk;
  var vy=xmy*cosuk-sinnok*sinuk;
  var vz=sinik*cosuk;
  var x=rk*ux;
  var y=rk*uy;
  var z=rk*uz;
  var xdot=rdotk*ux+rfdotk*vx;
  var ydot=rdotk*uy+rfdotk*vy;
  var zdot=rdotk*uz+rfdotk*vz;

  var xkm = x*xkmper;
  var ykm = y*xkmper;
  var zkm = z*xkmper;
  var xdotkmps = xdot*xkmper/60;
  var ydotkmps = ydot*xkmper/60;
  var zdotkmps = zdot*xkmper/60;
  var velocity = Math.sqrt(Math.pow(xdot,2) + Math.pow(ydot,2) + Math.pow(zdot,2))*xkmper/60;

  
  this.x = xkm;
  this.y = ykm;
  this.z = zkm;
  
  var as_axis = xkm;
  var bs_axis = ykm;
  var cs_axis = zkm;

  this.xdot = xdotkmps;
  this.ydot = ydotkmps;
  this.zdot = zdotkmps;
  var us_axis=as_axis*Math.cos(gst*torad)+bs_axis*Math.sin(gst*torad);
  var vs_axis=-as_axis*Math.sin(gst*torad)+bs_axis*Math.cos(gst*torad);
  var ws_axis=cs_axis;

//longitude
  longitude=Math.atan(vs_axis/us_axis)/torad;
  if(us_axis<0){
    longitude=longitude+180;
  }
  if(longitude>=180){
    longitude=longitude-360;
  }

//tan_lat
 var t_lat1=ws_axis/Math.sqrt(us_axis*us_axis+vs_axis*vs_axis);
 var t_lat2=(6377.397155*0.006674372230614)/Math.sqrt(us_axis*us_axis+vs_axis*vs_axis);

var tan_lat=0;
do{
    var tmp=tan_lat;
    tan_lat= t_lat1+t_lat2*(tan_lat/Math.sqrt(1+0.99332*tan_lat*tan_lat));
}while (Math.abs(tan_lat-tmp)>0.00000001);

//latitude
  var latitude=Math.atan(tan_lat)/torad;

//altitude
  var altitude=Math.sqrt(1+tan_lat*tan_lat)*(ws_axis/tan_lat-6377.397155*0.993325628/(Math.sqrt(1+0.993325628*tan_lat*tan_lat)));
  this.longitude=longitude;
  this.latitude=latitude;
  this.altitude=altitude;
  this.velocity=velocity;
  return this;
}
