Пример #1
0
 /// <summary>
 /// performs the operations as described in the abstract class file. If it is called and a
 /// cell already exists, then the content of that cell with be changed along with the value
 /// </summary>
 /// <param name="name">name of the cell</param>
 /// <param name="formula">formula to be stored in the cell</param>
 /// <returns>all of the dependents of a cell</returns>
 protected override ISet <string> SetCellContents(string name, Formula formula)
 {
     addCell(name, formula, formula.Evaluate(Lookup));
     dependencyGraph.ReplaceDependents(name, formula.GetVariables());
     return(CellsToRecalculate(name));
 }
Пример #2
0
        /// <summary>
        /// If content is null, throws an ArgumentNullException.
        ///
        /// Otherwise, if name is null or invalid, throws an InvalidNameException.
        ///
        /// Otherwise, if content parses as a double, the contents of the named
        /// cell becomes that double.
        ///
        /// Otherwise, if content begins with the character '=', an attempt is made
        /// to parse the remainder of content into a Formula f using the Formula
        /// constructor with s => s.ToUpper() as the normalizer and a validator that
        /// checks that s is a valid cell name as defined in the AbstractSpreadsheet
        /// class comment.  There are then three possibilities:
        ///
        ///   (1) If the remainder of content cannot be parsed into a Formula, a
        ///       Formulas.FormulaFormatException is thrown.
        ///
        ///   (2) Otherwise, if changing the contents of the named cell to be f
        ///       would cause a circular dependency, a CircularException is thrown.
        ///
        ///   (3) Otherwise, the contents of the named cell becomes f.
        ///
        /// Otherwise, the contents of the named cell becomes content.
        ///
        /// If an exception is not thrown, the method returns a set consisting of
        /// name plus the names of all other cells whose value depends, directly
        /// or indirectly, on the named cell.
        ///
        /// For example, if name is A1, B1 contains A1*2, and C1 contains B1+A1, the
        /// set {A1, B1, C1} is returned.
        /// </summary>
        public override ISet <string> SetContentsOfCell(string name, string content)
        {
            var ReturnSet = new HashSet <string>();

            if (content == null)
            {
                throw new ArgumentNullException();
            }

            if (name == null || !IsValid.IsMatch(name))
            {
                throw new InvalidNameException();
            }

            //Double case.
            double number;

            if (double.TryParse(content, out number))
            {
                foreach (string s in SetCellContents(name.ToUpper(), number))
                {
                    ReturnSet.Add(s);
                }
            }

            //Formula case.
            else if (content != string.Empty && content[0] == '=')
            {
                string  text = content.Substring(1);
                Formula form = new Formula(text, s => s.ToUpper(), s => IsValid.IsMatch(s));
                foreach (string redo in SetCellContents(name.ToUpper(), form))
                {
                    ReturnSet.Add(redo);
                }
            }

            //Text case.
            else
            {
                foreach (string s in SetCellContents(name.ToUpper(), content))
                {
                    ReturnSet.Add(s);
                }
            }


            //Now we have all the cells to Recalculate in ReturnSet.
            foreach (string recalc in ReturnSet)
            {
                foreach (Cell cell in CellList)
                {
                    if (cell.Name == recalc)
                    {
                        //Only need to recalcuate cells whose contents are formulas. Other cells are self sufficient and values set earlier.
                        if (cell.Contents.GetType() == typeof(Formula))
                        {
                            Formula contents = (Formula)cell.Contents;
                            try
                            {
                                cell.Value = contents.Evaluate(s => (double)GetCellValue(s));
                            }
                            catch (InvalidCastException)
                            {
                                cell.Value = new FormulaError("One or more variables have an undefined value.");
                            }
                            catch (FormulaEvaluationException)
                            {
                                cell.Value = new FormulaError("Issue evaluating formula.");
                            }
                        }
                    }
                }
            }
            return(ReturnSet);
        }
Пример #3
0
        /// <summary>
        /// If formula parameter is null, throws an ArgumentNullException.
        ///
        /// Otherwise, if name is null or invalid, throws an InvalidNameException.
        ///
        /// Otherwise, if changing the contents of the named cell to be the formula would cause a
        /// circular dependency, throws a CircularException.
        ///
        /// Otherwise, the contents of the named cell becomes formula.  The method returns a
        /// Set consisting of name plus the names of all other cells whose value depends,
        /// directly or indirectly, on the named cell.
        ///
        /// For example, if name is A1, B1 contains A1*2, and C1 contains B1+A1, the
        /// set {A1, B1, C1} is returned.
        /// </summary>
        protected override ISet <string> SetCellContents(string cell_name, SpreadsheetUtilities.Formula formula)
        {
            IEnumerable <string> backup_variables = null;
            object backup_contents = null;
            bool   had_name        = false;
            string name            = Normalize(cell_name);

            //if the formula passed in is null this throws an ArgumentNullException();
            if (formula == null)
            {
                throw new ArgumentNullException("Formula cannot be null");
            }
            //checks if the name is null or invalid if so throws a new InvalidNameException();
            if (name == null || IsValid(name) == false)
            {
                throw new InvalidNameException();
            }
            //checks if the cell with the name has been set up, if so this sets the contents of the cell to the formula passed in.
            if (spreadsheet.ContainsKey(name))
            {
                backup_variables = dependency_graph.GetDependees(name);
                backup_contents  = spreadsheet[name].get_contents();
                spreadsheet[name].set_contents(formula);
                had_name = true;
            }
            //if the cell hasn't been set up this creates a new cell and sets its contents to the text passed in.
            else
            {
                backup_contents  = " ";
                backup_variables = new HashSet <string> {
                };
                spreadsheet.Add(name, new Cell(name, formula));
            }
            IEnumerable <string> variables = formula.GetVariables(); //Gets all the variables

            dependency_graph.ReplaceDependees(name, variables);      //Replace the dependees of the name with all the variables in the formula passed in.
            //creates a hash set for the return ISet.
            ISet <string> depends = new HashSet <string> {
            };

            //looks through each item in the dependency graph and add them to the hash set to return.
            try
            {
                IEnumerable <string> recalculate_cells = GetCellsToRecalculate(name);
                foreach (string item in recalculate_cells)
                {
                    depends.Add(item);
                }
            }
            catch (CircularException)
            {
                spreadsheet[name].set_contents(backup_contents);
                dependency_graph.ReplaceDependees(name, backup_variables);
                throw new CircularException();
            }
            //sets the value of the cell
            IEnumerable <string> evaluate_cells = GetCellsToRecalculate(name);

            foreach (string cell in evaluate_cells)
            {
                Formula value_of_formula = (Formula)GetCellContents(cell);
                try
                {
                    spreadsheet[cell].set_value(value_of_formula.Evaluate(Lookup));
                }
                catch (ArgumentException)
                {
                }
            }
            //returns the hash set with all the dependents of name.
            return(depends);
        }
Пример #4
0
        /// <summary>
        /// Requires that all of the variables in formula are valid cell names.
        ///
        /// If name is null or invalid, throws an InvalidNameException.
        ///
        /// Otherwise, if changing the contents of the named cell to be the formula would cause a
        /// circular dependency, throws a CircularException.
        ///
        /// Otherwise, the contents of the named cell becomes formula.  The method returns a
        /// Set consisting of name plus the names of all other cells whose value depends,
        /// directly or indirectly, on the named cell.
        ///
        /// For example, if name is A1, B1 contains A1*2, and C1 contains B1+A1, the
        /// set {A1, B1, C1} is returned.
        /// </summary>
        protected override ISet <string> SetCellContents(string name, Formula formula)
        {
            // check if name is null or invalid
            if (!Regex.IsMatch(name, IsValid.ToString()) || ReferenceEquals(name, null) || !Regex.IsMatch(name, @"^[a-zA-Z_](?: [a-zA-Z_]|\d)*$"))
            {
                throw new InvalidNameException();
            }

            IEnumerable <String> dependees = dg.GetDependees(name);

            // replace dependents of name with the formula variables
            dg.ReplaceDependees(name, formula.GetVariables());

            //check if dependency graph produces circular dependency
            try
            {
                HashSet <String> hsDependees = new HashSet <String>(GetCellsToRecalculate(name));

                Cell cell = new Cell(formula);
                cell.value = formula;

                // if cell does not contain name, add new key for the value.
                // if it does contain name, then replace key with the value
                if (!cells.ContainsKey(name))
                {
                    cells.Add(name, new Cell(formula));
                }
                else
                {
                    cells[name] = new Cell(formula);
                }

                foreach (string values in new HashSet <String>(GetCellsToRecalculate(name)))
                {
                    if (!(cells[values].contents is Formula))
                    {
                        cell.value = formula.Evaluate((Lookup)LookupValue);
                    }
                    else
                    {
                        try
                        {
                            Formula f     = (Formula)cells[values].contents;
                            double  value = f.Evaluate((Lookup)LookupValue);
                            cells[values].value = value;
                        }
                        catch (Exception e)
                        {
                            cells[values].value = new FormulaError();
                        }
                    }
                }

                return(new HashSet <String>(GetCellsToRecalculate(name)));
            }
            // if exception is caught, keep old dependents
            catch (CircularException e)
            {
                dg.ReplaceDependees(name, dependees);
                throw new CircularException();
            }
        }
Пример #5
0
        /// <summary>
        /// If text is null, throws an ArgumentNullException.
        ///
        /// Otherwise, if name is null or invalid, throws an InvalidNameException.
        ///
        /// Otherwise, the contents of the named cell becomes text.  The method returns a
        /// set consisting of name plus the names of all other cells whose value depends,
        /// directly or indirectly, on the named cell.
        ///
        /// For example, if name is A1, B1 contains A1*2, and C1 contains B1+A1, the
        /// set {A1, B1, C1} is returned.
        /// </summary>
        protected override ISet <string> SetCellContents(string cell_name, string text)
        {
            string name = Normalize(cell_name);

            //if the text passed in is null this throws an ArgumentNullException();
            if (text == null)
            {
                throw new ArgumentNullException();
            }
            //checks if the name is null or invalid if so throws a new InvalidNameException();
            if (name == null || IsValid(name) == false)
            {
                throw new InvalidNameException();
            }
            else if (text.Length < 1)
            {
                return(new HashSet <string> {
                });
            }
            //checks if the cell with the name has been set up, if so this sets the contents of the cell to the text passed in.
            if (spreadsheet.ContainsKey(name))
            {
                spreadsheet[name].set_contents(text);
            }
            //if the cell hasnt been set up this creates a new cell and sets its contents to the text passed in.
            else
            {
                spreadsheet.Add(name, new Cell(name, text, text));
            }
            //creates a hash set for the return ISet.
            HashSet <string> depends = new HashSet <string> {
            };

            spreadsheet[name].set_value(text);
            //looks through each item in the dependency graph and add them to the hash set to return.
            foreach (string item in GetCellsToRecalculate(name))
            {
                depends.Add(item);
            }
            List <string> dependency_fix = new List <string> {
            };

            foreach (string value in dependency_graph.GetDependees(name))
            {
                dependency_fix.Add(value);
            }
            foreach (string key in dependency_fix)
            {
                dependency_graph.RemoveDependency(key, name);
            }
            foreach (string cell in depends)
            {
                if (!(cell == name))
                {
                    Formula value_of_formula = (Formula)GetCellContents(cell);
                    spreadsheet[cell].set_value(value_of_formula.Evaluate(Lookup));
                }
            }
            //returns the hash set with all the dependents of name.
            return(depends);
        }
Пример #6
0
 public Cell(Formula name, Func <string, double> lookup)
 {
     content     = name;
     value       = name.Evaluate(lookup);
     contentType = "Formula";
 }
        protected override ISet <string> SetCellContents(string name, Formula formula)
        {
            // Parse the formula to get the variables
            IEnumerable variables = formula.GetVariables();

            // Get features of cell prior to removing it in case there is a circular dependency
            Cell   beforeCircleCheck = new Cell();
            Object contents          = new Object();

            if (spreadsheetCells.TryGetValue(name, out beforeCircleCheck))
            {
                contents = beforeCircleCheck.cellContents;
            }

            // If the cell already exists, remove it
            if (spreadsheetCells.ContainsKey(name))
            {
                spreadsheetCells.Remove(name);
                foreach (String variable in variables)
                {
                    dependencies.RemoveDependency(name, variable);
                }
            }

            // Create new cell object
            Cell toBeAdded = new Cell();

            // Set cellName equal to name
            toBeAdded.cellName = name;
            // Set cellContents eequal to formula
            toBeAdded.cellContents = "=" + formula;
            // Set cellContentsType equal to formula
            toBeAdded.cellContentsType = "formula";

            // Add (name, cell) to spreadsheetCells dictionary
            spreadsheetCells.Add(name, toBeAdded);

            // Add to dependency Graph
            foreach (String variable in variables)
            {
                dependencies.AddDependency(name, variable);
            }

            // Check for circular dependencies. If one is found, restore origional cell
            try
            {
                GetCellsToRecalculate(name);
            }
            catch (CircularException e)
            {
                // Restore origional cell
                if (!(beforeCircleCheck == null))
                {
                    spreadsheetCells.Remove(name);
                    foreach (String var in variables)
                    {
                        dependencies.AddDependency(name, var);
                    }
                    toBeAdded.cellContents = beforeCircleCheck.cellContents;
                    spreadsheetCells.Add(name, toBeAdded);
                }
                throw e;
            }

            // Set value of cell
            try
            {
                toBeAdded.cellValue = formula.Evaluate((x) => (double)GetCellValue(x));
            }
            catch (InvalidCastException)
            {
                toBeAdded.cellValue = new FormulaError();
            }
            catch (FormulaEvaluationException)
            {
                toBeAdded.cellValue = new FormulaError();
            }

            // Get dependencies for return method call
            HashSet <String> returnValues = new HashSet <String>();
            // Call GetCellsToRecalculate for direct dependents
            IEnumerable dependents = GetCellsToRecalculate(name);

            foreach (String temp in dependents)
            {
                // Add direct dependents to returnValues
                returnValues.Add(temp);
            }

            // Call GetDependees on dependencies to get indirect dependents
            IEnumerable dependees = dependencies.GetDependees(name);

            foreach (String temp in dependees)
            {
                // Add indriect dependents to returnValues
                returnValues.Add(temp);
            }

            // Recalculate
            Cell recalculation;

            foreach (String depend in dependents)
            {
                if (spreadsheetCells.TryGetValue(depend, out recalculation))
                {
                    // Set value of cell
                    try
                    {
                        recalculation.cellValue = formula.Evaluate((x) => (double)GetCellValue(x));
                    }
                    catch (InvalidCastException)
                    {
                        recalculation.cellValue = new FormulaError();
                    }
                    catch (FormulaEvaluationException)
                    {
                        recalculation.cellValue = new FormulaError();
                    }
                }
            }

            // Change changed to true since we made a change to the spreadsheet
            Changed = true;

            // return
            return(returnValues);
        }
        protected override ISet <string> SetCellContents(string name, string text)
        {
            // Check to see if text is empty
            if (text.Equals(""))
            {
                Cell value;
                if (spreadsheetCells.TryGetValue(name, out value))
                {
                    value.cellContents = "";
                    value.cellValue    = "";

                    // Readd cell's that need to be recomputed
                    IEnumerable <String> recalc = GetCellsToRecalculate(name);
                    //recalc.Skip<String>(1);
                    Cell contents;
                    foreach (String cellNm in recalc)
                    {
                        spreadsheetCells.TryGetValue(cellNm, out contents);
                        if (contents.cellName.Equals(name))
                        {
                            continue;
                        }

                        SetContentsOfCell(cellNm, contents.cellContents.ToString());
                        String toBeAddedContents = contents.cellContents.ToString();
                    }
                }

                spreadsheetCells.Remove(name);
                return(new HashSet <String>());
            }

            // If the cell already exists, remove it
            if (spreadsheetCells.ContainsKey(name))
            {
                spreadsheetCells.Remove(name);
            }

            // Create new cell object
            Cell toBeAdded = new Cell();

            // Set cellName equal to name
            toBeAdded.cellName = name;
            // Set cellContents equal to text
            toBeAdded.cellContents = text;
            // Set cellValue equal to text
            toBeAdded.cellValue = text;
            // Set cellContentsType equal to string
            toBeAdded.cellContentsType = "string";

            // Add (name, cell) to spreadsheetCells dictionary
            spreadsheetCells.Add(name, toBeAdded);

            // Get dependencies for return method call
            HashSet <String> returnValues = new HashSet <String>();
            // Call GetCellsToRecalculate to get direct dependents
            IEnumerable dependents = GetCellsToRecalculate(name);

            foreach (String temp in dependents)
            {
                // Store direct dependents in returnValues
                returnValues.Add(temp);
            }

            // Call GetDependees on dependencies to get indirect dependents
            IEnumerable dependees = dependencies.GetDependees(name);

            foreach (String temp in dependees)
            {
                // Store indirect dependents in returnValues
                returnValues.Add(temp);
            }

            Cell recalculation;

            foreach (String depend in dependents)
            {
                if (spreadsheetCells.TryGetValue(depend, out recalculation))
                {
                    // Set value of cell
                    try
                    {
                        String equalPattern = @"^=";
                        String cellContents = recalculation.cellContents.ToString();
                        if (Regex.IsMatch(cellContents, equalPattern))
                        {
                            String  parsedContents = cellContents.Substring(1);
                            Formula f = new Formula(parsedContents);
                            recalculation.cellValue = f.Evaluate((x) => (double)GetCellValue(x));
                            //SetContentsOfCell(recalculation.cellName, recalculation.cellContents.ToString());
                        }
                    }
                    catch (InvalidCastException)
                    {
                        recalculation.cellValue = new FormulaError();
                    }
                    catch (FormulaEvaluationException)
                    {
                        recalculation.cellValue = new FormulaError();
                    }
                }
            }

            // Change changed to true since we made a change to the spreadsheet
            Changed = true;
            // return
            return(returnValues);
        }
        protected override ISet <string> SetCellContents(string name, double number)
        {
            // If the cell already exists, remove it
            if (spreadsheetCells.ContainsKey(name))
            {
                spreadsheetCells.Remove(name);
            }

            // Create new cell
            Cell toBeAdded = new Cell();

            // Set cellName equal to name
            toBeAdded.cellName = name;
            // Set cellContents equal to number
            toBeAdded.cellContents = number;
            // Set cellValue equal to number
            toBeAdded.cellValue = number;
            // Set cellContentsType equal to double
            toBeAdded.cellContentsType = "double";

            // Add (name, cell) to our spreadsheetCells dictionary
            spreadsheetCells.Add(name, toBeAdded);

            // Get dependecies for return portion of method call
            HashSet <String> returnValues = new HashSet <String>();
            // Call GetCellsToRecalculate to get direct dependents
            IEnumerable dependents = GetCellsToRecalculate(name);

            foreach (String temp in dependents)
            {
                // Add direct dependents to returnValues
                returnValues.Add(temp);
            }

            // Call GetDependees on dependencies to get indirect dependents
            IEnumerable dependees = dependencies.GetDependees(name);

            foreach (String temp in dependees)
            {
                // Add indirect dependents to returnValues
                returnValues.Add(temp);
            }

            // Recalculate
            Cell recalculation;

            foreach (String depend in dependents)
            {
                if (spreadsheetCells.TryGetValue(depend, out recalculation))
                {
                    // Set value of cell
                    try
                    {
                        String equalPattern = @"^=";
                        String cellContents = recalculation.cellContents.ToString();
                        if (Regex.IsMatch(cellContents, equalPattern))
                        {
                            String  parsedContents = cellContents.Substring(1);
                            Formula f = new Formula(parsedContents);
                            recalculation.cellValue = f.Evaluate((x) => (double)GetCellValue(x));
                            //SetContentsOfCell(recalculation.cellName, recalculation.cellContents.ToString());
                        }
                    }
                    catch (InvalidCastException)
                    {
                        recalculation.cellValue = new FormulaError();
                    }
                    catch (FormulaEvaluationException)
                    {
                        recalculation.cellValue = new FormulaError();
                    }
                }
            }

            // Change changed to true since we made a change to the spreadsheet
            Changed = true;

            // Return
            return(returnValues);
        }