/*
    Method:     Magick::colors [ { |colorinfo| } ]
    Purpose:    If called with the optional block, iterates over the colors,
                otherwise returns an array of Magick::Color objects
    Notes:      There are 3 implementations

*/
VALUE
Magick_colors(VALUE class)
{
#if defined(HAVE_GETCOLORINFOARRAY) // GraphicsMagick
    ColorInfo **color_ary;
    ExceptionInfo exception;
    volatile VALUE ary;
    int x;

    GetExceptionInfo(&exception);

    color_ary = GetColorInfoArray(&exception);
    HANDLE_ERROR

    if (rb_block_given_p())
    {
        x = 0;
        while(color_ary[x])
        {
            rb_yield(Color_from_ColorInfo(color_ary[x]));
            x += 1;
        }
        magick_free(color_ary);
        return class;
    }
    else
    {
        ary = rb_ary_new();

        x = 0;
        while (color_ary[x])
        {
            rb_ary_push(ary, Color_from_ColorInfo(color_ary[x]));
            x += 1;
        }
        magick_free(color_ary);
        return ary;
    }

#elif defined(HAVE_GETCOLORINFOLIST)    // ImageMagick 6.0.0

    const ColorInfo **color_info_list;
    unsigned long number_colors, x;
    volatile VALUE ary;

#if defined(HAVE_OLD_GETCOLORINFOLIST)
    color_info_list = GetColorInfoList("*", &number_colors);

#else
    // IM 6.1.3 added an exception parm to GetColorInfoList
    ExceptionInfo exception;

    GetExceptionInfo(&exception);

    color_info_list = GetColorInfoList("*", &number_colors, &exception);
    HANDLE_ERROR
#endif


    if (rb_block_given_p())
    {
        for(x = 0; x < number_colors; x++)
        {
            rb_yield(Color_from_ColorInfo(color_info_list[x]));
        }
        magick_free(color_info_list);
        return class;
    }
    else
    {
        ary = rb_ary_new2((long) number_colors);
        for(x = 0; x < number_colors; x++)
        {
            rb_ary_push(ary, Color_from_ColorInfo(color_info_list[x]));
        }

        magick_free(color_info_list);
        return ary;
    }

#else   // ImageMagick < 6.0.0

    const ColorInfo *color_list;
    ColorInfo *color;
    ExceptionInfo exception;
    volatile VALUE ary, el;

    GetExceptionInfo(&exception);

    color_list = GetColorInfo("*", &exception);
    DestroyExceptionInfo(&exception);

    // The order of the colors list can change in mid-iteration,
    // so the only way we can guarantee a single pass thru the list
    // is to copy the elements into an array without returning to
    // IM. So, we always create a Ruby array and either return it
    // or iterate over it.
    ary = rb_ary_new();
    for (color = (ColorInfo *)color_list; color; color = color->next)
    {
        rb_ary_push(ary, Color_from_ColorInfo(color));
    }

    // If block, iterate over colors
    if (rb_block_given_p())
    {
        while ((el = rb_ary_shift(ary)) != Qnil)
        {
            rb_yield(el);
        }
        return class;
    }
    else
    {
        return ary;
    }

#endif
}