hackedteam/rcs-console

View on GitHub
src/it/ht/rcs/console/entities/view/GeoMapView.mxml

Summary

Maintainability
Test Coverage
<?xml version="1.0" encoding="utf-8"?>

<s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
          xmlns:s="library://ns.adobe.com/flex/spark"
          xmlns:mx="library://ns.adobe.com/flex/mx"
          xmlns:maps="it.ht.rcs.console.maps.*"
          xmlns:components="it.ht.rcs.console.entities.view.components.*"
          xmlns:timeline="it.ht.rcs.console.entities.view.components.advanced.timeline.*"
          xmlns:entities="it.ht.rcs.console.entities.view.*"
          xmlns:renderers="it.ht.rcs.console.entities.view.renderers.*"
          removedFromStage="onRemovedFromStage()"
          addedToStage="onAddedToStage()"
          height="100%"
          width="100%">
  
  <fx:Script>
    <![CDATA[
  
      
      import flash.filters.GlowFilter;
      import flash.utils.setTimeout;
      
      import it.ht.rcs.console.entities.controller.EntityManager;
      import it.ht.rcs.console.entities.model.Entity;
      import it.ht.rcs.console.entities.model.Link;
      import it.ht.rcs.console.entities.model.Position;
      import it.ht.rcs.console.entities.model.Positions;
      import it.ht.rcs.console.entities.model.PositionsFlow;
      import it.ht.rcs.console.entities.view.components.advanced.timeline.HourRenderer;
      import it.ht.rcs.console.entities.view.components.advanced.timeline.TimelineUtils;
      import it.ht.rcs.console.entities.view.map.CustomMarker;
      import it.ht.rcs.console.events.FilterEvent;
      import it.ht.rcs.console.events.RefreshEvent;
      import it.ht.rcs.console.events.SectionEvent;
      import it.ht.rcs.console.monitor.controller.LicenseManager;
      import it.ht.rcs.console.search.model.SearchItem;
      import it.ht.rcs.console.target.model.Target;
      
      import locale.R;
      
      import mx.collections.ArrayCollection;
      import mx.collections.ListCollectionView;
      import mx.controls.Alert;
      import mx.core.FlexGlobals;
      import mx.rpc.events.FaultEvent;
      import mx.rpc.events.ResultEvent;
      
      import org.un.cava.birdeye.ravis.graphLayout.data.Edge;
      
      //map stuff
      //map stuff
    
     
      private var icons:Dictionary; //pins?
      private var targetsMarkers:Dictionary; //pins?
      private var placesMarkers:Dictionary;
      private var lines:Array;
      private var links:Dictionary;
      private var markers:Array;
      private var circles:Array;

      //Styling
      private var circleFillColor:uint=0xFF0000;
      private var circleFillAlpha:Number=0.2;
      private var circleBorderTickness:int=0.2;
      private var circleBorderFillColor:uint=0xFF0000;
      private var circleBorderFillAlpha:Number=0.5;
      
      private const ALPHA_RATIO:Number=100 / 60;
      
      private var relevence0:uint=0x333333;
      private var relevence1:uint=0x999999;
      private var relevence2:uint=0x5DE35F;
      private var relevence3:uint=0xFFDC42;
      private var relevence4:uint=0xFF4034;
      
      private var relevanceColors:Array=[relevence0, relevence1, relevence2, relevence3, relevence4];
      
      
      [Bindable]
      public var actionbar:EntitiesActionBar
      [Bindable]
      public var section:EntitiesSection;
      [Bindable]
      public var entities:ListCollectionView; //all entities
      
      private var startDate:Date;
      
      private var endDate:Date;
      
      private var currentDate:Date;
      
      [Bindable]
      public var filterCriteria:Object={ type: [], relevance: [], time: "time", from: "lastMonth", to: 0 };
      
      [Bindable]
      public var options:Object={links: false, fit: true, places: false};
      
      private var entitiesToShow:ArrayCollection //only targets and positions
      private var positions:ArrayCollection; //only positions
      private var targets:ArrayCollection; //only targets
      
      //TODO > CHECK MAP IS READY!
      private function onMapReady():void
      {
       
      }
      
      private function clearMap():void
      {
       
      }
      
      private function drawMap():void
      {
          trace("DRAW MAP")
          mapViewer.setAllowNoSelection(true);
          mapViewer.clearOverlays();
          
          var i:int=0;
          var entity:Entity;
          var marker:Object;
          
          targetsMarkers=new Dictionary()
          placesMarkers=new Dictionary()
          icons=new Dictionary()
          markers=new Array();
          circles=new Array();
          lines=new Array();
          links=new Dictionary();
          
          var items:Vector.<Object>=new Vector.<Object>();
          
          //positions
          for (i=0; i < positions.length; i++)
          {
            entity=positions.getItemAt(i) as Entity;
            items.push(entity)
            marker=mapViewer.addMarker(Number(entity.position.latitude), Number(entity.position.longitude), "mapMarker_location.png","location",entity._id);
            
            markers.push(marker);
            placesMarkers[entity._id]=marker;
            marker.setVisible(false);
    
          }
          
          //targets
          for (i=0; i < targets.length; i++)
          {
            entity=targets.getItemAt(i) as Entity;
            if (entity.position)
            {
              items.push(entity)
              marker=mapViewer.addMarker(Number(entity.position.latitude), Number(entity.position.longitude), "mapMarker_target.png", "target",entity._id);
              
              markers.push(marker);
              targetsMarkers[entity._id]=marker;
              marker.setVisible(false);
         
            }
          }
          mapViewer.positions=items;
          onDateChange()
          
      }
      
      private function onRemovedFromStage():void
      {
        tracker.reset();
        FlexGlobals.topLevelApplication.removeEventListener(FilterEvent.ENTITIES_FILTER_CHANGED, onFilterChange);
        FlexGlobals.topLevelApplication.removeEventListener(FilterEvent.RESET_FILTER, resetFilter);
        FlexGlobals.topLevelApplication.removeEventListener("optionsChange", onOptionsChange);
        
      }
      
      private function onOptionsChange(e:Event):void
      {
        trace("options change")
        onDateChange()
      }
      
      
      private function onFilterChange(e:FilterEvent):void
      {
        trace("GEO MAP FILTER CHANGE")
        if (filterCriteria.from == "lastMonth")
        {
          startDate=new Date();
          startDate.time=startDate.time - (1000 * 60 * 60 * 24 * 30);
          endDate=new Date();
        }
          
        else if (filterCriteria.from == "last3Months")
        {
          startDate=new Date();
          startDate.time=startDate.time - (1000 * 60 * 60 * 24 * 90);
          endDate=new Date();
        }
          
        else if (filterCriteria.from == "last6Months")
        {
          startDate=new Date();
          startDate.time=startDate.time - (1000 * 60 * 60 * 24 * 180);
          endDate=new Date();
        }
          
        else if (filterCriteria.from && filterCriteria.to)
        {
          startDate=new Date(filterCriteria.from * 1000)
          endDate=new Date(filterCriteria.to * 1000);
        }
        
        trace("from: " + startDate)
        trace("to: " + endDate)
        
        clearMap()
        mapViewer.visible=false
        refresh()
      }
      
      private function resetFilter(e:FilterEvent):void
      {
        trace("FILTER RESET")
      }
      
      public function doStop():void
      {
        //tracker.doStop()
      }

      
    
   
      public function init():void
      {
        
   
        
        //FlexGlobals.topLevelApplication.addEventListener(RefreshEvent.REFRESH, onRefresh);
        
        //default dates
        
        endDate=new Date();
        endDate.hours=23
        endDate.minutes=59
        endDate.seconds=59;
        endDate.milliseconds=0
        
        startDate=new Date();
        startDate.date-=30; //30 days
        startDate.hours=0;
        startDate.minutes=0;
        startDate.seconds=0;
        startDate.milliseconds=0;
        
        
        //default filters settings
        /*         fitCh.selected=true;
        positionsCh.selected=false;
        linksCh.selected=false; */
        
        
        options.fit=true;
        options.places=false
        options.links=false;
        
    
        
        tracker.visible=false;
        loadingBox.visible=true;
        tracker.addEventListener(Timeline.READY, onTrackerReady)
        
      }
      
      
      //not used - remove
      private function onDateRange(e:Event):void
      {
        e.stopImmediatePropagation()
        tracker.reset();
        
        if (filterCriteria.from && filterCriteria.to)
        {
          //TODO CHECK DATES!
        }

        setTimeout(onDateFilter, 100)
      }
      
      //not used - remove
      private function onDateFilter():void
      {
        
        tracker.visible=false;
        loadingBox.visible=true;
        
        if (filterCriteria.from > filterCriteria.to)
        {
          /*  fromDf.selectedDate=new Date()
          fromDf.selectedDate.time=startDate.time
          toDf.selectedDate=new Date()
          toDf.selectedDate.time=endDate.time */
          Alert.show("Start date must be before end date")
          return;
        }
          
        else if ((filterCriteria.to - filterCriteria.from) > (TimelineUtils.DAY * 365))
        {
          /* fromDf.selectedDate=new Date(startDate.time)
          toDf.selectedDate=new Date(endDate.time) */
          Alert.show("Selected range cannot exceed one year")
          return;
        }
        
        /*         startDate=new Date(fromDf.selectedDate.time);
        startDate.minutes=0;
        startDate.seconds=0;
        startDate.milliseconds=0
        
        endDate=new Date(toDf.selectedDate.time);
        endDate.hours=23
        endDate.minutes=59;
        endDate.seconds=59;
        endDate.milliseconds=0; */
        
        if (filterCriteria.from == "lastMonth")
        {
          startDate=new Date();
          startDate.time=startDate.time - (1000 * 60 * 60 * 24 * 30);
          endDate=new Date();
        }
          
        else if (filterCriteria.from == "last3Months")
        {
          startDate=new Date();
          startDate.time=startDate.time - (1000 * 60 * 60 * 24 * 90);
          endDate=new Date();
        }
          
        else if (filterCriteria.from == "last6Months")
        {
          startDate=new Date();
          startDate.time=startDate.time - (1000 * 60 * 60 * 24 * 180);
          endDate=new Date();
        }
          
        else if (filterCriteria.from && filterCriteria.to)
        {
          startDate=new Date(filterCriteria.from * 1000)
          endDate=new Date(filterCriteria.to * 1000);
        }
        
        clearMap()
        mapViewer.visible=false
        refresh()
      }
      
      
      
      private function onTrackerReady(e:Event):void
      {
        trace("TRACKER READY")
        tracker.removeEventListener(Timeline.READY, onTrackerReady)
        //clearMap()
        loadingBox.visible=false;
        tracker.visible=true;
        setTimeout(getPositionsDetail, 100, targets)
        //refresh()
      }
      
      private function onAddedToStage():void
      {
        startDate=new Date();
        startDate.time=startDate.time - (1000 * 60 * 60 * 24 * 30);
        endDate=new Date();
        
        filterCriteria={type: [], relevance: [], time: "time", from: "lastMonth", to: 0, programs:[]};
        FlexGlobals.topLevelApplication.addEventListener(FilterEvent.ENTITIES_FILTER_CHANGED, onFilterChange)
        FlexGlobals.topLevelApplication.addEventListener("optionsChange", onOptionsChange);
        FlexGlobals.topLevelApplication.addEventListener(FilterEvent.RESET_FILTER, resetFilter);
      }
      
      
      private function onRefresh(e:RefreshEvent):void
      {
        clearMap()
        refresh();
      }
      
      public function refresh():void
      {
        clearMap()
        tracker.reset()
        loadingBox.visible=true;
        tracker.visible=false;
        mapViewer.visible=false;
        
        trace("GEO MAP >>>>>>>>>>>>>>>> REFRESH")
        trace("TOTAL ENTITIES: " + entities.length)
        
        //get details about entities
        info.selectedItem=null;
        info.selectedItems=null;
        actionbar.selectedObject=null;
        actionbar.selectedObjects=null;
        actionbar.linkEnabled=false;
        
        entitiesToShow=new ArrayCollection()
        
        var entity:Entity;
        var i:int;
        for (i=0; i < entities.length; i++)
        {
          entity=entities.getItemAt(i) as Entity;
          if (entity.type == "position" || entity.type == "target")
            entitiesToShow.addItem(entity);
        }
        
        positions=new ArrayCollection()
        targets=new ArrayCollection()
        
        for (i=0; i < entitiesToShow.length; i++)
        {
          entity=entitiesToShow.getItemAt(i) as Entity;
          if (entity.type == "position")
          {
            positions.addItem(entity)
          }
          else if (entity.type == "target")
          {
            targets.addItem(entity)
          }
        }
        
        drawMap()
        getPositionsSummary(targets)
        
      }
      
      
      
      private function onMapClick():void
      {
    
      }
      
      private function getPositionsSummary(targets:ArrayCollection):void
      {
        var ids:Array=new Array();
        for (var i:int=0; i < targets.length; i++)
        {
          var e:Entity=targets.getItemAt(i) as Entity;
          ids.push(e._id)
        }
        EntityManager.instance.positions(ids, formatDate(startDate), formatDate(endDate), true, onPositionsSummaryResult, onPositionsFault)
      }
      
      private function getPositionsDetail(targets:ArrayCollection):void
      {
        var ids:Array=new Array();
        for (var i:int=0; i < targets.length; i++)
        {
          var e:Entity=targets.getItemAt(i) as Entity;
          ids.push(e._id)
        }
        /*   startDate=fromDf.selectedDate
        endDate=toDf.selectedDate */
        if (filterCriteria.from == "lastMonth")
        {
          startDate=new Date();
          startDate.time=startDate.time - (1000 * 60 * 60 * 24 * 30);
          endDate=new Date();
        }
          
        else if (filterCriteria.from == "last3Months")
        {
          startDate=new Date();
          startDate.time=startDate.time - (1000 * 60 * 60 * 24 * 90);
          endDate=new Date();
        }
          
        else if (filterCriteria.from == "last6Months")
        {
          startDate=new Date();
          startDate.time=startDate.time - (1000 * 60 * 60 * 24 * 180);
          endDate=new Date();
        }
          
        else if (filterCriteria.from && filterCriteria.to)
        {
          startDate=new Date(filterCriteria.from * 1000);
          endDate=new Date(filterCriteria.to * 1000);
        }
        endDate.hours=23
        endDate.minutes=59
        endDate.seconds=59
        EntityManager.instance.positions(ids, formatDate(startDate), formatDate(endDate), false, onPositionsDetailResult, onPositionsFault)
      }
      
      private function onPositionsDetailResult(e:ResultEvent):void
      {
        var pos:ArrayCollection=e.result as ArrayCollection;
        for (var i:int=0; i < pos.length; i++)
        {
          var d:Date=new Date()
          d.time=pos.getItemAt(i).time * 1000;
          trace(d)
        }
        tracker.fillMinutes(pos)
        //tracker.populateMinutes(pos)
        
      }
      
      private function onPositionsSummaryResult(e:ResultEvent):void
      {
        var hours:ArrayCollection=e.result as ArrayCollection;
        
        trace(">>>>>>>>>>>>>>>>>>>>>>>>Position Summary result")
        tracker.addEventListener("ready", onTrackerReady)
        setTimeout(tracker.draw, 200, startDate, endDate)
        setTimeout(tracker.fillHours, 300, hours)
        
        mapViewer.visible=true
        
      }
      
      private function onPositionsFault(e:FaultEvent):void
      {
        trace("positions fault")
      }
      
      //Entities operations
      private function onEntityDeleted():void
      {
        //TODO
      }
      
      private function onEntityCreated():void
      {
        //TODO
      }
      
      private function onEntityUpdated():void
      {
        //TODO
      }
      
      private function onLinkAdded():void
      {
        //TODO
      }
      
      private function onMarkerClick():void
      {
       
      }
      
      public function unselectAll():void
      {
      
      }
      
      private function onMarkerDoubleClick():void
      {
     
      }
      
      private function onDateChange():void
      {
        var i:int;
        
        mapViewer.clearLines();
        lines=new Array()
        links=new Dictionary()
        
        //        trace("Geo Map > Date Change: " + tracker.currentDate)
        //        currentDate=tracker.currentDate;
        if (tracker.selectedDate)
          currentDate=tracker.selectedDate
        
        var marker:Object
        for (var tm:* in targetsMarkers)
        {
          marker=targetsMarkers[tm];
          marker.setVisible(false)
        }
        
        for (var pm:* in placesMarkers)
        {
          marker=placesMarkers[pm] ;
          //if (positionsCh.selected)
          if (options.places)
          {
            marker.setVisible(true)
          }
          else
          {
            marker.setVisible(false)
          }
        }
        
        
        if (tracker.currentFlow)
        {
          for (i=0; i < tracker.currentFlow.positions.length; i++)
          {
            var log:Positions=tracker.currentFlow.positions.getItemAt(i) as Positions;
            var entity:Entity=getTarget(log._id);
            var p:Position=log.position; 
            if (targetsMarkers[entity._id])
            {
              marker=targetsMarkers[entity._id]
            }
            marker.setVisible(true)
            //marker.setLatLng(new LatLng(p.lat, p.lon)) 
              marker.setPosition({lat:p.lat,lng:p.lon})
              marker.setOpacity((log.alpha * ALPHA_RATIO) / 100)
           
            //draw links
            if (entity.links && options.links) //linksCh.selected)
            {
              //draw connections
              for (var l:int=0; l < entity.links.length; l++)
              {
                var link:Link=entity.links.getItemAt(l) as Link;
                var entity2:Entity=EntityManager.instance.getItem(link.le);
                // trace("Link beetween: "+entity.type+ " and "+EntityManager.instance.getEntityById(link.le).type)
                if (entity && entity2)
                {
                  if (entity.type == "target" && entity2.type == "position")
                  {
                    trace("DRAW LINK")
                    drawLink({lat: marker.getPosition().lat(), lng:marker.getPosition().lng()}, {lat: entity2.position.latitude, lng:entity2.position.longitude}, entity, link);
                  }
                }
              }
            }
          }
        }
        
        mapViewer.unselectAll();
        for (i=0; i < lines.length; i++)
        {
          //var polyline:Polyline=lines[i] as Polyline;
         // polyline.foreground.filters=null;
        }
        
        actionbar.selectedObject=null;
        actionbar.selectedObjects=null;
        info.selectedItem=null;
        info.selectedItems=null
        actionbar.linkEnabled=false;
        //if (fitCh.selected)
        if (options.fit)
          
         mapViewer.fitBounds(options.places)
      }
      
      private function drawLink(pos1:Object, pos2:Object, entity:Entity, link:Link):void
      {
        //https://developers.google.com/maps/documentation/flash/overlays
       /*  var polyline:Polyline=new Polyline([pos1, pos2], new PolylineOptions({strokeStyle: new StrokeStyle({color: relevanceColors[link.rel], thickness: 2, alpha: 1})}));
        polyline.foreground.addEventListener(MouseEvent.MOUSE_OVER, function(e:MouseEvent):void
        {
          Mouse.cursor="button"
        })
        polyline.foreground.addEventListener(MouseEvent.MOUSE_OUT, function(e:MouseEvent):void
        {
          Mouse.cursor="auto"
        })
        polyline.foreground.addEventListener(MouseEvent.CLICK, onLinkClick);
        
        
        
        map.addOverlay(polyline);
        overlays.push(polyline);
        lines.push(polyline)
        var str:String="<Edge><data fromID='" + entity._id + "' toID='" + link.le + "' rel='" + link.rel + "' type='" + link.type + "'level='" + link.level + "'></data></Edge>"
        links[polyline.foreground]=str
         */
        
        var line:Object = mapViewer.addLine(pos1, pos2);
      }
      
      
      private function getTarget(id:String):Entity
      {
        if (!targets)
          return null
        for (var i:int=0; i < targets.length; i++)
        {
          var entity:Entity=targets.getItemAt(i) as Entity;
          if (entity._id == id)
            return entity;
        }
        return null;
      }
      
      //utils stuff
      private function formatDate(d:Date):String
      {
        return String(int(d.time / 1000));
      }
      
      private function doubleDigits(n:Number):String
      {
        if (n < 10)
          return "0" + String(n);
        return String(n);
      }
      
      protected function onLinkClick(e:MouseEvent):void
      {
     
      }
      
      public function reset():void
      {
        trace("GEO MAP >>>>>>>>>>>>>>>> RESET")
        //tracker.reset()
        endDate=new Date();
        endDate.hours=0
        endDate.minutes=0
        endDate.seconds=0;
        endDate.milliseconds=0
        
        startDate=new Date();
        startDate.date-=30 //30 days
        startDate.hours=0
        startDate.minutes=0
        startDate.seconds=0;
        startDate.milliseconds=0;
        
        //fromDf.selectedDate=new Date(startDate.time);
        //toDf.selectedDate=new Date(endDate.time);
        clearMap()
      }
      
      public function addListeners():void
      {
        FlexGlobals.topLevelApplication.addEventListener(FilterEvent.ENTITIES_FILTER_CHANGED, onFilterChange)
        FlexGlobals.topLevelApplication.addEventListener(FilterEvent.RESET_FILTER, resetFilter);
      }
      
      public function removeListeners():void
      {
        FlexGlobals.topLevelApplication.removeEventListener(FilterEvent.ENTITIES_FILTER_CHANGED, onFilterChange)
        FlexGlobals.topLevelApplication.removeEventListener(FilterEvent.RESET_FILTER, resetFilter);
      
        FlexGlobals.topLevelApplication.removeEventListener("optionsChange", onOptionsChange);
      }
      protected function onMapSelection():void
      {

        //single selection
        info.selectedItem=mapViewer.selectedPosition
        info.selectedItems=new <Object>[info.selectedItem];
        
        actionbar.selectedObject=mapViewer.selectedPosition
        actionbar.selectedObjects=new <Object>[info.selectedItem];
        actionbar.selectedObjects.push(info.selectedItem)
        actionbar.linkEnabled=false;
      }
      
    ]]>
  </fx:Script>
  
  <s:HGroup width="100%"
            height="100%"
            gap="5">
    
    <s:VGroup width="100%"
              height="100%">
      <s:HGroup verticalAlign="middle"
                horizontalAlign="left"
                width="100%"
                paddingTop="6"
                gap="0">

        
        <renderers:FilterRenderer label="{R.get('OPTIONS')}"
                                  filter="{options}"
                                  property="options"
                                  popupFactory="it.ht.rcs.console.entities.view.filters.OptionsPopup"
                                  width="150"/>
        
        <renderers:FilterRenderer label="{R.get('TIMEFRAME')}"
                                  filter="{filterCriteria}"
                                  property="time"
                                  popupFactory="it.ht.rcs.console.entities.view.filters.DateFilterPopup"
                                  width="150"/>
        
      </s:HGroup>
      <s:Line width="100%">
        <s:stroke>
          <s:SolidColorStroke color="0xCCCCCC"/>
        </s:stroke>
      </s:Line>
      <s:BorderContainer width="100%"
                         height="100%"
                         borderAlpha="1"
                         borderColor="0xCCCCCC"
                         backgroundColor="0xCCCCCC"
                         backgroundAlpha="0.1">
        
        
        
        <maps:MapViewer id="mapViewer"
                             change="onMapSelection()"
                             width="100%"
                             height="100%"/>
      </s:BorderContainer>
      <s:Line width="100%">
        <s:stroke>
          <s:SolidColorStroke color="0xCCCCCC"/>
        </s:stroke>
      </s:Line>
      <s:Group width="100%">
        <s:Rect width="100%"
                height="{6*28}">
          <s:fill>
            <s:BitmapFill source="@Embed('img/backgrounds/geomaptimeline.png')"
                          fillMode="repeat"/>
          </s:fill>
        </s:Rect>
        <timeline:Timeline width="100%"
                           id="tracker"
                           dateChange="onDateChange()"/>

        <s:HGroup verticalAlign="middle"
                  horizontalAlign="center"
                  id="loadingBox"
                  visible="true"
                  width="100%"
                  height="100%">
          <s:SWFLoader source="@Embed('/img/evidence/spinner16.swf')"/>
          <s:Label text="Loading timeline data. Please wait..."
                   fontWeight="bold"/>
        </s:HGroup>
      </s:Group>
    </s:VGroup>
    
    <entities:EntityInfoPanel id="info"/>
  </s:HGroup>
  
</s:VGroup>