/*
 * [TestEnum.java]
 *
 * Summary: Demonstrate use of Enum static and instance fields in nested enums.
 *
 * Copyright: (c) 2009-2017 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.8+
 *
 * 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.*;

/**
 * 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
    {
    /**
     * constant of the enclosing  TestEnum class
     */
    private static final int outerConstant = 11;

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

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

    /**
     * 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;

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

        /**
         * constructor
         *
         * @param horns how many horns this animal has.
         */
        Animals( int horns )
            {
            this.horns = horns;
            // may not reference the static legs variable here
            }
        /**
         * how many horns does this animal have?
         *
         * @return how many horns this animal has
         */
        /**
         * static method of the enclosing TestEnum class
         *
         * @return an indicator number
         */
        private static int outerStaticMethod()
            {
            return 14;
            }

        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;
            }

        /**
         * 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() );
            }

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

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

        /**
         * 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() );
            }
        }
    }