/*
 * [TestEnum.java]
 *
 * Summary: Demonstrate use of Enum static and instance fields in nested enums.
 *
 * Copyright: (c) 2009-2012 Roedy Green, Canadian Mind Products, http://mindprod.com
 *
 * Licence: This software may be copied and used freely for any purpose but military.
 *          http://mindprod.com/contact/nonmil.html
 *
 * Requires: JDK 1.7+
 *
 * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/
 *
 * Version History:
 *  1.0 2009-03-24 initial version
 *  1.1 2011-11-05 add comments about accessing variables of enclosing class.
 */
package com.mindprod.example;

import static java.lang.System.out;

/**
 * Demonstrate use of Enum static and instance fields in nested enums.
 *
 * @author Roedy Green, Canadian Mind Products
 * @version 1.1 2011-11-05 add comments about accessing variables of enclosing class.
 * @since 2009-03-24
 */
public class TestEnum
    {
    // ------------------------------ CONSTANTS ------------------------------

    /**
     * constant of the enclosing  TestEnum class
     */
    private static final int outerConstant = 11;

    /**
     * instance variable of the enclosing TestEnum class
     */
    private static int outerStatic = 12;

    // ------------------------------ FIELDS ------------------------------

    /**
     * instance variable of the enclosing TestEnum class. Can't be accessed directly from within the enum.
     */
    int outerInstance = 13;

    // -------------------------- STATIC METHODS --------------------------

    /**
     * static method of the enclosing TestEnum class
     *
     * @return an indicator number
     */
    private static int outerStaticMethod()
        {
        return 14;
        }

    // -------------------------- OTHER METHODS --------------------------

    /**
     * instance method of the enclosing TestEnum class.
     * Can't be accessed directly from within the enum.
     *
     * @return an indicator number
     */
    int outerInstanceMethod()
        {
        return 15;
        }

    // -------------------------- INNER CLASSES --------------------------

    /**
     * implicitly, the Animals enum is actually a nested static class.  You can see this most easily if you decompile.
     */
    enum Animals
        {
            COW( 2 ),
            GOAT( 2 ),
            OSTRICH( 0 )
                    {
                    /**
                     OSTRICH overrides the default version of the method. */
                    int getWingCount()
                        {
                        return wc;
                        }

                    /**
                     field that only OSTRICH has */
                    @SuppressWarnings( { "FieldMayBeStatic" } )
                    final int wc = 2;
                    };

        /**
         * COW, GOAT and OSTRICH all share a single copy of this field.
         * This is an artificial example. Usually this would be an instance field.
         */
        static int legs = 4;

        // ------------------------------ FIELDS ------------------------------

        /**
         * even though COW, GOAT and OSTRICH all have this field, they each have their own copy.
         */
        int horns;

        // --------------------------- CONSTRUCTORS ---------------------------

        /**
         * constructor
         *
         * @param horns how many horns this animal has.
         */
        Animals( int horns )
            {
            this.horns = horns;
            // may not reference the static legs variable here
            }

        // --------------------- GETTER / SETTER METHODS ---------------------

        /**
         * how many horns does this animal have?
         *
         * @return how many horns this animal has
         */
        int getHorns()
            {
            return horns;
            }

        /**
         * define how many horns this animal has
         *
         * @param horns number of horns this animal hes
         */
        void setHorns( int horns )
            {
            // set horns variable, one copy for each enum constant.
            this.horns = horns;
            }

        /**
         * how many legs does this animal have?
         * Since legs is static, this method could be static too.
         *
         * @return number of legs this animal has
         */
        int getLegs()
            {
            return legs;
            }

        // -------------------------- OTHER METHODS --------------------------

        /**
         * default method, overridden by OSTRICH only.
         *
         * @return number of wings this animal has.
         */
        int getWingCount()
            {
            return 0;
            }

        /**
         * define how many legs this animal has.
         *
         * @param legs number of legs.
         */
        void setLegs( int legs )
            {
            // Set shared legs variable.
            Animals.legs = legs;

            // Try to access an static constant of the enclosing class.
            out.println( outerConstant );

            // Try to access an static variable of the enclosing class.
            out.println( outerStatic );

            // Try to access an instance variable of the enclosing class.
            // You can't access instance variables or methods of the enclosing class
            // because this enum in implicitly a nested _static_ class
            // NOT LEGAL: out.println( outerInstance);

            // Try to access an static method of the enclosing class.
            out.println( outerStaticMethod() );

            // Try to access an instance method of the enclosing class.
            // You can't access instance variables or methods of the enclosing class
            // because this enum in implicitly a nested _static_ class
            // NOT LEGAL: out.println( outerInstanceMethod() );
            }
        }

    // --------------------------- main() method ---------------------------

    /**
     * test enum
     *
     * @param args not used
     */
    public static void main( String[] args )
        {
        // prints 2
        out.println( Animals.COW.getHorns() );
        Animals.COW.setHorns( 1 );
        // prints 1
        out.println( Animals.COW.getHorns() );
        // prints 2
        out.println( Animals.GOAT.getHorns() );
        // prints 4
        out.println( Animals.COW.getLegs() );
        Animals.COW.setLegs( 5 );
        // prints 5
        out.println( Animals.COW.getLegs() );
        // prints 5
        out.println( Animals.GOAT.getLegs() );
        //  prints 2
        out.println( Animals.OSTRICH.getWingCount() );
        //  prints 0
        out.println( Animals.GOAT.getWingCount() );
        }
    }