/// <summary>
        /// Generates a current switch.
        /// </summary>
        /// <param name="name">Name of current switch.</param>
        /// <param name="parameters">Parameters of current switch.</param>
        /// <param name="context">Reading context.</param>
        /// <returns>
        /// A new instance of current switch.
        /// </returns>
        private IEntity GenerateCurrentSwitch(string name, ParameterCollection parameters, ICircuitContext context)
        {
            if (parameters.Count < 4)
            {
                context.Result.Validation.Add(new ValidationEntry(ValidationEntrySource.Reader, ValidationEntryLevel.Warning, "Wrong parameter count for current switch", parameters.LineInfo));
                return(null);
            }

            string modelName = parameters.Get(3).Image;
            var    model     = context.ModelsRegistry.FindModel(modelName);

            if (model.Entity is ISwitchModel)
            {
                BehavioralResistor resistor = new BehavioralResistor(name);
                Model resistorModel         = model;
                context.CreateNodes(resistor, parameters.Take(2));
                var ic = $"i({parameters.Get(2)})";
                var iswitchModelParameters = resistorModel.Parameters as ISwitchModelParameters;

                double iOff = iswitchModelParameters.OffCurrent;
                double rOff = iswitchModelParameters.OffResistance;
                double iOn  = iswitchModelParameters.OnCurrent;
                double rOn  = iswitchModelParameters.OnResistance;

                double lm            = Math.Log(Math.Sqrt(rOn * rOff));
                double lr            = Math.Log(rOn / rOff);
                double im            = (iOn + iOff) / 2.0;
                double id            = iOn - iOff;
                var    resExpression = GetISwitchExpression(iOff, rOff, iOn, rOn, ic, lm, lr, im, id);
                resistor.Parameters.Expression  = resExpression;
                resistor.Parameters.ParseAction = (expression) =>
                {
                    var parser = new ExpressionParser(context.Evaluator.GetEvaluationContext(null), false, context.CaseSensitivity);
                    return(parser.Resolve(expression));
                };

                context.SimulationPreparations.ExecuteActionAfterSetup(
                    (simulation) =>
                {
                    if (context.ModelsRegistry is StochasticModelsRegistry stochasticModelsRegistry)
                    {
                        resistorModel = stochasticModelsRegistry.ProvideStochasticModel(name, simulation, model);

                        if (!context.Result.FindObject(resistorModel.Name, out _))
                        {
                            stochasticModelsRegistry.RegisterModelInstance(resistorModel);
                        }
                    }

                    iOff = iswitchModelParameters.OffCurrent;
                    rOff = iswitchModelParameters.OffResistance;
                    iOn  = iswitchModelParameters.OnCurrent;
                    rOn  = iswitchModelParameters.OnResistance;

                    lm            = Math.Log(Math.Sqrt(rOn * rOff));
                    lr            = Math.Log(rOn / rOff);
                    im            = (iOn + iOff) / 2.0;
                    id            = iOn - iOff;
                    resExpression = GetISwitchExpression(iOff, rOff, iOn, rOn, ic, lm, lr, im, id);
                    resistor.Parameters.Expression  = resExpression;
                    resistor.Parameters.ParseAction = (expression) =>
                    {
                        var parser = new ExpressionParser(context.Evaluator.GetEvaluationContext(simulation), false, context.CaseSensitivity);
                        return(parser.Resolve(expression));
                    };
                });
                return(resistor);
            }

            CurrentSwitch csw = new CurrentSwitch(name);

            context.CreateNodes(csw, parameters);

            // Get the controlling voltage source
            if (parameters[2] is WordParameter || parameters[2] is IdentifierParameter)
            {
                csw.ControllingSource = context.NameGenerator.GenerateObjectName(parameters.Get(2).Image);
            }
            else
            {
                context.Result.Validation.Add(new ValidationEntry(ValidationEntrySource.Reader, ValidationEntryLevel.Warning, "Voltage source name expected", parameters.LineInfo));
                return(null);
            }

            // Get the model
            context.SimulationPreparations.ExecuteActionBeforeSetup((simulation) =>
            {
                context.ModelsRegistry.SetModel(
                    csw,
                    simulation,
                    parameters.Get(3),
                    $"Could not find model {parameters.Get(3)} for current switch {name}",
                    (Context.Models.Model switchModel) => csw.Model = switchModel.Name,
                    context.Result);
            });

            // Optional on or off
            if (parameters.Count > 4)
            {
                switch (parameters.Get(4).Image.ToLower())
                {
                case "on":
                    csw.SetParameter("on", true);
                    break;

                case "off":
                    csw.SetParameter("off", true);
                    break;

                default:
                    context.Result.Validation.Add(new ValidationEntry(ValidationEntrySource.Reader, ValidationEntryLevel.Warning, "ON or OFF expected", parameters.LineInfo));
                    return(csw);
                }
            }

            return(csw);
        }
        /// <summary>
        /// Generates a voltage switch.
        /// </summary>
        /// <param name="name">Name of voltage switch to generate.</param>
        /// <param name="parameters">Parameters for voltage switch.</param>
        /// <param name="context">Reading context.</param>
        /// <returns>
        /// A new voltage switch.
        /// </returns>
        protected IEntity GenerateVoltageSwitch(string name, ParameterCollection parameters, ICircuitContext context)
        {
            if (parameters.Count < 5)
            {
                context.Result.Validation.Add(new ValidationEntry(ValidationEntrySource.Reader, ValidationEntryLevel.Warning, "Wrong parameter count for voltage switch", parameters.LineInfo));
                return(null);
            }

            string modelName = parameters.Get(4).Image;

            var model = context.ModelsRegistry.FindModel(modelName);

            if (model.Entity is VSwitchModel)
            {
                BehavioralResistor resistor = new BehavioralResistor(name);
                Model resistorModel         = model;
                context.CreateNodes(resistor, parameters.Take(BehavioralResistor.BehavioralResistorPinCount));
                var vSwitchModelParameters = resistorModel.Parameters as VSwitchModelParameters;

                double vOff = vSwitchModelParameters.OffVoltage;
                double rOff = vSwitchModelParameters.OffResistance;
                double vOn  = vSwitchModelParameters.OnVoltage;
                double rOn  = vSwitchModelParameters.OnResistance;

                string vc            = $"v({parameters.Get(2)}, {parameters.Get(3)})";
                double lm            = Math.Log(Math.Sqrt(rOn * rOff));
                double lr            = Math.Log(rOn / rOff);
                double vm            = (vOn + vOff) / 2.0;
                double vd            = vOn - vOff;
                string resExpression = GetVSwitchExpression(vOff, rOff, vOn, rOn, vc, lm, lr, vm, vd);

                resistor.Parameters.Expression  = resExpression;
                resistor.Parameters.ParseAction = (expression) =>
                {
                    var parser = new ExpressionParser(context.Evaluator.GetEvaluationContext(null), false, context.CaseSensitivity);
                    return(parser.Resolve(expression));
                };

                context.SimulationPreparations.ExecuteActionAfterSetup(
                    (simulation) =>
                {
                    if (context.ModelsRegistry is StochasticModelsRegistry stochasticModelsRegistry)
                    {
                        resistorModel = stochasticModelsRegistry.ProvideStochasticModel(name, simulation, model);

                        if (!context.Result.FindObject(resistorModel.Name, out _))
                        {
                            stochasticModelsRegistry.RegisterModelInstance(resistorModel);
                        }
                    }

                    vOff          = vSwitchModelParameters.OffVoltage;
                    rOff          = vSwitchModelParameters.OffResistance;
                    vOn           = vSwitchModelParameters.OnVoltage;
                    rOn           = vSwitchModelParameters.OnResistance;
                    lm            = Math.Log(Math.Sqrt(rOn * rOff));
                    lr            = Math.Log(rOn / rOff);
                    vm            = (vOn + vOff) / 2.0;
                    vd            = vOn - vOff;
                    resExpression = GetVSwitchExpression(vOff, rOff, vOn, rOn, vc, lm, lr, vm, vd);
                    resistor.Parameters.Expression  = resExpression;
                    resistor.Parameters.ParseAction = (expression) =>
                    {
                        var parser = new ExpressionParser(context.Evaluator.GetEvaluationContext(simulation), false, context.CaseSensitivity);
                        return(parser.Resolve(expression));
                    };
                });
                return(resistor);
            }

            VoltageSwitch vsw = new VoltageSwitch(name);

            context.CreateNodes(vsw, parameters);

            context.SimulationPreparations.ExecuteActionBeforeSetup((simulation) =>
            {
                context.ModelsRegistry.SetModel(
                    vsw,
                    simulation,
                    parameters.Get(4),
                    $"Could not find model {parameters.Get(4)} for voltage switch {name}",
                    (Context.Models.Model model2) => { vsw.Model = model2.Name; },
                    context.Result);
            });

            // Optional ON or OFF
            if (parameters.Count == 6)
            {
                switch (parameters.Get(5).Image.ToLower())
                {
                case "on":
                    vsw.SetParameter("on", true);
                    break;

                case "off":
                    vsw.SetParameter("off", true);
                    break;

                default:
                    context.Result.Validation.Add(new ValidationEntry(ValidationEntrySource.Reader, ValidationEntryLevel.Warning, "ON or OFF expected", parameters.LineInfo));
                    return(vsw);
                }
            }
            else if (parameters.Count > 6)
            {
                context.Result.Validation.Add(new ValidationEntry(ValidationEntrySource.Reader, ValidationEntryLevel.Warning, "Too many parameters for voltage switch", parameters.LineInfo));
                return(vsw);
            }

            return(vsw);
        }
        /// <summary>
        /// Generate resistor.
        /// </summary>
        /// <param name="name">Name of resistor to generate.</param>
        /// <param name="parameters">Parameters and pins for resistor.</param>
        /// <param name="context">Reading context.</param>
        /// <returns>
        /// A new instance of resistor.
        /// </returns>
        protected IEntity GenerateRes(string name, ParameterCollection parameters, ICircuitContext context)
        {
            if (parameters.Count == 3)
            {
                var evalContext = context.Evaluator.GetEvaluationContext();

                // RName Node1 Node2 something
                var    something  = parameters[2];
                string expression = null;

                if (something is AssignmentParameter asp)
                {
                    expression = asp.Value;
                }
                else
                {
                    expression = something.Image;
                }

                if (evalContext.HaveSpiceProperties(expression) || evalContext.HaveFunctions(expression))
                {
                    BehavioralResistor behavioralResistor = new BehavioralResistor(name);
                    context.CreateNodes(behavioralResistor, parameters.Take(BehavioralResistor.BehavioralResistorPinCount));

                    behavioralResistor.Parameters.Expression  = expression;
                    behavioralResistor.Parameters.ParseAction = (expression) =>
                    {
                        var parser = new ExpressionParser(context.Evaluator.GetEvaluationContext(null), false, context.CaseSensitivity);
                        return(parser.Resolve(expression));
                    };

                    if (evalContext.HaveFunctions(expression))
                    {
                        context.SimulationPreparations.ExecuteActionBeforeSetup((simulation) =>
                        {
                            behavioralResistor.Parameters.Expression = expression.ToString();

                            behavioralResistor.Parameters.ParseAction = (expression) =>
                            {
                                var parser = new ExpressionParser(context.Evaluator.GetEvaluationContext(simulation), false, context.CaseSensitivity);
                                return(parser.Resolve(expression));
                            };
                        });
                    }

                    return(behavioralResistor);
                }
            }

            Resistor res = new Resistor(name);

            context.CreateNodes(res, parameters);

            if (parameters.Count == 3)
            {
                // RName Node1 Node2 something
                var something = parameters[2];

                // Check if something is a model name
                if ((something is WordParameter || something is IdentifierParameter) &&
                    context.ModelsRegistry.FindModel(parameters.Get(2).Image) != null)
                {
                    // RName Node1 Node2 modelName
                    context.Result.Validation.Add(
                        new ValidationEntry(
                            ValidationEntrySource.Reader,
                            ValidationEntryLevel.Warning,
                            $"R parameter needs to be specified",
                            parameters.LineInfo));
                    return(null);
                }

                // Check if something can be resistance
                if (!(something is WordParameter ||
                      something is IdentifierParameter ||
                      something is ValueParameter ||
                      something is ExpressionParameter ||
                      (something is AssignmentParameter ap && (ap.Name.ToLower() == "r" || ap.Name.ToLower() == "resistance"))))
                {
                    context.Result.Validation.Add(
                        new ValidationEntry(
                            ValidationEntrySource.Reader,
                            ValidationEntryLevel.Warning,
                            $"Third parameter needs to represent resistance of resistor",
                            parameters.LineInfo));

                    return(null);
                }

                // Set resistance
                if (something is AssignmentParameter asp)
                {
                    context.SetParameter(res, "resistance", asp, true, false);
                }
                else
                {
                    context.SetParameter(res, "resistance", something, true, false);
                }
            }
            else
            {
                var resistorParameters = new List <Parameter>(parameters.Skip(Resistor.ResistorPinCount).ToArray());

                // RName Node1 Node2 something param1 ...
                if (resistorParameters.Count == 0)
                {
                    context.Result.Validation.Add(
                        new ValidationEntry(
                            ValidationEntrySource.Reader,
                            ValidationEntryLevel.Warning,
                            $"Resistor doesn't have at least 3 parameters",
                            parameters.LineInfo));
                    return(null);
                }

                var something = resistorParameters[0];

                // Check if something is a model name
                bool hasModelSyntax = (something is WordParameter || something is IdentifierParameter) &&
                                      context.ModelsRegistry.FindModel(something.Image) != null;
                bool hasTcParameter = parameters.Any(
                    p => p is AssignmentParameter ap && ap.Name.Equals(
                        "tc",
                        false ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase));

                AssignmentParameter tcParameter = null;

                if (hasTcParameter)
                {
                    tcParameter = (AssignmentParameter)parameters.Single(
                        p => p is AssignmentParameter ap && ap.Name.Equals(
                            "tc",
                            false ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase));
                    resistorParameters.Remove(tcParameter);
                }

                if (hasModelSyntax)
                {
                    var modelNameParameter = resistorParameters[0];

                    // Ignore tc parameter on resistor ...
                    context.SimulationPreparations.ExecuteActionBeforeSetup((simulation) =>
                    {
                        context.ModelsRegistry.SetModel(
                            res,
                            simulation,
                            modelNameParameter,
                            $"Could not find model {modelNameParameter} for resistor {name}",
                            (Context.Models.Model model) => res.Model = model.Name,
                            context.Result);
                    });

                    resistorParameters.RemoveAt(0);

                    if (resistorParameters.Count > 0 && (resistorParameters[0] is WordParameter ||
                                                         resistorParameters[0] is IdentifierParameter ||
                                                         resistorParameters[0] is ValueParameter ||
                                                         resistorParameters[0] is ExpressionParameter))
                    {
                        context.SetParameter(res, "resistance", resistorParameters[0].Image, true, false);
                        resistorParameters.RemoveAt(0);
                    }
                }
                else
                {
                    if (hasTcParameter)
                    {
                        var model = new ResistorModel(res.Name + "_default_model");
                        if (tcParameter.Values.Count == 2)
                        {
                            context.SetParameter(model, "tc1", tcParameter.Values[0]);
                            context.SetParameter(model, "tc2", tcParameter.Values[1]);
                        }
                        else
                        {
                            context.SetParameter(model, "tc1", tcParameter.Value);
                        }

                        context.ModelsRegistry.RegisterModelInstance(new Context.Models.Model(model.Name, model, model.Parameters));
                        res.Model = model.Name;
                        context.Result.AddEntity(model);
                    }

                    // Check if something can be resistance
                    var resistanceParameter = resistorParameters[0];

                    if (!(resistanceParameter is WordParameter ||
                          resistanceParameter is IdentifierParameter ||
                          resistanceParameter is ValueParameter ||
                          resistanceParameter is ExpressionParameter ||
                          (resistanceParameter is AssignmentParameter ap && (ap.Name.ToLower() == "r" || ap.Name.ToLower() == "resistance"))))
                    {
                        context.Result.Validation.Add(
                            new ValidationEntry(
                                ValidationEntrySource.Reader,
                                ValidationEntryLevel.Warning,
                                $"Invalid value for resistance",
                                parameters.LineInfo));
                        return(null);
                    }

                    if (resistanceParameter is AssignmentParameter asp)
                    {
                        context.SetParameter(res, "resistance", asp.Value, true, false);
                    }
                    else
                    {
                        context.SetParameter(res, "resistance", resistanceParameter.Image, true, false);
                    }

                    resistorParameters.RemoveAt(0);
                }

                foreach (var parameter in resistorParameters)
                {
                    if (parameter is AssignmentParameter ap)
                    {
                        try
                        {
                            context.SetParameter(res, ap.Name, ap.Value);
                        }
                        catch (Exception e)
                        {
                            context.Result.Validation.Add(
                                new ValidationEntry(
                                    ValidationEntrySource.Reader,
                                    ValidationEntryLevel.Error,
                                    $"Can't set parameter for resistor: '{parameter.Image}'",
                                    parameters.LineInfo,
                                    exception: e));

                            return(null);
                        }
                    }
                    else
                    {
                        context.Result.Validation.Add(
                            new ValidationEntry(
                                ValidationEntrySource.Reader,
                                ValidationEntryLevel.Error,
                                $"Invalid parameter for resistor: '{parameter.Image}'",
                                parameters.LineInfo));

                        return(null);
                    }
                }
            }

            return(res);
        }