import UIKit
import ArcGIS

class ViewController: UIViewController, AGSGeoViewTouchDelegate {

    @IBOutlet var mapView: AGSMapView!
    var map:AGSMap!
    private var mapImageLayer:AGSArcGISMapImageLayer!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        //create an instance of a map
        self.map = AGSMap(basemap: .topographic())
        
        //map image layer
        self.mapImageLayer = AGSArcGISMapImageLayer(url: URL(string: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/SampleWorldCities/MapServer")!)
        
        //hide Continent and World layers
        self.mapImageLayer.load { [weak self] (error: Error?) in
            if error == nil {
                self?.mapImageLayer.subLayerContents[1].isVisible = false
                self?.mapImageLayer.subLayerContents[2].isVisible = false
            }
        }
        self.map.operationalLayers.add(self.mapImageLayer)
        
        //set initial viewpoint to a specific region
        self.map.initialViewpoint = AGSViewpoint(center: AGSPoint(x: -10977012.785807, y: 4514257.550369, spatialReference: AGSSpatialReference(wkid: 3857)), scale: 68015210)
        
        //assign map to the map view
        self.mapView.map = self.map
        
        //add self as the touch delegate for the map view
        self.mapView.touchDelegate = self
    }
    
    //MARK: - AGSGeoViewTouchDelegate
    
    func geoView(_ geoView: AGSGeoView, didTapAtScreenPoint screenPoint: CGPoint, mapPoint: AGSPoint) {
        //get the geoElements for all layers present at the tapped point
        self.identifyLayers(screenPoint)
    }
    
    //MARK: - Identify layers
    
    private func identifyLayers(_ screen: CGPoint) {
        
        //self.mapView.identifyLayer(self.mapImageLayer, screenPoint: screen, tolerance: 12, returnPopupsOnly: false) { (identifyLayerResult: AGSIdentifyLayerResult) in
        self.mapView.identifyLayer(self.mapImageLayer, screenPoint: screen, tolerance: 12, returnPopupsOnly: false, maximumResults: 10) { (identifyLayerResult: AGSIdentifyLayerResult) in
            var messageString = ""
            var totalCount = 0
            let count = self.geoElementsCountFromResult(identifyLayerResult)
            let layerName = identifyLayerResult.layerContent.name
            messageString.append("\(layerName) :: \(count)")
            
            //update total count
            totalCount += count
        
        //if any elements were found show the results
        //else notify user that no elements were found
        if totalCount > 0 {
            self.presentAlert(title: "Number of elements found", message: messageString)
        }
        else {
            self.presentAlert(message: "No element found")
        }
        }
    }
    
    //MARK: - Helper methods
    
    private func geoElementsCountFromResult(_ result: AGSIdentifyLayerResult) -> Int {
        //create temp array
        var tempResults = [result]
        
        //using Depth First Search approach to handle recursion
        var count = 0
        var index = 0
        
        while index < tempResults.count {
            //get the result object from the array
            let identifyResult = tempResults[index]
            
            //update count with geoElements from the result
            count += identifyResult.geoElements.count
            // get the name of the geoElements, in this case the city
            //
            for feature in identifyResult.geoElements as! [AGSArcGISFeature] {
                let cityName = feature.attributes["CITY_NAME"] as! String
                print("City Name Identified: \(cityName)")
            }
            
            //check if the result has any sublayer results
            //if yes then add those result objects in the tempResults
            //array after the current result
            if identifyResult.sublayerResults.count > 0 {
                tempResults.insert(contentsOf: identifyResult.sublayerResults, at: index + 1)
            }
            
            //update the count and repeat
            index += 1
        }
        
        return count
    }
    
    /// Shows an alert with the given title, message, and an OK button.
    func presentAlert(title: String? = nil, message: String) {
        let okAction = UIAlertAction(title: "OK", style: .default)
        let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
        alertController.addAction(okAction)
        present(alertController, animated: true)
    }
    
    /// Show an alert with the title "Error", the error's `localizedDescription`
    /// as the message, and an OK button.
    func presentAlert(error: Error) {
        presentAlert(title: "Error", message: error.localizedDescription)
    }
}