/*
 * $Id: foreach2.prg 10153 2009-02-03 02:05:45Z druzus $
 */

/*
 * Harbour Project source code:
 *    demonstration code for FOR EACH overloading
 *
 * Copyright 2007 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
 * www - http://www.harbour-project.org
 *
 */


#include "hbclass.ch"

proc main()
local e, o

   ? "FOR EACH e IN myclass1()"
   o:=myclass1()
   for each e in o
      ? e:__enumIndex(), "=>", e
   next
   ? "FOR EACH e IN myclass1() DESCEND"
   for each e in o descend
      ? e:__enumIndex(), "=>", e
   next

   ?
   ? "FOR EACH e IN myclass2()"
   o:=myclass2()
   for each e in o
      ? e:__enumIndex(), "=>", e
   next
   ? "FOR EACH e IN myclass2() DESCEND"
   for each e in o descend
      ? e:__enumIndex(), "=>", e
   next

return


/* The first form of FOR EACH overloading
 * Can be use when all values can be calculated when FOR EACH starts
 * It overloads __enumStart() message which set base enumerator values.
 * for ascending iteration it sets: {"A","B","C"}
 * and for descending: {1, 2, 3}
 */
CREATE CLASS myclass1
   METHOD __enumStart( enum, lDescend )
END CLASS

METHOD __enumStart( enum, lDescend ) CLASS myclass1
   /* set base value for enumerator */
   /* important: the messages have to be send to the enumerator
    * reference (@enum) not directly to the enumerator enum
    */
   (@enum):__enumBase( iif( lDescend, {1, 2, 3}, {"A","B","C"} ) )
   return .T. /* .F. means stop iteration */


/* The second form of FOR EACH overloading
 * We are overloading the folowing messages:
 *    __enumStart()     // executed when FOR EACH starts
 *    __enumSkip()      // executed on each LOOP
 *    __enumStop()      // executed when FOR EACH stops
 * Such method can be used when we cannot calculate all values
 * when FOR EACH starts or such calculation is expensive so we
 * want to make them dynamically
 */

CREATE CLASS myclass2
   VAR    value
   METHOD __enumStart( enum, lDescend )
   METHOD __enumSkip( enum, lDescend )
   METHOD __enumStop()
END CLASS

METHOD __enumStart( enum, lDescend ) CLASS myclass2
   /* Here we can have initialization code */
   ::value := 0.00
   /* set enumerator value */
   (@enum):__enumValue( ::value )
   /* set enumerator index, to make it more funny for descend
    * iterations we will use negative indexes ;-)
    */
   (@enum):__enumIndex( iif( lDescend, -1, 1 ) )
   return .T. /* continue iteration */

METHOD __enumSkip( enum, lDescend ) CLASS myclass2
   if lDescend
      ::value -= 3
   else
      ::value += 3
   endif
   /* stop iteration when abs( ::value ) > 20 */
   if abs( ::value ) > 20
      return .F.
   endif
   /* set enumerator value */
   (@enum):__enumValue( ::value / 10.0 )
   /* the index is updated automatically but if we want some noncontinuous
    * indexes then here we van set it using (@enum):__enumIndex( nNeIndex )
    * message
    */
   return .T. /* continue iteration */

METHOD PROCEDURE __enumStop() CLASS myclass2
   /* Here we can have cleanup code */
   return
