
class SequenceIterable:

    def __init__(self, values):
        self.values = values
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index >= len(self.values):
            raise StopIteration
        item = self.values[self.index]
        self.index += 1
        return item

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class Countdown:

    def __init__(self, start):
        self.start = start


    def __iter__(self):
        return self

    def __next__(self):
        val = self.start 
        if val < 0:
            raise StopIteration
        self.start -= 1
        return val


# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class PowerTwo:

    def __init__(self, power):
        self.power = power
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index > self.power:
            raise StopIteration
        value = 2**self.index
        self.index += 1
        return value

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~        

class Card:
    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit

    def __str__(self):
        return f"{self.rank} {self.suit}"

class Deck:
    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    suits = ['Clubs', 'Diamonds', 'Hearts', 'Spades']

    def __init__(self):
        self.cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks]

    def __getitem__(self, index):
        return self.cards[index]


# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~        

class FileReader:

    def __init__(self, filename):
        # self.file = open(filename)
        self.index = 0
        self.data = []
        with open(filename, 'r') as self.file:
            for line in self.file:
                self.data.append(line)

    def __iter__(self):
        return self

    def __next__(self):
        if self.index >= len(self.data):
            raise StopIteration
        st = self.data[self.index].strip()
        self.index += 1
        return st


# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~        

class InfinityIterator:
    
    def __init__(self):
        self.value = 0

    def __iter__(self):
        return self
    
    def __next__(self):
        foo = self.value
        self.value += 10
        return foo

def test_7():
    # a = iter(InfinityIterator())
    a = InfinityIterator()
    print(next(a))
    print(next(a))
    print(next(a))


def test_6():
    # reader = FileReader("lorem.txt")
    for lite in FileReader('lorem.txt'):
        print(lite)

def test_5():
    deck = Deck()
    for card in deck:
        print(card)

def test_4():
    for i in PowerTwo(4):
        print(i)

def test_3():
    for i in Countdown(3):
        print(i)

def test_2():
    container = SequenceIterable([1, 2 , 3, True, 'hello'])
    for i in container:
        print(i)

def test_1():
    class MyClass:
        def __init__(self):
            self.items = [1, 2, 3]
            self.index = 0

        def __iter__(self):
            return self

        def __next__(self):
            if self.index >= len(self.items):
                raise StopIteration
            item = self.items[self.index]
            self.index += 1
            return item


    for item in MyClass():
        print(item)    


def main():
    l = [1, 2, 3]
    s = 'abc'
    # test_1()
    # test_2()
    # test_3()
    # test_4()
    # test_5()
    # test_6()
    test_7()




if __name__ == '__main__':
    main()