 
 import Foundation
 
-public protocol Array2DProtocol: RangeReplaceableCollection {
+public protocol Array2DProtocol: RangeReplaceableCollection where Index == IndexPath, Element == Array2D<Value, Item>.Element {
     associatedtype Value
     associatedtype Item
     var array2DView: Array2D<Value, Item> { get set }
 }
 
-public struct Array2D<Value, Item>: Array2DProtocol {
-
-    public struct Section: MutableCollection {
+public struct Array2D<Value, Item>: Array2DProtocol, CustomDebugStringConvertible {
+
+    public struct Section: MutableCollection, CustomDebugStringConvertible {
 
         public var value: Value
         public var items: [Item]

            self = newValue
        }
    }
}

extension MutableObservableCollection where UnderlyingCollection: Collection, UnderlyingCollection.Index == Int, UnderlyingCollection.Element: Array2DProtocol {
//
//    public typealias Value = UnderlyingCollection.Element.Value
//    public typealias Item = UnderlyingCollection.Element.Item
//
//    public subscript(itemAt indexPath: IndexPath) -> Item {
//        get {
//            return collection[indexPath.section].array2DSectionView[indexPath.item]
//        }
//        set {
//            descriptiveUpdate { (collection) -> [CollectionOperation<IndexPath>] in
//                collection[itemAt: indexPath] = newValue
//                return [.update(at: indexPath)]
//            }
//        }
//    }

//    public subscript(sectionAt index: Int) -> Section {
//        get {
//            return collection[sectionAt: index]
//        }
//        set {
//            descriptiveUpdate { (collection) -> [CollectionOperation<IndexPath>] in
//                collection[sectionAt: index] = newValue
//                return [.update(at: IndexPath(indexes: [index]))]
//            }
//        }
//    }
}

//extension MutableObservableCollection where UnderlyingCollection: RangeReplacableTreeNode, UnderlyingCollection: Array2DProtocol {
//
//    /// Append new section at the end of the 2D array.
//    public func appendSection(_ section: Section, withItems items: [Item] = []) {
//        append(UnderlyingCollection(section: section, items: items))
//    }
//
//    /// Append `item` to the section `section` of the array.
//    public func appendItem(_ item: Item, toSection section: Int) {
//        batchUpdate(subtreeAt: IndexPath(index: section)) { (subtree) in
//            subtree.append(UnderlyingCollection(item: item))
//        }
//    }
//
//    /// Insert section at `index` with `items`.
//    public func insert(section: Section, withItems items: [Item], at index: Int)  {
//        insert(UnderlyingCollection(section: section, items: items), at: [index])
//    }
//
//    /// Insert `item` at `indexPath`.
//    public func insert(item: Item, at indexPath: IndexPath)  {
//        insert(UnderlyingCollection(item: item), at: indexPath)
//    }
//
//    /// Insert `items` at index path `indexPath`.
//    public func insert(contentsOf items: [Item], at indexPath: IndexPath) {
//        insert(contentsOf: items.map { UnderlyingCollection(item: $0) }, at: indexPath)
//    }
//
//    /// Move the section at index `fromIndex` to index `toIndex`.
//    public func moveSection(from fromIndex: Int, to toIndex: Int) {
//        move(from: [fromIndex], to: [toIndex])
//    }
//
//    /// Move the item at `fromIndexPath` to `toIndexPath`.
//    public func moveItem(from fromIndexPath: IndexPath, to toIndexPath: IndexPath) {
//        move(from: fromIndexPath, to: toIndexPath)
//    }
//
//    /// Remove and return the section at `index`.
//    @discardableResult
//    public func removeSection(at index: Int) -> (section: Section, items: [Item]) {
//        let node = remove(at: [index])
//        return (node.value.array2DElementView.section!, node.children.map { $0.value.array2DElementView.item! })
//    }
//
//    /// Remove and return the item at `indexPath`.
//    @discardableResult
//    public func removeItem(at indexPath: IndexPath) -> Item {
//        let node = remove(at: indexPath)
//        return node.value.array2DElementView.item!
//    }
//
//    /// Remove all items from the array. Keep empty sections.
//    public func removeAllItems() {
//        batchUpdate { (section) in
//            for index in section.collection.indices {
//                section.batchUpdate(subtreeAt: index, { (section) in
//                    section.removeAll()
//                })
//            }
//        }
//    }
//
//    /// Remove all items and sections from the array.
//    public func removeAllItemsAndSections() {
//        removeAll()
//    }
//}

                items[index] = newValue
            }
        }

        public var debugDescription: String {
            return "\(value): \(items.debugDescription)"
        }
    }

    public enum Element {
        case section(Section)
        case item(Item)

        public var section: Section? {
            if case .section(let section) = self {
                return section
            } else {
                return nil
            }
        }

        public var item: Item? {
            if case .item(let item) = self {
                return item
            } else {
                return nil
            }
        }
    }

    public var sections: [Section]
