//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
//  THIS FILE IS GENERATED BY EASY BINDINGS, DO NOT MODIFY IT
//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

import Cocoa

//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
//    Array controller AutoLayoutDeviceDocument symbolDisplayController
//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

final class Controller_AutoLayoutDeviceDocument_symbolDisplayController : ReadOnlyAbstractGenericRelationshipProperty, EBGraphicViewControllerProtocol, HiddenEBProtocol {

  //····················································································································
  // Model
  //····················································································································

  private var mModel : ReadWriteArrayOf_SymbolInstanceInDevice? = nil

  //····················································································································

  var selectedSet : EBReferenceSet <SymbolInstanceInDevice> {
    set (newValue) {
    //--- Add observers to newly selected set
      for object in newValue.subtracting (self.mPrivateSelectedSet).values {
        object.selectionDisplay_property.addEBObserver (self.mObjectSelectionObserver)
      }
    //--- Remove observers to deselected set
      let deselectedSet = self.mPrivateSelectedSet.subtracting (newValue)
      for object in deselectedSet.values {
        object.selectionDisplay_property.removeEBObserver (self.mObjectSelectionObserver)
      }
      if deselectedSet.count > 0 {
        self.mObjectSelectionObserver.postEvent () // Required, as removing observer does not post event
      }
    //---
      self.mPrivateSelectedSet = newValue
    }
    get {
      return self.selectedArray_property.propset
    }
  }

  //····················································································································

  private var mPrivateSelectedSet = EBReferenceSet <SymbolInstanceInDevice> () {
    didSet {
      self.selectedArray_property.postEvent ()
      self.mInternalSelectedArrayProperty.setProp (EBReferenceArray (Array (self.mPrivateSelectedSet.values)))
    }
  }

  //····················································································································
  // Selected Array
  //····················································································································

  private let mInternalSelectedArrayProperty = StandAloneArrayOf_SymbolInstanceInDevice ()

  //····················································································································

  var selectedArrayDidChange_property : EBAbstractProperty { return self.mInternalSelectedArrayProperty } // EBGraphicViewControllerProtocol
  var selectedArray_property : ReadOnlyArrayOf_SymbolInstanceInDevice { return self.mInternalSelectedArrayProperty }

  //····················································································································

  var selectedArray : EBReferenceArray <SymbolInstanceInDevice> { return self.selectedArray_property.propval }

  //····················································································································
  //   Init
  //····················································································································

  override init () {
    super.init ()
  //--- Selection observers
    self.canBringForward_property.mReadModelFunction = { [weak self] in
      if let me = self {
        return .single (me.canBringForward)
      }else{
        return .empty
      }
    }
    self.selectedArray_property.addEBObserver (self.canBringToFront_property)
  //---
    self.canBringToFront_property.mReadModelFunction = { [weak self] in
      if let me = self {
        return .single (me.canBringToFront)
      }else{
        return .empty
      }
    }
    self.selectedArray_property.addEBObserver (self.canBringToFront_property)
  //---
    self.canSendBackward_property.mReadModelFunction = { [weak self] in
      if let me = self {
        return .single (me.canSendBackward)
      }else{
        return .empty
      }
    }
    self.selectedArray_property.addEBObserver (self.canSendBackward_property)
  //---
    self.canSendToBack_property.mReadModelFunction = { [weak self] in
      if let me = self {
        return .single (me.canSendToBack)
      }else{
        return .empty
      }
    }
    self.selectedArray_property.addEBObserver (self.canSendToBack_property)
  //---
    self.canFlipHorizontally_property.mReadModelFunction = { [weak self] in
      if let me = self {
        return .single (me.canFlipHorizontally)
      }else{
        return .empty
      }
    }
    self.selectedArray_property.addEBObserver (self.canFlipHorizontally_property)
  //---
    self.canFlipVertically_property.mReadModelFunction = { [weak self] in
      if let me = self {
        return .single (me.canFlipVertically)
      }else{
        return .empty
      }
    }
    self.selectedArray_property.addEBObserver (self.canFlipVertically_property)
  //---
    self.canRotate90_property.mReadModelFunction = { [weak self] in
      if let me = self {
        return .single (me.canRotate90)
      }else{
        return .empty
      }
    }
    self.selectedArray_property.addEBObserver (self.canRotate90_property)
  }

  //····················································································································

  var objectCount : Int {
    if let n = self.mModel?.propval.count {
      return n
    }else{
      return 0
    }
  }

  //····················································································································

  final func bind_model (_ inModel : ReadWriteArrayOf_SymbolInstanceInDevice, _ inUndoManager : EBUndoManager?) {
    self.mModel = inModel
    self.mUndoManager = inUndoManager
    inModel.attachClient (self)
    self.startObservingObjectShape ()
    self.startObservingSelectionShape ()
    self.inspectorViewManagerStartsObservingSelection ()
  }

  //····················································································································

  final func unbind_model () {
    self.stopObservingObjectShape ()
    self.stopObservingSelectionShape ()
    self.inspectorViewManagerStopsObservingSelection ()
    self.mModel?.detachClient (self)
    self.selectedSet = EBReferenceSet ()
    self.mModel = nil
    self.mUndoManager = nil
 }

  //····················································································································

  override func notifyModelDidChange () {
    super.notifyModelDidChange ()
    let currentSelectedSet = self.selectedSet
    let objectArray = self.objectArray
    let newSelectedSet = currentSelectedSet.intersection (objectArray.values)
    self.mInternalSelectedArrayProperty.setProp (EBReferenceArray (Array (newSelectedSet.values)))
  }

   //····················································································································

   var objectArray : EBReferenceArray <SymbolInstanceInDevice> {
     if let values = self.mModel?.propval {
       return values
     }else{
       return EBReferenceArray ()
     }
   }

  //····················································································································
  //    Undo manager
  //····················································································································

  private var mUndoManager : EBUndoManager? = nil
  var ebUndoManager : EBUndoManager? { return self.mUndoManager }

  //····················································································································
  //   SELECTION
  // MARK: -
  //····················································································································

  var selectedIndexesSet : Set <Int> {
    var result = Set <Int> ()
    var idx = 0
    for object in self.objectArray.values {
      if self.selectedArray_property.propset.contains (object) {
        result.insert (idx)
      }
      idx += 1
    }
    return result
  }

  //····················································································································

  func setSelection (_ inObjects : [SymbolInstanceInDevice]) {
    self.selectedSet = EBReferenceSet (inObjects)
  }

  //····················································································································
  //  Graphic view interface
  //····················································································································

  var selectedGraphicObjectSet : EBReferenceSet <EBGraphicManagedObject> {
  //  return self.selectedArray_property.propset // Faudrait faire mieux !
    var result = EBReferenceSet <EBGraphicManagedObject> (minimumCapacity: self.selectedArray_property.propval.count)
    for object in self.selectedArray_property.propval.values {
      result.insert (object)
    }
    return result
  }

   //····················································································································

   var graphicObjectArray : [EBGraphicManagedObject] {
     if let v = self.mModel?.propval {
       return v.values
     }else{
       return []
     }
   }

  //····················································································································
  // MARK: -
  // Compute selection shape
  //····················································································································

  private var mObjectSelectionObserver = EBOutletEvent ()

  //····················································································································

  private func startObservingSelectionShape () {
    self.mModel?.addEBObserverOf_selectionDisplay (self.mObjectSelectionObserver)
    self.mObjectSelectionObserver.mEventCallBack = { self.computeSelectionShape () }
  }

  //····················································································································

  func computeSelectionShape () {
    var selectionDisplayArray = [EBShape] ()
    for object in self.objectArray.values {
      if !self.selectedArray_property.propset.contains (object) {
        selectionDisplayArray.append (EBShape ())
      }else if let shape = object.selectionDisplay {
        selectionDisplayArray.append (shape)
      }else{
        selectionDisplayArray.append (EBShape ())
      }
    }
    for view in self.mEBGraphicViews {
      view.updateSelectionShape (selectionDisplayArray)
    }
  }

  //····················································································································

  private func stopObservingSelectionShape () {
    self.mModel?.removeEBObserverOf_selectionDisplay (self.mObjectSelectionObserver)
    self.mObjectSelectionObserver.mEventCallBack = nil
  }

  //····················································································································
  // MARK: -
  // Compute object shape
  //····················································································································

  private var mObjectDisplayObserver = EBOutletEvent ()

  //····················································································································

  private func startObservingObjectShape () {
    self.mModel?.addEBObserverOf_objectDisplay (self.mObjectDisplayObserver)
    self.mObjectDisplayObserver.mEventCallBack = { [weak self] in self?.updateObjectDisplay () }
  }

  //····················································································································

  private func stopObservingObjectShape () {
    self.mModel?.removeEBObserverOf_objectDisplay (self.mObjectDisplayObserver)
    self.mObjectDisplayObserver.mEventCallBack = nil
  }

  //····················································································································

  func updateObjectDisplay () {
    var displayArray = [EBShape] ()
    for object in self.objectArray.values {
      if let shape = object.objectDisplay {
        displayArray.append (shape)
      }else{
        displayArray.append (EBShape ())
      }
    }
    for view in self.mEBGraphicViews {
      view.updateObjectDisplay (displayArray)
    }
  }

  //····················································································································
  // MARK: -
  //····················································································································

  func alignmentPointSetArray () -> [Set<CanariPoint>] {
    var result = [Set<CanariPoint>] ()
    for object in self.objectArray.values {
      result.append (object.alignmentPoints ())
    }
    return result
  }

  //····················································································································
  // MARK: -
  // EBGraphicViews
  //····················································································································

  private var mEBGraphicViews = Set <EBGraphicView> ()
  private var mPasteboardTypes = Set <NSPasteboard.PasteboardType> ()

  //····················································································································

  func addPasteBoardType (_ inType : NSPasteboard.PasteboardType) {
    if !self.mPasteboardTypes.contains (inType) {
      self.mPasteboardTypes.insert (inType)
      for ebView in self.mEBGraphicViews {
        ebView.ebRegister (draggedTypes: [inType])
      }
    }
  }

  //····················································································································

  func boundViews () -> [EBGraphicView] {
    return Array (self.mEBGraphicViews)
  }

  //····················································································································

  final func setBackgroundImageAffineTransform (_ inAffineTransform : NSAffineTransform) {
     for ebView in self.mEBGraphicViews {
       ebView.mBackgroundImageAffineTransform = inAffineTransform
     }
  }

  //····················································································································

  final func setForegroundImageAffineTransform (_ inAffineTransform : NSAffineTransform) {
     for ebView in self.mEBGraphicViews {
       ebView.mForegroundImageAffineTransform = inAffineTransform
     }
  }

  //····················································································································

  final func bind_ebView (_ inEBView : EBGraphicView?) {
    if let ebView = inEBView {
      ebView.ebRegister (draggedTypes: Array (self.mPasteboardTypes))
      self.mEBGraphicViews.insert (ebView)
      ebView.set (controller: self)
    }
  }

  //····················································································································

  final func bind_ebView (_ inView : EBEnclosingGraphicView?) {
    if let ebView = inView?.mGraphicView {
      self.mEBGraphicViews.insert (ebView)
      ebView.set (controller: self)
    }
  }

  //····················································································································

  final func unbind_ebView (_ inEBView : EBGraphicView?) {
    if let ebView = inEBView {
      ebView.updateObjectDisplay ([])
      ebView.updateSelectionShape ([])
      self.mEBGraphicViews.remove (ebView)
    }
  }
  //····················································································································

  final func unbind_ebView (_ inView : EBEnclosingGraphicView?) {
    if let ebView = inView?.mGraphicView {
      ebView.updateObjectDisplay ([])
      ebView.updateSelectionShape ([])
      self.mEBGraphicViews.remove (ebView)
    }
  }


  //····················································································································
  //    Explorer
  //····················································································································

  final func addExplorer (name : String, y : inout CGFloat, view : NSView) {
  }

  //····················································································································

  func selectedObjectIndexSet () -> NSIndexSet {
    let modelObjects = self.objectArray
    let selectedObjects = self.selectedArray_property.propset
    let indexSet = NSMutableIndexSet ()
    for object in selectedObjects.values {
      if let index = modelObjects.firstIndex (of: object) {
        indexSet.add (index)
      }
    }
    return indexSet
  }

  //····················································································································
  //    select
  //····················································································································

  func select (object inObject : SymbolInstanceInDevice) {
    if let model = self.mModel {
      switch model.selection {
      case .empty, .multiple :
        break
      case .single (let objectArray) :
       let array = EBReferenceArray (objectArray)
       if array.contains (inObject) {
           self.selectedSet = EBReferenceSet (inObject)
        }
      }
    }
  }

  //····················································································································
  //    add
  //····················································································································

   @objc func add (_ sender : Any) {
    if let model = self.mModel {
      switch model.selection {
      case .empty, .multiple :
        break
      case .single (let v) :
        let newObject = SymbolInstanceInDevice (self.ebUndoManager)
        var array = EBReferenceArray (v)
        array.append (newObject)
      //--- New object is the selection
        self.selectedSet = EBReferenceSet ([newObject])
        model.setProp (array)
      }
    }
  }

  //····················································································································
  //    remove
  //····················································································································

  @objc func remove (_ sender : Any) {
    if let model = self.mModel {
      switch model.selection {
      case .empty, .multiple :
        break
      case .single (let model_prop) :
      //------------- Find the object to be selected after selected object removing
      //--- Dictionary of object sorted indexes
        var sortedObjectDictionary = EBReferenceDictionary <SymbolInstanceInDevice, Int> ()
        for (index, object) in model_prop.enumerated () {
          sortedObjectDictionary [object] = index
        }
        var indexArrayOfSelectedObjects = [Int] ()
        for object in self.selectedArray_property.propset.values {
          let index = sortedObjectDictionary [object]
          if let idx = index {
            indexArrayOfSelectedObjects.append (idx)
          }
        }
      //--- Sort
        indexArrayOfSelectedObjects.sort { $0 < $1 }
      //--- Find the first index of a non selected object
        var newSelectionIndex = indexArrayOfSelectedObjects [0] + 1
        for index in indexArrayOfSelectedObjects {
          if newSelectionIndex < index {
            break
          }else{
            newSelectionIndex = index + 1
          }
        }
        var newSelectedObject : SymbolInstanceInDevice? = nil
        if (newSelectionIndex >= 0) && (newSelectionIndex < model_prop.count) {
          newSelectedObject = model_prop [newSelectionIndex]
        }
      //----------------------------------------- Remove selected object
      //--- Dictionary of object absolute indexes
        var objectDictionary = EBReferenceDictionary <SymbolInstanceInDevice, Int> ()
        for (index, object) in model_prop.enumerated () {
          objectDictionary [object] = index
        }
      //--- Build selected objects index array
        var selectedObjectIndexArray = [Int] ()
        for object in self.selectedArray_property.propset.values {
          let index = objectDictionary [object]
          if let idx = index {
            selectedObjectIndexArray.append (idx)
          }
        }
      //--- Sort in reverse order
        selectedObjectIndexArray.sort { $1 < $0 }
      //--- Remove objects, in reverse of order of their index
        var newObjectArray = EBReferenceArray (model_prop)
        for index in selectedObjectIndexArray {
          newObjectArray.remove (at: index)
        }
      //----------------------------------------- Set new selection
        var newSelectionSet = EBReferenceSet <SymbolInstanceInDevice> ()
        if let object = newSelectedObject {
          newSelectionSet.insert (object)
        }
        self.selectedSet = newSelectionSet
      //----------------------------------------- Set new object array
        model.setProp (newObjectArray)
      }
    }
  }

  //····················································································································
  //  SELECTION OPERATIONS
  //····················································································································

  private func sortedIndexArrayOfSelectedObjects () -> [Int] {
    var result = [Int] ()
    let objects = self.objectArray
    for object in self.selectedArray_property.propset.values {
      let idx = objects.firstIndex (of: object)!
      result.append (idx)
    }
    return result.sorted ()
  }

  //····················································································································
  // MARK: -
  //····················································································································

  func canCut (_ inPasteboardType : NSPasteboard.PasteboardType?) -> Bool {
    if (inPasteboardType == nil) || (self.selectedArray_property.propset.count == 0) {
      return false
    }else{
      for object in self.selectedArray_property.propset.values {
        if !object.canCopyAndPaste () || !object.canBeDeleted () {
          return false
        }
      }
      return true
    }
  }

  //····················································································································
  // MARK: -
  //····················································································································

  func cutSelectedObjectsIntoPasteboard (_ inPasteboardType : NSPasteboard.PasteboardType?, pasteOffset : CanariPoint) {
    self.copySelectedObjectsIntoPasteboard (inPasteboardType, pasteOffset: pasteOffset)
    self.deleteSelectedObjects ()
  }

  //····················································································································

  func canCopy (_ inPasteboardType : NSPasteboard.PasteboardType?) -> Bool {
    return self.canCut (inPasteboardType)
  }

  //····················································································································
  // MARK: -
  //····················································································································

  func copySelectedObjectsIntoPasteboard (_ inPasteboardType : NSPasteboard.PasteboardType?,
                                          pasteOffset : CanariPoint) {
    if let pasteboardType = inPasteboardType {
    //--- Declare pasteboard types
      let pb = NSPasteboard.general
      pb.declareTypes ([pasteboardType, .pdf], owner: self)
    //--- Build PDF representation
      let indexArray = self.sortedIndexArrayOfSelectedObjects ()
      let objects = self.objectArray
      var shape = EBShape ()
      for idx in indexArray {
        let object = objects [idx]
        if let s = object.objectDisplay {
          shape.add (s)
        }
      }
      let pdfData = buildPDFimageData (frame: shape.boundingBox, shape: shape)
      pb.setData (pdfData, forType: .pdf)
   //--- Build private representation
      var objectDictionaryArray = [NSDictionary] ()
      var objectAdditionalDictionaryArray = [NSDictionary] ()
      for idx in indexArray {
        let object = objects [idx]
        let dict = NSMutableDictionary ()
        object.saveIntoDictionary (dict)
        objectDictionaryArray.append (dict)
        let additionalDict = NSMutableDictionary ()
        object.saveIntoAdditionalDictionary (additionalDict)
        objectAdditionalDictionaryArray.append (additionalDict)
      }
    //--- Copy private representation(s)
      let dataDictionary : NSDictionary = [
        OBJECT_DICTIONARY_KEY : objectDictionaryArray,
        OBJECT_ADDITIONAL_DICTIONARY_KEY : objectAdditionalDictionaryArray,
        X_KEY : pasteOffset.x,
        Y_KEY : pasteOffset.y
      ]
      pb.setPropertyList (dataDictionary, forType: pasteboardType)
    }
  }

  //····················································································································
  // MARK: -
  //····················································································································

  func canPaste (_ inPasteboardType : NSPasteboard.PasteboardType?) -> Bool {
    if let pasteboardType = inPasteboardType {
      let pb = NSPasteboard.general
      return pb.availableType (from: [pasteboardType]) != nil
    }else{
      return false
    }
  }

  //····················································································································

   func pasteFromPasteboard (_ inPasteboardType : NSPasteboard.PasteboardType?, _ inWindow : NSWindow) {
    let pb = NSPasteboard.general
    if let pasteboardType = inPasteboardType,
       pb.availableType (from: [pasteboardType]) != nil,
       let dataDictionary = pb.propertyList (forType: pasteboardType) as? NSDictionary,
       let dictionaryArray = dataDictionary [OBJECT_DICTIONARY_KEY] as? [NSDictionary],
       let additionalDictionaryArray = dataDictionary [OBJECT_ADDITIONAL_DICTIONARY_KEY] as? [NSDictionary],
       let X = dataDictionary [X_KEY] as? Int,
       let Y = dataDictionary [Y_KEY] as? Int {
      var newObjects = [SymbolInstanceInDevice] ()
      var userSet = EBReferenceSet <AnyObject> ()
      var idx = 0
      var errorMessage = ""
      for dictionary in dictionaryArray {
        if let object = makeManagedObjectFromDictionary (self.ebUndoManager, dictionary) as? SymbolInstanceInDevice {
          if errorMessage == "" {
            errorMessage = object.operationAfterPasting (additionalDictionary: additionalDictionaryArray [idx], objectArray: self.objectArray.values)
          }
          idx += 1
          if errorMessage == "" {
            object.translate (xBy: X, yBy: Y, userSet: &userSet)
            newObjects.append (object)
          }
        }
      }
      if errorMessage == "" {
        var objects = self.objectArray
        objects.append (objects: newObjects)
        self.mModel?.setProp (objects)
        self.selectedSet = EBReferenceSet (newObjects)
      }else{
         let alert = NSAlert ()
         alert.messageText = errorMessage
         alert.addButton (withTitle: "Ok")
         alert.beginSheetModal (for: inWindow) { (inReturnCode : NSApplication.ModalResponse) in }
      }
    }
  }

  //····················································································································
  // MARK: -
  //····················································································································

  func canDelete () -> Bool {
    if self.selectedArray_property.propset.count == 0 {
      return false
    }else{
      for object in self.selectedArray_property.propset.values {
        if !object.canBeDeleted () {
          return false
        }
      }
      return true
    }
  }

  //····················································································································

  var mAfterObjectRemovingCallback : Optional < () -> Void > = nil

  //····················································································································

  func deleteSelectedObjects () {
    if self.canDelete (), let model = self.mModel {
    //--- Remove selected objects
      let objectsToRemove = self.selectedArray_property.propset
      for object in objectsToRemove.values {
        object.operationBeforeRemoving ()
        var objects = model.propval
        if let idx = objects.firstIndex (of: object) {
          objects.remove (at: idx)
          model.setProp (objects)
        }
      }
    //---
      self.mAfterObjectRemovingCallback? ()
    }
  }

  //····················································································································
  // MARK: -
  //····················································································································

  func selectAllObjects () {
    self.selectedSet = EBReferenceSet (self.objectArray.values)
  }

  //····················································································································
  // BRING FORWARD
  // MARK: -
  //····················································································································

  var canBringForward_property = EBTransientProperty_Bool ()

  //····················································································································

  var canBringForward : Bool {
    let objects = self.objectArray
    var result = (objects.count > 1) && (self.selectedArray_property.propset.count > 0)
    if result {
      let sortedIndexArray = self.sortedIndexArrayOfSelectedObjects ()
      result = sortedIndexArray.last! < (objects.count - 1)
    }
    return result
  }

  //····················································································································

  func bringForward () {
    var objects = self.objectArray
    let sortedIndexArray = self.sortedIndexArrayOfSelectedObjects ()
    for idx in sortedIndexArray.reversed () {
       let object = objects [idx]
       objects.remove (at: idx)
       objects.insert (object, at: idx+1)
    }
    self.mModel?.setProp (objects)
  }

  //····················································································································
  // BRING TO FRONT
  // MARK: -
  //····················································································································

  var canBringToFront_property = EBTransientProperty_Bool ()

  //····················································································································

  var canBringToFront : Bool {
    let objects = self.objectArray
    if (objects.count > 1) && (self.selectedArray_property.propset.count > 0) {
      let sortedIndexArray = self.sortedIndexArrayOfSelectedObjects ()
      var top = objects.count - 1
      for idx in sortedIndexArray.reversed () {
        if idx < top {
          return true
        }
        top -= 1
      }
    }
    return false
  }

  //····················································································································

  func bringToFront () {
    var objects = self.objectArray
    let sortedIndexArray = self.sortedIndexArrayOfSelectedObjects ()
    for idx in sortedIndexArray {
      let object = objects [idx]
      objects.remove (at: idx)
      objects.append (object)
    }
    self.mModel?.setProp (objects)
  }

  //····················································································································
  // SEND BACKWARD
   // MARK: -
 //····················································································································

  var canSendBackward_property = EBTransientProperty_Bool ()

  //····················································································································

  var canSendBackward : Bool {
    let objects = self.objectArray
    var result = (objects.count > 1) && (self.selectedArray_property.propset.count > 0)
    if result {
      let sortedIndexArray = self.sortedIndexArrayOfSelectedObjects ()
      result = sortedIndexArray [0] > 0
    }
    return result
  }

  //····················································································································

  func sendBackward () {
    var objects = self.objectArray
    let sortedIndexArray = self.sortedIndexArrayOfSelectedObjects ()
    for idx in sortedIndexArray.reversed () {
      let object = objects [idx]
      objects.remove (at: idx)
      objects.insert (object, at: idx-1)
    }
    self.mModel?.setProp (objects)
  }

  //····················································································································
  // SEND TO BACK
  // MARK: -
  //····················································································································

  var canSendToBack_property = EBTransientProperty_Bool ()

  //····················································································································

  func sendToBack () {
    var objects = self.objectArray
    let sortedIndexArray = self.sortedIndexArrayOfSelectedObjects ()
    var newObjectArray = EBReferenceArray <SymbolInstanceInDevice> ()
    for idx in sortedIndexArray.reversed () {
      let object = objects [idx]
      objects.remove (at: idx)
      newObjectArray.append (object)
    }
    newObjectArray.reverse ()
    newObjectArray.append (objects: objects)
    self.mModel?.setProp (newObjectArray)
  }

  //····················································································································

  var canSendToBack : Bool {
    let objects = self.objectArray
    if (objects.count > 1) && (self.selectedArray_property.propset.count > 0) {
      let sortedIndexArray = self.sortedIndexArrayOfSelectedObjects ()
      var bottom = 0
      for idx in sortedIndexArray {
        if idx > bottom {
          return true
        }
        bottom += 1
      }
    }
    return false
  }

  //····················································································································
  // SNAP TO GRID
  // MARK: -
  //····················································································································

  func snapToGrid (_ inGrid : Int) {
    for object in self.selectedArray_property.propset.values {
      object.snapToGrid (inGrid)
    }
  }

  //····················································································································

  func canSnapToGrid (_ inGrid : Int) -> Bool {
    for object in self.selectedArray_property.propset.values {
      if object.canSnapToGrid (inGrid) {
        return true
      }
    }
    return false
  }


 //····················································································································
  // HORIZONTAL FLIP
  // MARK: -
  //····················································································································

  var canFlipHorizontally_property = EBTransientProperty_Bool ()

  //····················································································································

  func flipHorizontally () {
    for object in self.selectedArray_property.propset.values {
      object.flipHorizontally ()
    }
  }

  //····················································································································

  var canFlipHorizontally : Bool {
    for object in self.selectedArray_property.propset.values {
      if !object.canFlipHorizontally () {
        return false
      }
    }
    return self.selectedArray_property.propset.count > 0
  }

  //····················································································································
  // VERTICAL FLIP
  // MARK: -
  //····················································································································

  var canFlipVertically_property = EBTransientProperty_Bool ()

  //····················································································································

  func flipVertically () {
    for object in self.selectedArray_property.propset.values {
      object.flipVertically ()
    }
  }

  //····················································································································

  var canFlipVertically : Bool {
    for object in self.selectedArray_property.propset.values {
      if !object.canFlipVertically () {
        return false
      }
    }
    return self.selectedArray_property.propset.count > 0
  }

  //····················································································································
  // ROTATE 90
  // MARK: -
  //····················································································································

  var canRotate90_property = EBTransientProperty_Bool ()
  private var mRotate90PointSet = Set <CanariPoint> ()

 //····················································································································

  var canRotate90 : Bool {
    self.mRotate90PointSet.removeAll ()
    if self.selectedArray.count == 0 {
      return false
    }else{
      for object in self.selectedArray.values {
        if !object.canRotate90 (accumulatedPoints: &self.mRotate90PointSet) {
          return false
        }
      }
      return !self.mRotate90PointSet.isEmpty
    }
  }

  //····················································································································

  func rotate90Clockwise () {
    let r = CanariRect (points: Array (self.mRotate90PointSet))
    var userSet = EBReferenceSet <AnyObject> ()
    for object in self.selectedArray.values {
      object.rotate90Clockwise (from: r.center, userSet: &userSet)
    }
  }

  //····················································································································

  func rotate90CounterClockwise () {
    let r = CanariRect (points: Array (self.mRotate90PointSet))
    var userSet = EBReferenceSet <AnyObject> ()
    for object in self.selectedArray.values {
      object.rotate90CounterClockwise (from: r.center, userSet: &userSet)
    }
  }

  //····················································································································
  // MARK: -
  //····················································································································

  func addToSelection (objects inObjects : [SymbolInstanceInDevice]) {
    if let objectSet = self.mModel?.propset {
      var newSelectedSet = self.selectedArray_property.propset
      for object in inObjects {
        if objectSet.contains (object) {
          newSelectedSet.insert (object)
        }
      }
      self.selectedSet = newSelectedSet
    }
  }

  //····················································································································

  func addToSelection (objectsWithIndex inIndexes : [Int]) {
    let objects = self.objectArray
    var newSelectedSet = self.selectedArray_property.propset
    for idx in inIndexes {
      let newSelectedObject = objects [idx]
      newSelectedSet.insert (newSelectedObject)
    }
    self.selectedSet = newSelectedSet
  }

  //····················································································································

  func removeFromSelection (objectWithIndex inIndex : Int) {
    let objects = self.objectArray
    let object = objects [inIndex]
    var newSelectedSet = self.selectedArray_property.propset
    newSelectedSet.remove (object)
    self.selectedSet = newSelectedSet
  }

  //····················································································································

  func clearSelection () {
    self.selectedSet = EBReferenceSet ()
  }

  //····················································································································

  func setSelection (objectsWithIndexes inIndexes : [Int]) {
    let objects = self.objectArray
    var selectedObjects = [SymbolInstanceInDevice] ()
    for index in inIndexes {
      let newSelectedObject = objects [index]
      selectedObjects.append (newSelectedObject)
    }
    self.selectedSet = EBReferenceSet (selectedObjects)
  }

  //····················································································································
  // MARK: -
  //  INSPECTOR
  //····················································································································

  private var mInspectorReceivingView : NSView? = nil
  private var mCurrentAttachedView : NSView? = nil
  private var mInspectorDictionary = [ObjectIdentifier : NSView] ()
  private var mInspectorObserver = EBOutletEvent ()

  //····················································································································

  func register (inspectorReceivingView : NSView?) {
    self.mInspectorReceivingView = inspectorReceivingView
    self.updateInspectorViews ()
  }

  //····················································································································

  func register (inspectorView : NSView?, for inEntity : EBGraphicManagedObject.Type) {
    self.mInspectorDictionary [ObjectIdentifier (inEntity)] = inspectorView
    self.updateInspectorViews ()
  }

  //····················································································································

  private func inspectorViewManagerStartsObservingSelection () {
    self.selectedArray_property.addEBObserver (self.mInspectorObserver)
    self.mInspectorObserver.mEventCallBack = { [weak self] in self?.updateInspectorViews () }
  }

  //····················································································································

  private func inspectorViewManagerStopsObservingSelection () {
    self.mInspectorObserver.mEventCallBack = nil
    self.selectedArray_property.removeEBObserver (self.mInspectorObserver)
  }

  //····················································································································

  private func updateInspectorViews () {
    if let inspectorView = self.mInspectorReceivingView {
    //--- Remove current attached view
      self.mCurrentAttachedView?.removeFromSuperview ()
    //--- Add the new attached view
      if self.mViewIsHidden {
        self.mCurrentAttachedView = nil
      }else if self.selectedArray.count == 0 {
        let tf = self.textField ("Empty Selection", inspectorView.frame)
        inspectorView.addSubview (tf)
        self.mCurrentAttachedView = tf
      }else{
        var selectionTypes = Set <ObjectIdentifier> ()
        for object in self.selectedArray.values {
          let T = ObjectIdentifier (type (of: object))
          selectionTypes.insert (T)
        }
        if selectionTypes.count > 1 {
          let tf = self.textField ("Multiple Selection", inspectorView.frame)
          inspectorView.addSubview (tf)
          self.mCurrentAttachedView = tf
        }else if let selectionInspectorView = self.mInspectorDictionary [selectionTypes.first!] {
          selectionInspectorView.autoresizingMask = [.width, .minYMargin]
          selectionInspectorView.frame = inspectorView.frame
          inspectorView.addSubview (selectionInspectorView)
          self.mCurrentAttachedView = selectionInspectorView
        }else{
          let tf = self.textField ("No Inspector for this Selection", inspectorView.frame)
          inspectorView.addSubview (tf)
          self.mCurrentAttachedView = tf
        }
      }
    }
  }

  //····················································································································

  private func textField (_ inString : String, _ inspectorFrame : NSRect) -> NSTextField {
    let textHeight : CGFloat = 30.0
    let r = NSRect (
      x: 0.0,
      y: inspectorFrame.origin.y + (inspectorFrame.size.height - textHeight) / 2.0,
      width: inspectorFrame.size.width,
      height: textHeight
    )
    let tf = NSTextField (frame: r)
    tf.alignment = .center
    tf.isBezeled = false
    tf.isBordered = false
    tf.drawsBackground = false
    tf.isEnabled = true
    tf.isEditable = false
    tf.autoresizingMask = [.width, .minYMargin, .maxYMargin]
    tf.stringValue = inString
    tf.font = NSFont.boldSystemFont (ofSize: NSFont.systemFontSize * 1.25)
    tf.textColor = NSColor.lightGray
    return tf
  }

  //····················································································································

  private var mViewIsHidden = false {
    didSet { self.updateInspectorViews () }
  }

  //····················································································································

  var isHidden : Bool {
    get { return self.mViewIsHidden }
    set { self.mViewIsHidden = newValue }
  }

  //····················································································································

}

//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

