/// <summary>
        /// If the lhs is not already a variable try to rearrange the equation to place a variable on the lhs.
        /// </summary>
        public static EqnCalc IsolateFirstVariableIfRequired(EqnCalc eqOriginal, ContentManager cm)
        {
            try
            {
                if (eqOriginal.Inputs[0] is Variable)
                {
                    return(eqOriginal);
                }                                                              // Nothing required

                IList <SingleValue> eqVars = eqOriginal?.FindAllVariables();

                Result <EqnCalc> r_result = RearrangeEquation(eqOriginal, eqVars[0].Name, cm);

                if (r_result.IsNotGood())
                {
                    Logging.LogMessage(r_result.Message);
                    return(eqOriginal);
                }

                return(r_result.Value);
            }
            catch (Exception ex)
            {
                Logging.LogException(ex);
                return(eqOriginal);
            }
        }
        private static Result <bool> RearrangeOnce(EqnCalc eqCalc, int argIndexToPreserve, ContentManager cm)
        {
            FunctionCalc lhsFunCalc  = eqCalc.Inputs[0] as FunctionCalc;
            Function     lhsFunction = lhsFunCalc?.Function;

            if (lhsFunction == null)
            {
                return(Result <bool> .Bad($"Unexpected error: lhs is not a funcalc"));
            }

            SingleResult argToPreserve = lhsFunCalc.Inputs[argIndexToPreserve];

            // Create placeholders that the function rearrangements will treat as variables
            IList <string> argPlaceholders = new List <string>();
            IDictionary <string, SingleResult> placeFillers = new Dictionary <string, SingleResult>();

            for (int i = 0; i < lhsFunCalc.Inputs.Count; i++)
            {
                string placeholder = $"v{i}";
                argPlaceholders.Add(placeholder);
                if (i != argIndexToPreserve)
                {
                    placeFillers.Add(placeholder, lhsFunCalc.Inputs[i]);
                }
            }
            string resPlaceHolder = "res";

            placeFillers.Add(resPlaceHolder, eqCalc.Inputs[1]);

            // Ask the function definition for a rearrangement that isolates the required variable
            Result <string> r_rearrangement = lhsFunction.GetRearrangement(argPlaceholders, resPlaceHolder, argIndexToPreserve);

            if (r_rearrangement.IsNotGood() || string.IsNullOrEmpty(r_rearrangement.Value))
            {
                return(Result <bool> .Bad($"Rearrangement failed: {r_rearrangement.Message}"));
            }

            // Parse the rearrangement expression
            JongErrWarn  errW   = null;
            FunctionCalc newRhs = cm.CreateFunctionCalcFromExpression(r_rearrangement.Value, "", null, out errW);

            if (newRhs == null)
            {
                return(Result <bool> .Bad($"Rearrangement cannot be used: {errW?.ErrWarnString}"));
            }

            // Subsitute for the placeholders
            Result <bool> r_ok = SubsituteForPlaceholders(newRhs, placeFillers);

            if (r_ok.IsNotGood())
            {
                return(Result <bool> .Bad($"Error substituting for placeholders: {r_ok.Message}"));
            }

            // Update the eqCalc with the rearrangement
            eqCalc.Inputs[1] = newRhs;
            eqCalc.Inputs[0] = argToPreserve;

            return(Result <bool> .Good(true));
        }
        private static IList <Foundlocation> FindVariable(EqnCalc eqCalc, string varName)
        {
            IList <Foundlocation> foundVars = new List <Foundlocation>();

            AddFoundVars(eqCalc.Inputs[0], varName, EqSide.Left, -1, 1, foundVars);
            AddFoundVars(eqCalc.Inputs[1], varName, EqSide.Right, -1, 1, foundVars);

            return(foundVars);
        }
        public static Result <EqnCalc> RearrangeEquation(EqnCalc eqOriginal, string varRequired, ContentManager cm)
        {
            try
            {
                // Copy the structure of eqOriginal so we don't mess it up
                Result <EqnCalc> r_eqCalc = CreateStructureCopy(eqOriginal, cm);
                if (r_eqCalc.IsNotGood())
                {
                    return(Result <EqnCalc> .Bad(r_eqCalc.Message));
                }

                EqnCalc eqCalc = r_eqCalc.Value;

                int varDepth = -1;
                while (true)
                {
                    // --------- Find varRequired and check it only appears once
                    IList <Foundlocation> found = FindVariable(eqCalc, varRequired);
                    if ((found == null) || (found.Count == 0))
                    {
                        return(Result <EqnCalc> .Bad($"Variable '{varRequired}' was not found in the equation"));
                    }
                    if (found.Count > 1)
                    {
                        return(Result <EqnCalc> .Bad(
                                   $"Cannot rearrange equation because it contains multiple instances of Variable '{varRequired}'"));
                    }

                    // --------- Swap sides if it was found on the right
                    if (found[0].EqSide == EqSide.Right)
                    {
                        SingleResult side = eqCalc.Inputs[1];
                        eqCalc.Inputs[1] = eqCalc.Inputs[0];
                        eqCalc.Inputs[0] = side;
                    }

                    // --------- Check we are making progress
                    if (found[0].Depth == 1)   // Success!
                    {
                        // Try to simplify the equation before returning it
                        Result <bool> r_changes = SimplifyEquation(eqCalc, cm);
                        if (r_changes.IsNotGood())
                        {
                            return(Result <EqnCalc> .Bad(r_changes.Message));
                        }
                        bool changesWereMade = r_changes.Value;

                        // Successful return
                        return(Result <EqnCalc> .Good(eqCalc));
                    }
                    else if (varDepth < 0)
                    {
                        varDepth = found[0].Depth;
                    }
                    else if (found[0].Depth >= varDepth)
                    {
                        return(Result <EqnCalc> .Bad($"Last rearrangement did not achieve anything"));
                    }
                    else if (found[0].Depth < 1)
                    {
                        return(Result <EqnCalc> .Bad($"Unexpected error: found[0].Depth < 1"));
                    }

                    // ------------ Rearrange once
                    Result <bool> r_resOnce = RearrangeOnce(eqCalc, found[0].TopBranchindex, cm);
                    if (r_resOnce.IsNotGood())
                    {
                        return(Result <EqnCalc> .Bad(r_resOnce.Message));
                    }
                }
            }
            catch (Exception ex)
            {
                return(Result <EqnCalc> .Bad(ex));
            }
        }