/// <summary>
        /// Based on the node's connectivity, select values for OPTIONS
        /// automatically.  The strategy is
        /// - Try to keep the OPTIONS the node already has.
        /// - look for OPTIONS in the next connected downstream node(s)
        /// - for each value in OPTIONS, see if the value can be coerced
        ///   to our current type(s)
        /// - Prefer to use OPTIONS from the node at the other end of 
        ///   prefer because it's probably the node were adding via ::addIOArk().
        ///
        /// At this point in the code, our new list of types has already been
        /// computed based on our new connectivity.
        /// </summary>
        /// <param name="pref"></param>
        private void setTypeSafeOptions(Ark pref)
        {
            // This method is nonsense in the case of an Output tool.
            Debug.Assert(IsInput);

            // If we have OPTIONS && any item in OPTION is illegal input given
            // our new type, then remove all the OPTIONS.
            ParameterDefinition macroPd = getParameterDefinition();
            String[] options = macroPd.getValueOptions();
            List<DXType> types = macroPd.getTypes();
            bool can_coerce = true;
            if (options != null && options.Length > 0)
            {
                can_coerce = true;
                for (int i = 0; i < options.Length && can_coerce; i++)
                {
                    can_coerce = can_coerce && canCoerceValue(options[i], types);
                }
                if (!can_coerce)
                {
                    macroPd.removeValueOptions();
                    options = null;
                }
            }

            //If our current OPTIONS are safe to keep using...
            if (options != null && options.Length > 0)
                return;

            // If the parameter has no option values, then check each downstream
            // input tab.  If any has option values, then try to use those but
            // only if each of the option values is legal given our new type.
            Node destination;
            NodeDefinition destinationDef;
            ParameterDefinition destinationParamDef;
            int paramIndex;

            // First check the new ark to see if it gave give us
            // option values.  option strings are stored as a null-terminated
            // array of char*.
            String[] dest_option_values = null;
            can_coerce = true;
            if (pref != null)
            {
                destination = pref.getDestinationNode(out paramIndex);
                destinationDef = destination.Definition;
                destinationParamDef = destinationDef.getInputDefinition(paramIndex);
                dest_option_values = destinationParamDef.getValueOptions();

                if (dest_option_values != null && dest_option_values.Length > 0)
                {
                    for (int i = 0; i < dest_option_values.Length && can_coerce; i++)
                    {
                        can_coerce = can_coerce && canCoerceValue(dest_option_values[i], types);
                    }
                }
            }

            if (can_coerce && dest_option_values != null && dest_option_values.Length > 0)
            {
                for (int i = 0; i < dest_option_values.Length; i++)
                {
                    if (!macroPd.addValueOption(dest_option_values[i]))
                    {
                        ErrorDialog ed = new ErrorDialog();
                        ed.post("Cannot add {0} to Options values", dest_option_values[i]);
                        break;
                    }
                }
            }
            else
            {
                // get all the destination nodes  When we're called as via ::addIOArk(),
                // the new connection has not yet been added to our list
                // of downstream nodes.
                List<Ark> arks = getOutputArks(1);
                foreach (Ark ark in arks)
                {
                    destination = ark.getDestinationNode(out paramIndex);
                    destinationDef = destination.Definition;
                    destinationParamDef = destinationDef.getInputDefinition(paramIndex);

                    // for each option value see, see if it can be coerced.
                    dest_option_values = destinationParamDef.getValueOptions();
                    if (dest_option_values == null || dest_option_values.Length == 0) continue;

                    can_coerce = true;
                    for (int i = 0; i < dest_option_values.Length && can_coerce; i++)
                    {
                        can_coerce = can_coerce && canCoerceValue(dest_option_values[i], types);
                    }
                    if (can_coerce)
                    {
                        for (int i = 0; i < dest_option_values.Length; i++)
                        {
                            if (!macroPd.addValueOption(dest_option_values[i]))
                            {
                                ErrorDialog ed = new ErrorDialog();
                                ed.post("Cannot add {0} to Options values",
                                    dest_option_values[i]);
                                break;
                            }
                        }
                        break;
                    }
                }
            }
        }
        protected override bool addIOArk(List<Parameter> io, int index, Ark a)
        {
            List<DXType> newTypesList = null;
            if (IsInput)
            {
                int i;
                Node dest = a.getDestinationNode(out i);
                Parameter pin = dest.getInputParameter(i);
                ParameterDefinition pind = pin.Definition;

                ParameterDefinition macroPd = getParameterDefinition();
                List<DXType> outTypes = macroPd.getTypes();
                newTypesList = DXType.IntersectTypeLists(outTypes, pind.getTypes());
                foreach (DXType t in outTypes.ToArray())
                {
                    macroPd.removeType(t);
                }

                Parameter pout = getOutputParameter(1);
                ParameterDefinition nodePd = pout.Definition;
                outTypes = nodePd.getTypes();

                foreach (DXType t in outTypes.ToArray())
                {
                    nodePd.removeType(t);
                }

                foreach (DXType t in newTypesList.ToArray())
                {
                    DXType newt = t.duplicate();
                    nodePd.addType(newt);
                    macroPd.addType(t);
                }

                setTypeSafeOptions(a);
            }
            else
            {
                int i;
                Node dest = a.getSourceNode(out i);
                Parameter pin = dest.getOutputParameter(i);
                ParameterDefinition pind = pin.Definition;

                ParameterDefinition macroPd = getParameterDefinition();
                List<DXType> outTypes = macroPd.getTypes();
                newTypesList = DXType.IntersectTypeLists(outTypes, pind.getTypes());
                foreach (DXType t in outTypes.ToArray())
                {
                    macroPd.removeType(t);
                }

                Parameter pout = getInputParameter(1);
                ParameterDefinition nodePd = pout.Definition;
                outTypes = nodePd.getTypes();

                foreach (DXType t in outTypes.ToArray())
                {
                    nodePd.removeType(t);
                }

                foreach (DXType t in newTypesList.ToArray())
                {
                    DXType newt = t.duplicate();
                    nodePd.addType(newt);
                    macroPd.addType(t);
                }
            }

            if (getConfigurationDialog() != null)
            {
                getConfigurationDialog().changeInput(1);
                getConfigurationDialog().changeOutput(1);
            }

            return base.addIOArk(io, index, a);
        }