﻿// JScript File

/*
 * @author: Charlie Szymanski
 * @created: March 28th, 2007 
 * @name: storm_path_script.js
 * @purpose: This will contain a class that generates storm paths. Basically the idea is to create a new instance of "StormPath"
 *           and have the class do the AJAX call and store the data. This should happen when the storm is added to the list of
 *           of 'Selected Storms' -- after the storm is loaded, there needs to be a method to toggle the path and winds on and off
 *           All storms will be saved into an array for global access.
 
     UPDATED August 2008 to include dates on hover over points. Datefield comes over in Euro style, needed to be converted to U.S. style
 */




var POIManager = Class.create();
var poiManager;
POIManager.prototype = {
    initialize: function(){
        this.poiArray = new Array()
        this.getPOI();
    },
    
    getPOI: function(){
        ibiseye.srvGetPointsOfInterest(this.getPOI_result.bind(this));
    },
    
    getPOI_result: function(r){
        //test(r);
        var ds = r.value;
        if(ds == null) return;
        var rows = ds.Tables[0].Rows.length;
	    if(rows == 0){
	        return;
	    }
	    for( var i=0; i < rows; i++ ){
	        row = ds.Tables[0].Rows[i];
            var data = new Hash();
            data.type = row.TYPE;
            data.lat = row.MAPLAT;
            data.lng = row.MAPLON;
            data.id = row.ANCHOR;
            data.html = "";
            if(data.type == "latlonline"){
                data.type2 = "Tropical Wave";
            }else if(data.type == "box"){
                data.type2 = "Area of Interest";
            }else{
                data.type2 = "Weather being watched";
            }
            
            data.html = "<a href='http://www.ibiseye.com' target='_blank'>Visit IBISEYE.com for more information about this "+data.type2+"</a>";
            data.index = i+1;
            
            this.poiArray.push(new POI(data));
        
        }
        
        //loop through invest data if available
        rows = ds.Tables[1].Rows.length;
        if(rows == 0){
            //return;
        }
        for(var i=0; i < rows; i++){
            row = ds.Tables[1].Rows[i];
            var data = new Hash();
            data.line = row.ENCODED.replace(/\\\\/g, "\\");;
            data.lat = row.LAT;
            data.lng = row.LON;
            data.bearing = row.STORM_BEARING;
            data.forwardSpeed = row.STORM_FORWARD_KTS;
            data.gusts = row.STORM_GUSTS_KTS;
            data.id = row.STORM_ID;
            data.sname = row.STORM_NAME;
            data.pressure = row.STORM_PRESSURE;
            data.wind = row.STORM_WIND_KTS;
            data.count = row.COUNTER;
            this.poiArray.push(new Invest(data));
            
        }
        
        this.showPOI();
        
    },
    
    showPOI: function(){
        this.showingPOI = true;
        this.poiArray.each(function(poi){
            poi.show();
        }.bind(this));
    }

}



//Link to KML file
var kmlURL = "http://ibis.htcreative.com/KML/windfields.aspx/";
//   /STORM ID/STORM TYPE/ (TS or H)


/**
 *
 * StormPath class -- keeps track of all the data related to a single storm.
 * @params (stormID): The ID of the storm
 * @params (active): Whether or not the storm is Active
 *
 **/  
 var stormPath = [];
 var loadedFirstStorm = false;
 function addStorm(storm){
    if(!loadedFirstStorm){
        stormPath.push(new StormPath(storm.stormID, storm.active, true));
        $("descriptor").innerHTML = "Storm " + storm.name;
        loadedFirstStorm = true;
    }else{
        stormPath.push(new StormPath(storm.stormID, storm.active, false));
        $("descriptor").innerHTML += ", " + storm.name;
    }
 }
 
 
 /*
 if(this.isFirst){
	                $("descriptor").innerHTML = "Storm " + this.name;
	            }else{
	                $("descriptor").innerHTML += ", " + this.name;
	            }*/
 
var StormPath = Class.create();
StormPath.prototype = {
    //initialze the class
    initialize: function(stormID, active, isFirst){
        this.stormID = stormID;
        this.active = active;
        //array of data objects
        this.dataArray = new Array();
        //array of markers
        this.markerArray = new Array();
        //array of normal points
        this.points = new Array();
        //array of forecasetd points
        this.forecastPoints = new Array();
        //is my line mapped?
        this.pathMapped = false;
        //are my winds mapped?
        this.fullMapped = false;
        //variable for kml winds
        this.windFieldsTropical;
        this.windFieldsHurricane;
        this.isFirst = isFirst;
        //this.trackBubbleStats = true;
        //lets also keep track of the boundaries of the storm
        this.stormBounds = new GLatLngBounds();
        //array to hold the encoded polyline data for MODELS
        this.modelArray = new Array();
        this.showingModels = false;
        //AJAXify the data
        this.getData();
        
    },
    /**
     * Calls the AJAX function
     **/
    getData: function(){
        
        //grab data
        ibiseye.srvGetStormPath(this.stormID, this.active, this.getData_result.bind(this));
    },
    /**
     *Loads the AJAX data
     *@params (r): .NET DataSet
     **/
    getData_result: function(r){
        var ds = r.value;
        //test(r);
        var rows = ds.Tables[0].Rows.length;
	    if(rows == 0){
	        return;
	    }
	    var pastFirstForecastPoint = false;
	    for( var i=0; i < rows; i++ ){
	        //row
            row = ds.Tables[0].Rows[i];
             //local variables for the storm list
            var data = new Object();
	        //if we're in the first row, add the unchanging variables to the storm object itself
	        if(i == 0){
	            this.season = row.YEAR_SEASON;
	            this.name = row.NAME; 
	            
	        }
	       
            //data.date = row.AD_TIME;
            data.name = row.NAME;
            
            data.lat = row.LAT;
            data.lng = row.LONG;
            data.wind = row.WIND_KTS;
            data.stormID = this.stormID;
            data.category = row.CAT;
            data.stormType = row.STORM_TYPE;
            data.html = row.PHTML;
            data.segmentID = row.ID;
            data.index = i;
            data.satImage = row.SAT_IMAGE;
            data.date = row.DT;
            //console.log(row);
            //array to hold HTML text
            var html = new Array();
            //generate icon
            var icon = this.getSimpleIcon(data.category);
            //generate the first info window
            var bubble = this.buildBubble(data);
            html.push(new GInfoWindowTab(data.name, "<div style='width:200px;'>"+bubble+"</div>"));
            /*
                MoTamman: SAT_IMAGES
                MoTamman: path: http://ibis.htcreative.com/data/goes12/archive/2*/

            //generate a tooltip
            var tooltip = this.buildToolTip(data);
            //generate the location of this marker
            var point = new GLatLng(data.lat, data.lng);
            //console.log(point + " Segment ID: " + data.segmentID);
            var marker = this.createMarker(point, html, icon, data, tooltip);
            //add marker to array
            this.markerArray.push(marker);
            //save data
            this.dataArray.push(data);
            //add to points
            if(data.stormType.toLowerCase() == "forecast"){
                if(!pastFirstForecastPoint){
                    var previousRow = ds.Tables[0].Rows[i-1];
                    this.lastActualPoint = this.markerArray[i-1];
                    var prevLatLng = new GLatLng(previousRow.LAT, previousRow.LONG);
                    this.forecastPoints.push(prevLatLng);
                    pastFirstForecastPoint = true;
                   // this.getModels();
                   // this.trackBubbleStats = false;
                }
                this.forecastPoints.push(point);
            }else{
                this.points.push(point);
            }
            /*if( (data.stormType.toLowerCase() == "forecast") && ( i < rows - 3) ){
                this.stormBounds.extend(point);
            }else if (data.stormType.toLowerCase() != "forecast"){
                this.stormBounds.extend(point);
            }*/
            //check to see what the category is -- do this every time and set class properties based on max winds
            if(data.category.startsWith("T")) this.isTropicalStorm = true;
            if(data.category.startsWith("H")) this.isHurricane = true;
            if(this.forecastPoints.length > 0) this.isActive = true;
            
        }
        if(this.isFirst){
            if(this.isTropicalStorm || this.isHurricane){
                this.kmlURL = kmlURL + this.stormID;
            }
            //using our boundaries, we'll calculate the centerpoint of the storm, as well as the zoom level
            this.forecastPoints.each(function(point){
                this.stormBounds.extend(point);
            }.bind(this));
            
            if(this.points.length < 4){
                this.points.each(function(point){
                    this.stormBounds.extend(point);
                }.bind(this));
            }else{
                this.stormBounds.extend(this.points[this.points.length-1]);
                this.stormBounds.extend(this.points[this.points.length-2]);
            }
            
            
            
            var clat = (this.stormBounds.getNorthEast().lat() + this.stormBounds.getSouthWest().lat()) /2;
            var clng = (this.stormBounds.getNorthEast().lng() + this.stormBounds.getSouthWest().lng()) /2;
            this.centerLatLng = new GLatLng(clat, clng);
            this.boundsZoom = map.getBoundsZoomLevel(this.stormBounds);
            this.mapStormFull();
            if(this.boundsZoom > 4) this.boundsZoom = 4;
            //if(this.centerLatLng.lng() > -56){
            //    map.setCenter(this.centerLatLng, this.boundsZoom+2);
            //}else{
            //    map.setCenter(this.centerLatLng, this.boundsZoom);
            //}    
            
        }else{
            this.mapStormPathOnly();
        }
    },
   /**
    *If the KML URL is coming in through an AJAX call, we'll catch it and assign it as a class property here.
    **/
    loadKML: function(r){
        this.kmlURL = r.value;
        
    },
    
    buildBubble: function(data){
        var bubble = "<a href='http://www.ibiseye.com' target='_blank'>Visit IBISEYE.com for more details</a>";
        return bubble;
    },
    
    //map just the storm path
    mapStormPathOnly: function(){
       
        //add storm line to map
       this.stormPathOnMap = new GPolyline(this.points,"#000000",4,.5);
	    map.addOverlay(this.stormPathOnMap);
	    //then the forecast points, if there are any
	    if(this.forecastPoints.length > 0){
	        this.forecastPathOnMap = new GPolyline(this.forecastPoints,"#f00000",4,.5);
	        map.addOverlay(this.forecastPathOnMap);
        }
        this.markerArray.each(function(m){map.addOverlay(m)});
        this.pathMapped = true;
     
        
    },
    //map out the full storm
    mapStormFull: function(){
        this.mapStormPathOnly();
        this.fullMapped = true;
        loadKML(this.kmlURL);
    },
    
   
    //build out an info bubble, takes a data object (basically a row of data)
    buildToolTip: function(data){
        var name = data.name;
        
        //parse date data
        var dateParts = data.date.split("/");
        var mm = dateParts[1];
        var dd = dateParts[0];
        var yyyy = dateParts[2];
        
        var dateString = mm + "/" + dd + "/" + yyyy;
        
        
        if(data.stormType.toLowerCase() == "forecast"){name = name + "<br />forecast point"}
         var html = "<div  style='font-size:10px; margin:5px;'><span class='red'>"+name+"</span><br /><span>wind: "+ data.wind + "mph</span><br />"+
                    "<span>Category: "+data.category+"<br />" + dateString + ":00 EDT</span>"
                    "</div>";
         return html;
         
    },
    //gets a simple google map marker based on storm category
    getSimpleIcon: function(cat){
        //sometimes there is an "E" status -- I have no idea what E is
        if( ( cat == "E") || ( cat == "L") || (cat == "H") || (cat == "W") ) cat = "td";
        var icon = new GIcon();
        icon.image = "images/icons/storms/"+cat+".png"; 
	    icon.iconSize = new GSize(17, 16);
	    icon.iconAnchor = new GPoint(8, 8);
	    icon.infoWindowAnchor = new GPoint(8, 8);
	    return icon;
    },
    /**
     *creates a Google Map Marker with HTML and ToolTips
     *@params (point): a GLatLng point
     *@params (html): an Array of HTML text -- one for each tab
     *@params (ic): a GIcon
     *@params (data): the data object used to generate the HTML and this point of the storm
     *@params (toolText): the HTML markup for the tooltip
     *@returns: a new GMarker
     **/ 
    createMarker: function(point,html,ic, data, toolText) {
       data.point = point;
       var marker = new GMarker(point,ic);
       marker.data = data;
       marker.html = html;
       marker.tooltip = "<div class='tooltip'>"+ toolText + "</div>";
       //listen for a marker click.
       GEvent.addListener(marker, "click", function() {
              this.markerClick(marker);
       }.bind(this));
       //when the window is opened, we want to ajax in the markup for the marker window
       GEvent.addListener(marker, "infowindowopen", function(){
            
       }.bind(this));
       
       GEvent.addListener(marker, "infowindowclose", function(){
           
       }.bind(this));
       //add listeners for mouse overs and mouse outs to show and hide the tooltip
       GEvent.addListener(marker,"mouseover", function() {
             showTooltip(marker, map);
       }.bind(this));      
	   GEvent.addListener(marker,"mouseout", function() {
	       tooltip.style.visibility="hidden"
       }.bind(this));	
       
       return marker;
    },
    
    markerClick: function(marker){
        if(!marker) return;
        //close current info window
              map.closeInfoWindow();
             
              //attempt to do my own panning.
              var markerLocation = marker.getPoint();
              var pixels = map.fromLatLngToDivPixel(markerLocation);
              var center = map.getCenter();
              var centerPixels = map.fromLatLngToDivPixel(center);
              
              var y = pixels.y;
              var x = pixels.x;
              x +=50;
              y = y - 100;
              
              var newLatLng = map.fromDivPixelToLatLng(new GPoint(x, y));
              map.panTo(newLatLng); 
             
              var pe = new PeriodicalExecuter(function(){
                    pe.stop();
                    marker.openInfoWindowTabsHtml(marker.html, {suppressMapPan:true});
               }, 1);
               
                    
    
    }

};

 
//holder for the winds KML layer
var windFields = null;

/**
 *
 *loadKML function is for adding tile sets to the map for a storm path. Removes the existing wind fields so the map
 * doesn't get cluttered.
 *@params (url): the link to the KML file
 **/
function loadKML(url){
    if(windFields) map.removeOverlay(windFields);
    windFieldsLayer = new GTileLayer(new GCopyrightCollection(), 0, 17);
    //getTileUrl function for hitting the mapsdt server for images
    windFieldsLayer.getTileUrl = function(a,b) {
        b=this.maxResolution()-b;
        return "http://maps.google.com/mapsdt?id="+url+"//"+alertsVersion+"&x="+a.x+"&y="+a.y+"&zoom="+b;
    }
    //make sure to define that the layear is PNG
    windFieldsLayer.isPng = function() {return true;}
    //create a new overlay out of our new tile set
    windFields = new GTileLayerOverlay(windFieldsLayer);
    //and add it to the map
    map.addOverlay(windFields);
}





var POI = Class.create();

POI.prototype = {

    initialize: function(data){
        this.data = data;
        this.icon = this.getIcon(data.type);
       // this.html = new Array();
       // this.html.push(new GInfoWindowTab(data.type, "<div style='width:100px;'>"+data.html+"</div>"));
        this.html = "<div style='width:200px;'>"+data.html+"</div>";
        this.point = new GLatLng(data.lat, data.lng);
        this.marker = this.createMarker(this.point, this.html, this.icon, data.type2, this.data);
    },
    
    /**
     *Generates an Icon based on type 
    */
    getIcon: function(type){
        var icon = new GIcon();
        icon.image = "images/icons/storms/"+type+".png"; 
	    icon.iconSize = new GSize(16, 17);
	    icon.iconAnchor = new GPoint(8,8);
	    icon.infoWindowAnchor = new GPoint(8, 8);
	    return icon;
    },
    
    createMarker: function(point,html,ic,toolText, data) {
       
       var marker = new GMarker(point,ic);
       marker.data = data;
       marker.tooltip = "<div class='tooltip'>"+ toolText + "</div>";
       
       GEvent.addListener(marker, "click", function() {
             // marker.openInfoWindowTabsHtml(html, {suppressMapPan:true});
              marker.openInfoWindowHtml(html);
              //pan to the marker
              this.panToMarker();
                         
       }.bind(this));
       
       GEvent.addListener(marker,"mouseover", function() {
             showTooltip(marker, map);
       }.bind(this));      
	   GEvent.addListener(marker,"mouseout", function() {
	       tooltip.style.visibility="hidden"
       }.bind(this));	
       
      
       
       return marker;
   },
   
   show: function(){
        map.addOverlay(this.marker);
   },
   
   panToMarker: function(){
        //attempt to do my own panning.
              var markerLocation = this.marker.getPoint();
              var pixels = map.fromLatLngToDivPixel(markerLocation);
              var center = map.getCenter();
              var centerPixels = map.fromLatLngToDivPixel(center);
              //centerPixels
              var y = pixels.y;
              y = y - 100;
              var newLatLng = map.fromDivPixelToLatLng(new GPoint(pixels.x, y));
              map.panTo(newLatLng);
    },
    /**
     * Destroys this marker and hopefully realeses its memory
     *
     **/
   destroy: function(){
    this.marker = null;
    this.data = null;
    this.icon = null;
    this.point = null;
    this.html = null;
   }

}



var Invest = Class.create();

Invest.prototype = {

    initialize: function(data){
        this.data = data;
        this.icon = this.getIcon(data.type);
        this.extraLine = null;
        this.line = this.getLine(data.line, "#000000", data.count-1);
        this.stormID = data.id;
        this.html = new Array();
        this.html.push(new GInfoWindowTab(data.type, "<div style='width:200px;'>"+this.buildBubble()+"</div>"));
        this.point = new GLatLng(data.lat, data.lng);
        var tooltip = "<b>Invest: </b> Bearing " + data.bearing + " degrees, at " + data.forwardSpeed + " with wind speeds of " + data.wind + " and a pressure of " + data.pressure + "." 
        this.marker = this.createMarker(this.point, this.icon, this.html, tooltip, this.data);
    },
    
    /**
     *Generates an Icon based on type 
    */
    getIcon: function(type){
        var icon = new GIcon();
        icon.image = "images/icons/storms/invest.png"; 
	    icon.iconSize = new GSize(25, 25);
	    icon.iconAnchor = new GPoint(13,13);
	    icon.infoWindowAnchor = new GPoint(13, 13);
	    return icon;
    },
    
    buildBubble: function(){
       var html = "<a href='http://www.ibiseye.com' target='_blank'>Visit IBISEYE.com for more information about this invest</a>";
        return html;
    },
    
    getLine: function(line, color, count){
        var levels = "";
        for(var i = 0; i < count; i++){
            levels += "P";
        }
        return new GPolyline.fromEncoded({
                        color: color,
                        weight: 3,
                        opacity: 0.8,
                        points: line,
                        levels: levels,
                        zoomFactor: 1,
                        numLevels: 18
                    });
    },
    
    createMarker: function(point,ic, html, toolText, data) {
       
       var marker = new GMarker(point,ic);
       marker.data = data;
       marker.tooltip = "<div class='tooltip'>"+ toolText + "</div>";
       
       GEvent.addListener(marker, "click", function() {
              marker.openInfoWindowTabsHtml(html);
              
                         
       }.bind(this));
       //when info window is finally rendered, add the alert narrative
       GEvent.addListener(marker, "infowindowopen", function(){
            
       }.bind(this));
       //listen for hovers for the tooltip.
       GEvent.addListener(marker,"mouseover", function() {
              showTooltip(marker, map);
              this.addExtraLine();
       }.bind(this));      
	   GEvent.addListener(marker,"mouseout", function() {
		    tooltip.style.visibility="hidden"
		    this.removeExtraLine();
       }.bind(this));	
       
       return marker;
   },
   //pan to model marker -- Currently inactive
   
    //show the path and marker
    show: function(){
       
        map.addOverlay(this.marker);
        map.addOverlay(this.line);;
        
    },
    
    //attempt to add another line to show the previous and next segments of this storm for clarity
    addExtraLine: function(marker){
       
        //create another line based on the points already in the point array. For now we'll leave forecast points as is.
        this.extraLine = this.getLine(this.data.line, "#FFFFAA", this.data.count-1);
	    map.addOverlay(this.extraLine);
        
    },
    
    //attempt to remove that line
    removeExtraLine: function(marker){
        map.removeOverlay(this.extraLine);
        this.extraLine = null;
    } 

}




alertKMLLocation =  "http://ibis.htcreative.com/KML/ibiseye/livealerts.aspx/";
function addWeatherKML(){
        
        
            newAlertLayer = new GTileLayer(new GCopyrightCollection(), 0, 17);
            //getTileUrl function for hitting the mapsdt server for images
            newAlertLayer.getTileUrl = function(a,b) {
                b=this.maxResolution()-b;
                //see utils_script for the get version code
                //need to make sure that the KML is aligned to the version -------------^
                return "http://maps.google.com/mapsdt?id="+alertKMLLocation+"ALL/"+alertsVersion+"&x="+a.x+"&y="+a.y+"&zoom="+b;
            }
            //make sure to define that the layear is PNG
            newAlertLayer.isPng = function() {return true;}
            //create a new overlay out of our new tile set
            var overlay = new GTileLayerOverlay(newAlertLayer);
            //and add it to the map
            map.addOverlay(overlay)
       }