import { Component,  Host, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges, forwardRef, Inject, InjectionToken } from '@angular/core';
import { LayerVectorComponent, SourceVectorComponent, MapComponent } from 'ngx-openlayers';
import { ItemService,ItemTypeService,IItem, IItemType } from '@farmmaps/common';

import { Feature } from 'ol';
import { Point,Geometry } from 'ol/geom';
import { MapBrowserEvent } from 'ol';
import { Types } from 'ol/MapBrowserEventType';
import * as style from 'ol/style';
import * as color from 'ol/color';
import * as loadingstrategy from 'ol/loadingstrategy';
import * as condition from 'ol/events/condition';
import * as extent from 'ol/extent';
import {Vector,Cluster,Source} from 'ol/source';
import {Layer} from 'ol/layer';
import {GeoJSON} from 'ol/format';
import {Select} from 'ol/interaction';
import {IStyles} from '../../../models/style.cache';
import {FeatureIconService} from '../../../services/feature-icon.service';
 
@Component({
  selector: 'fm-map-item-source-vector',
  template: `<ng-content></ng-content>`,
  providers: [
    { provide: SourceVectorComponent , useExisting: forwardRef(() => ItemVectorSourceComponent) }
  ]
})
export class ItemVectorSourceComponent extends SourceVectorComponent implements OnInit, OnChanges {
  instance: Vector<Geometry>;
  private _format: GeoJSON;
  private _select: Select;
  private _hoverSelect: Select;
  private _iconScale: number = 0.05;
  @Input() features: Array<Feature<Geometry>>;
  @Input() selectedFeature: Feature<Geometry>;
  @Input() selectedItem: IItem;
  @Input() styles:IStyles;
  @Output() onFeatureSelected: EventEmitter<Feature<Geometry>> = new EventEmitter<Feature<Geometry>>();
  @Output() onFeatureHover: EventEmitter<Feature<Geometry>> = new EventEmitter<Feature<Geometry>>();
  private stylesCache:IStyles = {};

  constructor(@Host() private layer: LayerVectorComponent, private itemService: ItemService, private map: MapComponent, private itemTypeService: ItemTypeService,private featureIconService$:FeatureIconService) {
    super(layer);
    this._format = new GeoJSON();
  }  

  geometry(feature: Feature<Geometry>) {
    let view = this.map.instance.getView();
    let resolution = view.getResolution();
    var geometry = feature.getGeometry();
    let e = geometry.getExtent();
    //var size = Math.max((e[2] - e[0]) / resolution, (e[3] - e[1]) / resolution);
    if (resolution > 12) {
      geometry = new Point(extent.getCenter(e));
    }
    return geometry;
   }

  getSelectedStyle(feature:Feature<Geometry>):style.Style {
    let key = feature.get('itemType')+"_selected";
    let evaluatedStyle: style.Style =undefined;
    var styleEntry = this.stylesCache[key];    
    if(styleEntry) {
      if(typeof styleEntry === 'function')  {
        evaluatedStyle = styleEntry(feature);
      } else {
        evaluatedStyle = styleEntry;
      }
    } else {
      evaluatedStyle = this.stylesCache["selected"] as style.Style;
    }    
    if(evaluatedStyle ) {
      evaluatedStyle .setGeometry((feature:Feature<Geometry>) => this.geometry(feature));
    } 
    return evaluatedStyle as style.Style
  }

  ngOnInit() {
    this.strategy = loadingstrategy.bbox;
    this.format = new GeoJSON();
    this._select = new Select({
      style:null,
      hitTolerance: 10,
      layers: [this.layer.instance as Layer<Source>]
    });
    this._hoverSelect = new Select({
      style: (feature:Feature<Geometry>) => {        
        return this.getSelectedStyle(feature);
      },
      hitTolerance: 10,
      condition: (e: MapBrowserEvent<UIEvent>) => {
        return e.type == 'pointermove';
      },
      layers: [this.layer.instance as Layer<Source>]
    });
    this.map.instance.addInteraction(this._select);
    this.map.instance.addInteraction(this._hoverSelect);      
    this._select.on('select', (e) => {
      if (e.selected.length > 0 && e.selected[0]) {
        this.onFeatureSelected.emit(e.selected[0]);
      } else {
        this.onFeatureSelected.emit(null);
      }
    });
    this._hoverSelect.on('select', (e) => {
      if (e.selected.length > 0 && e.selected[0]) {
        this.onFeatureHover.emit(e.selected[0]);
      } else {
        this.onFeatureHover.emit(null);
      }
    });
    this.instance = new Vector(this);
    this.host.instance.setSource(this.instance);
      
    this.host.instance.setStyle((feature) => {     
      var itemType = feature.get('itemType');
      var key = itemType + (this.selectedItem?"_I":"");
      if (!this.stylesCache[key]) {
        if (this.itemTypeService.itemTypes[itemType]) {
          let itemTypeEntry = this.itemTypeService.itemTypes[itemType];
          let fillColor = color.asArray(itemTypeEntry.iconColor);
          fillColor[3] = 0;
          this.stylesCache[key] = new style.Style({
              image: itemTypeEntry.icon ? new style.Icon({
                  anchor: [0.5, 1],
                  scale: 0.05,
                  src: this.featureIconService$.getIconImageDataUrl(itemTypeEntry.icon)
                }):null,
              stroke: new style.Stroke({
                color: 'red',
                width: 1
              }),
              fill: new style.Fill({
                color: fillColor
              }),
              geometry:(feature:Feature<Geometry>) => this.geometry(feature)
            });                   
        } else {
          key = 'file';
        }
      } 
      let evaluatedStyle =null;
      var styleEntry = this.stylesCache[key];    
      if(typeof styleEntry === 'function')  {
        evaluatedStyle = styleEntry(feature);
      } else {
        evaluatedStyle = styleEntry;
      }
      if(evaluatedStyle && evaluatedStyle.geometry_ == null) {
        evaluatedStyle.setGeometry((feature) => this.geometry(feature));
      } 
      return evaluatedStyle;
    });
  }

  ngOnChanges(changes: SimpleChanges) {
    if (changes["features"] && this.instance) {
      this.instance.clear(true);
      this._select.getFeatures().clear();
      this.instance.addFeatures(changes["features"].currentValue);
    }

    if (changes["selectedFeature"] && this.instance) {
      var features = this._hoverSelect.getFeatures();
      var feature = changes["selectedFeature"].currentValue
      //this.instance.clear(false);
      //this.instance.addFeatures(features.getArray());
      features.clear();
      if (feature) {
        //this.instance.removeFeature(feature);
        features.push(feature)
      }    
    }
    if (changes["selectedItem"] && this.instance) {
      var item = changes["selectedItem"].currentValue
      if (item) {
        this.map.instance.removeInteraction(this._hoverSelect);  
      } else {
        this.map.instance.addInteraction(this._hoverSelect);  
      }
    }
    if (changes["styles"] && this.instance) {
      let styles = changes["styles"].currentValue;
      for (const key in styles) {
        if (styles.hasOwnProperty(key)) {
          this.stylesCache[key]=styles[key]; 
        }
      }
    }
  }
}
