# Sparse Array Example Using Special Methods
# Python 3 Reflexive Metaprogramming
# H. Conrad Cunningham

# Developed for CSci 658, Software Language Engineering, Spring 2018

#234567890123456789012345678901234567890123456789012345678901234567890

# 2018-03-18: (V1)
# 2018-03-23: (V1a) Added has_index method
# 2018-04-12: (V1b) Added type print statement

class SparseArray:

    def __init__(self, assoc=None):
        self._arr = {}
        if assoc is not None:
            self.from_assoc(assoc)

    def from_assoc(self,assoc): # sequence of (int,value) pairs
        for p in assoc:
            if len(p) == 2:
                (i,v) = p
                if type(i) is int:
                    self._arr[i] = v
                else:
                    print(
                        f'Index not int in assoc list: {str(i)}')
            else:
                print(f'Invalid pair in assoc list: {str(p)}')

    def has_index(self, index):
        if type(index) is int:
            return index in self._arr
        else:
            print(f'Warning: Index not int: {index}') 
            return False

    def __getitem__(self, index):        # arr[index]
        if type(index) is int:
            return self._arr[index]
        else:
            print(f'Index not int: {index}') 

    def __setitem__(self, index, value): # arr[index] =
        if type(index) is int:
            self._arr[index] = value
        else:
            print(f'Index not int: {index}')

    def __delitem__(self, index):        # del arr[index]
        if type(index) is int:
            del self._arr[index]
        else:
            print(f'Index not int: {index}')

    def __contains__(self, item):        # item (is value) in arr
        return item in self._arr.values()

    def to_assoc(self):
        return sorted(self._arr.items())
    
    def __str__(self):
        return str(self.to_assoc())
    
if __name__ == '__main__':
    arr = SparseArray()
    print(f'Inital array arr -> {str(arr)}')
    print(f'type(arr) = {type(arr)}')
    arr[1] = "one"
    print(f'After arr[1] = "one" -> {arr}')
    print(f'arr.has_index(1) = {arr.has_index(1)}')
    print(f'arr.has_index(2) = {arr.has_index(2)}')
    arr.from_assoc([(2,"two"),(3,"three"),("four",4),"five"])
    print(f'After from_assoc -> {arr}')
    print(f'arr[1] -> {arr[1]}')
    arr[10] = "ten"
    print(f'After arr[10] = "ten" -> {arr}') 
    del arr[3]
    print(f'After del arr[3] -> {arr}') 
    print(f'"ten" in arr -> {"ten" in arr}')
    sarr = SparseArray([(2,"two"),(3,"three"),("four",4),"five"])
    print(f'New array sarr -> {sarr}')
    test = SparseArray()
    test.from_assoc([(2,"two"),(3,"three"),(1,"one")])
    print(f'New array test -> {test}')
    print(f'{test.__dict__}')
    print(f'{SparseArray.__dict__["to_assoc"]}')


