using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;

namespace Iterators
{
    // Listing 5-32
    class FibonacciEnumerable :
        IEnumerable<BigInteger>, IEnumerator<BigInteger>
    {
        private BigInteger v1;
        private BigInteger v2;
        private bool first = true;

        public BigInteger Current
        {
            get { return v1; }
        }

        public void Dispose()
        {
        }

        object IEnumerator.Current
        {
            get { return Current; }
        }

        public bool MoveNext()
        {
            if (first)
            {
                v1 = 1;
                v2 = 1;
                first = false;
            }
            else
            {
                var tmp = v2;
                v2 = v1 + v2;
                v1 = tmp;
            }

            return true;
        }

        public void Reset()
        {
            first = true;
        }

        public IEnumerator<BigInteger> GetEnumerator()
        {
            return new FibonacciEnumerable();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

    class Example32
    {
        public static void UseHandWrittenEnumerable()
        {
            // Ten kod mógłby działać dowolnie długo, ale ponieważ nie stanowi
            // jedynej metody wykonywanej w ramach tego projektu, zatrzymamy
            // go po wyliczeniu 100 elementów ciągu Fibonacciego.

            int count = 0;
            foreach (BigInteger n in new FibonacciEnumerable())
            {
                Console.WriteLine(n);
                if (++count == 100) { break; }
            }
        }
    }
}
