var map = null;
var geocoder = null;
var khand = null;
var _mode = 'd';  // can be d, dm, dgs

function load() 
{
    if (GBrowserIsCompatible()) {
        map = new GMap2(document.getElementById("map"));
        viewFromCookie();
        map.addControl(new GSmallMapControl());
        map.addControl(new GMapTypeControl());
        GEvent.addListener(map, "click", 
                           function(marker, point) {
                               reportPointCoords(point);
                           });
        // Don't need to add zoomend (moveend called after a zoom)
        GEvent.addListener(map, "moveend", 
                           function() {
                               viewToCookie();
                           });
        geocoder = new GClientGeocoder();
        geocoder.setBaseCountryCode("ES");

        khand = new GKeyboardHandler(map);

        var dt = $('#datepicker').val();
        if (!dt) {
            var t = new Date();
            var m = t.getMonth()+1;
            var d = t.getDate();
            var y = t.getFullYear();
            $('#datepicker').val(y + '-' + m + '-' + d);
        }
    }
}

function dec2sexa(num) 
{
    var r = Math.floor(num);
    if (num < 0) { r = r + 1; }
    return [r, Math.abs(num - r) * 60];
}

// Convert radian angle to degrees
function radToDeg(angleRad) 
{
    return (180.0 * angleRad / Math.PI);
}


// Convert degree angle to radians
function degToRad(angleDeg) 
{
    return (Math.PI * angleDeg / 180.0);
}

// Name:    calcJD
// Purpose: Julian day from calendar day
// Arguments:
//   year : 4 digit year
//   month: January = 1
//   day  : 1 - 31
// Return value:
//   The Julian day corresponding to the date
// Note:
//   Number is returned for start of day.  Fractional days should be
//   added later.
function calcJD(year, month, day)
{
    if (month <= 2) {
        year -= 1;
        month += 12;
    }
    var A = Math.floor(year/100);
    var B = 2 - A + Math.floor(A/4);
    
    var JD = Math.floor(365.25*(year + 4716)) + 
        Math.floor(30.6001*(month+1)) + day + B - 1524.5;
    return JD;
}

// Name:    calcTimeJulianCent
// Purpose: convert Julian Day to centuries since J2000.0
// Arguments:
//   jd : the Julian Day to convert
// Return value:
//   the T value corresponding to the Julian Day
function calcTimeJulianCent(jd)
{
    var T = (jd - 2451545.0)/36525.0;
    return T;
}

// Name:    calGeomMeanLongSun
// Purpose: calculate the Geometric Mean Longitude of the Sun
// Arguments:
//   t : number of Julian centuries since J2000.0
// Return value:
//   the Geometric Mean Longitude of the Sun in degrees
function calcGeomMeanLongSun(t)
{
    var L0 = 280.46646 + t * (36000.76983 + 0.0003032 * t);
    while(L0 > 360.0)
    {
        L0 -= 360.0;
    }
    while(L0 < 0.0)
    {
        L0 += 360.0;
    }
    return L0;      // in degrees
}

// Name:    calGeomAnomalySun
// Purpose: calculate the Geometric Mean Anomaly of the Sun
// Arguments:
//   t : number of Julian centuries since J2000.0
// Return value:
//   the Geometric Mean Anomaly of the Sun in degrees
function calcGeomMeanAnomalySun(t)
{
    var M = 357.52911 + t * (35999.05029 - 0.0001537 * t);
    return M;       // in degrees
}

// Name:    calcSunEqOfCenter
// Purpose: calculate the equation of center for the sun
// Arguments:
//   t : number of Julian centuries since J2000.0
// Return value:
//   in degrees
function calcSunEqOfCenter(t)
{
    var m = calcGeomMeanAnomalySun(t);

    var mrad = degToRad(m);
    var sinm = Math.sin(mrad);
    var sin2m = Math.sin(mrad+mrad);
    var sin3m = Math.sin(mrad+mrad+mrad);
    
    var C = sinm * (1.914602 - t * (0.004817 + 0.000014 * t)) + 
        sin2m * (0.019993 - 0.000101 * t) + sin3m * 0.000289;
    return C;       // in degrees
}

// Name:    calcSunTrueLong
// Purpose: calculate the true longitude of the sun
// Arguments:
//   t : number of Julian centuries since J2000.0
// Return value:
//   sun's true longitude in degrees
function calcSunTrueLong(t)
{
    var l0 = calcGeomMeanLongSun(t);
    var c = calcSunEqOfCenter(t);
    
    var O = l0 + c;
    return O;       // in degrees
}

// Name:    calcSunApparentLong
// Purpose: calculate the apparent longitude of the sun
// Arguments:
//   t : number of Julian centuries since J2000.0
// Return value:
//   sun's apparent longitude in degrees
function calcSunApparentLong(t)
{
    var o = calcSunTrueLong(t);
    
    var omega = 125.04 - 1934.136 * t;
    var lambda = o - 0.00569 - 0.00478 * Math.sin(degToRad(omega));
    return lambda;      // in degrees
}

// Name:    calcMeanObliquityOfEcliptic
// Purpose: calculate the mean obliquity of the ecliptic
// Arguments:
//   t : number of Julian centuries since J2000.0
// Return value:
//   mean obliquity in degrees
function calcMeanObliquityOfEcliptic(t)
{
    var seconds = 21.448 - t*(46.8150 + t*(0.00059 - t*(0.001813)));
    var e0 = 23.0 + (26.0 + (seconds/60.0))/60.0;
    return e0;      // in degrees
}

// Name:    calcObliquityCorrection
// Purpose: calculate the corrected obliquity of the ecliptic
// Arguments:
//   t : number of Julian centuries since J2000.0
// Return value:
//   corrected obliquity in degrees
function calcObliquityCorrection(t)
{
    var e0 = calcMeanObliquityOfEcliptic(t);
    
    var omega = 125.04 - 1934.136 * t;
    var e = e0 + 0.00256 * Math.cos(degToRad(omega));
    return e;       // in degrees
}

// Name:    calcSunDeclination
// Purpose: calculate the declination of the sun
// Arguments:
//   t : number of Julian centuries since J2000.0
// Return value:
//   sun's declination in degrees
function calcSunDeclination(t)
{
    var e = calcObliquityCorrection(t);
    var lambda = calcSunApparentLong(t);

    var sint = Math.sin(degToRad(e)) * Math.sin(degToRad(lambda));
    return radToDeg(Math.asin(sint));
}

// Name:    calcSunRtAscension
// Purpose: calculate the right ascension of the sun
// Arguments:
//   t : number of Julian centuries since J2000.0
// Return value:
//   sun's right ascension in degrees
function calcSunRtAscension(t)
{
    var e = calcObliquityCorrection(t);
    var lambda = calcSunApparentLong(t);
 
    var tananum = (Math.cos(degToRad(e)) * Math.sin(degToRad(lambda)));
    var tanadenom = (Math.cos(degToRad(lambda)));
    return radToDeg(Math.atan2(tananum, tanadenom));
}

// Name:    calcDayOfYear
// Purpose: Finds numerical day-of-year from mn, day and lp year info
// Arguments:
//   year
//   month: January = 1
//   day  : 1 - 31
// Return value:
//   The numerical day of year
function calcDayOfYear(year, month, day) 
{
    var N1 = Math.floor(275. * month / 9.0);
	var N2 = Math.floor((month + 9.0) / 12.0);
	var N3 = (1. + Math.floor((year - 4 * Math.floor(year / 4.) + 2) / 3.));
	return N1 - (N2 * N3) + day - 30;
}

function normTime(t) 
{
    if (t < 0) { t = t+24; }
    if (t >= 24) { t = t-24; }
    return t;
}

// ln in hours
function localMeanTime(H, ra, t, ln)
{
    return normTime(H + ra - (0.06571 * t) - 6.622 - ln);
}

function sun(lt, ln, year, month, day) 
{
    var T = calcTimeJulianCent(calcJD(year, month, day));
    var dec = degToRad(calcSunDeclination(T));
    var ra = calcSunRtAscension(T) / 15.; //hours
    lt = degToRad(lt);

    // Sun's local hour angle
    var cosH = (Math.cos(degToRad(90.833)) - Math.sin(dec)*Math.sin(lt)) /
        (Math.cos(dec)*Math.cos(lt));

    var lnHour = ln/15.0;
    var doy = calcDayOfYear(year, month, day);

    var times = {};
    if (cosH >= -1) {
        var Hset = radToDeg(Math.acos(cosH));
        times['set'] = localMeanTime(Hset/15., ra, doy + (18 - lnHour)/24., 
                                       lnHour);
    }
    if (cosH <= 1) {
        var Hrise = 360 - Hset;
        times['rise'] = localMeanTime(Hrise/15., ra, doy + (6 - lnHour)/24., 
                                      lnHour);
    }
    return times;
}

// rise 7:54, set 17:37
// 42 43.4974, -8 28.8867

// rise 13:11 set 19:39
// 63 53.0729, -63 16.8750

function toHMin (t) 
{
    var h = Math.floor(t);
    var m = Math.floor(60. * (t - h)) + '';
    if (m.length == 1) { m = '0' + m; }
    return h + ':' + m;
}

function getSelectedDate() 
{
    var dtext = $('#datepicker').val();
    dtext = dtext.replace('/', '-');
    var df = dtext.split('-');
    return new Date(df[0], df[1]-1, df[2]);
}

function reportPointCoords(point) 
{
    if (point) {
        var lt = point.lat();
        var ltgm = dec2sexa(lt);
        var ltms = dec2sexa(ltgm[1]);

        var ln = point.lng();
        var lngm = dec2sexa(ln);
        var lnms = dec2sexa(lngm[1]);

        var date = getSelectedDate();

        var times = sun(lt, ln, 
            date.getFullYear(), date.getMonth()+1, date.getDate());
        var tset = '(no se pone)';
        if (times['set']) {
            tset = toHMin(times['set']);
        }
        var trise = '(no sale)';
        if (times['rise']) {
            trise = toHMin(times['rise']);
        }

        // One second is around 30m, so for a precision of at least 1m
        // we need 0.03 s, 0.0005 m, or 9.2e-6 dg. 

        var latlong = "<font color='blue'>lat, long</font><font size='-1'>";
        if (_mode == 'd') {
            latlong += (' (grad):</font><br/>&nbsp;&nbsp;&nbsp;' + 
                        lt.toPrecision(8) + ", " + 
                        ln.toPrecision(8));
        }
        if (_mode == 'dm') {
            latlong += (' (grad min)</font><br/>&nbsp;&nbsp;&nbsp;' +
                        ltgm[0] + " " + 
                        ltgm[1].toPrecision(6) + ", " + 
                        lngm[0] + " " + 
                        lngm[1].toPrecision(6));
        }
        if (_mode == 'dms') {
            latlong += (' (grad min seg)</font><br/>&nbsp;&nbsp;&nbsp;' +
                        ltgm[0] + " " + ltms[0] + " " + 
                        ltms[1].toPrecision(5) + ", " + 
                        lngm[0] + " " + lnms[0] + " " + 
                        lnms[1].toPrecision(5));
        }
        map.openInfoWindowHtml(point,
                               latlong + "<br/><font color='blue'>sol</font> <font size='-1'>(hora <a href='http://es.wikipedia.org/wiki/Tiempo_universal_coordinado'>UTC</a>):</font>"+
                               "<br/>&nbsp;&nbsp;&nbsp;salida: " + trise +
                               "<br/>&nbsp;&nbsp;&nbsp;puesta: " + tset
                              );
    }
}

function findAddress(address, then) 
{
    if (geocoder) {
        geocoder.getLatLng(address,
                           function(point) {
                               if (!point) {
                                   alert("No hemos encontrado " + address);
                               } else {
                                   then(point, address);
                               }
                           });
    }
    else { alert("Tu navegador no es compatible con Google Maps. " +
                 "Deberķas considerar usar firefox."); }
}

function showPlace(where) 
{
    if (map) {
        findAddress(where,
                   function(point) {
                       map.setCenter(point);
                       reportPointCoords(point);
                   });
    }
    else { alert("Tu navegador no es compatible con Google Maps. " +
                 "Deberķas considerar usar firefox!."); }
}

function viewToCookie() 
{
    var nextyear = new Date();
    nextyear.setFullYear(nextyear.getFullYear() + 1);
    var expire = '; expires=' + nextyear.toGMTString();

    var center = map.getCenter();
    var zoom = map.getZoom();
    document.cookie = 'lat=' + escape(center.lat()) + expire;
    document.cookie = 'long=' + escape(center.lng()) + expire;
    document.cookie = 'zoom=' + escape(zoom) + expire;
    document.cookie = 'mode=' + _mode + expire;
}

function cookieField(fname) 
{
    var cookies = document.cookie;
    var pos = cookies.indexOf(fname + '=');
    if (pos != -1) {
        var start = pos + fname.length + 1;
        var end = cookies.indexOf(';', start);
        if (end == -1) end = cookies.length;
        var val = cookies.substring(start, end);
        return (unescape(val));
    }
}

function viewFromCookie() 
{
    var lat = cookieField("lat");
    var lng = cookieField("long");
    var zoom = cookieField("zoom");
    _mode = cookieField("mode");
    if (!_mode) { _mode = 'd'; }

    if (lat && lng && zoom) {
        map.setCenter(new GLatLng(parseFloat(lat), parseFloat(lng)), 
                      parseInt(zoom));
    }
    else {
        viewWholeSpain();
    }
}

function viewWholeSpain() 
{
    map.setCenter(new GLatLng(39.75, -3.25), 6);
}

