Beispiel #1
0
 /// <summary>
 /// Evaluates a set of cells in the order they appear.
 /// </summary>
 /// <param name="cellNames">Set of cells to be evaluated.</param>
 private void EvaluateCells(HashSet<string> cellNames)
 {
     foreach (string name in cellNames)
     {
         Cell outCell = new Cell();
         if (!cells.TryGetValue(name, out outCell))
         {
             continue;
         }
         if (outCell.Content is string || outCell.Content is double)
             return;
         Formula formula = (Formula)outCell.Content;
         outCell.Value = formula.Evaluate(GetValue);
     }
 }
Beispiel #2
0
        // MODIFIED PROTECTION FOR PS5
        /// <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 name, string text)
        {
            if (text == null)
                throw new ArgumentNullException();
            CheckValidCellName(name);
            if (text == "")
            {
                HashSet<string> recalculate = new HashSet<string>(GetCellsToRecalculate(name));
                dependencies.ReplaceDependees(name, new List<string>());
                cells.Remove(name);
                return recalculate;

            }
            Cell outCell = new Cell();
            if (cells.TryGetValue(name, out outCell))
            {
                cells[name].Content = text;
                dependencies.ReplaceDependees(name, new List<string>());
            }
            else
            {
                cells.Add(name, new Cell(name, text, text));
            }

            Changed = true;

            return new HashSet<string>(GetCellsToRecalculate(name));
        }
Beispiel #3
0
        // MODIFIED PROTECTION FOR PS5
        /// <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 name, Formula formula)
        {
            if (formula == null)
                throw new ArgumentException();
            CheckValidCellName(name);

            bool originalChangedState = Changed;
            List<string> origDeps = dependencies.GetDependees(name).ToList();
            Dictionary<string, Cell> origCells = new Dictionary<string, Cell>();
            for (int i = 0; i < cells.Count; i++)
            {
                origCells.Add(cells.ElementAt(i).Key, cells.ElementAt(i).Value.Clone());
            }

            Cell getCell = new Cell();
            if (cells.TryGetValue(name, out getCell))
            {
                cells[name].Content = formula;
                cells[name].Value = null;
            }
            else
            {
                cells.Add(name, new Cell(name, formula, null));
            }
            dependencies.ReplaceDependees(name, formula.GetVariables());
            try
            {
                Changed = true;
                return new HashSet<string>(GetCellsToRecalculate(name));
            }
            catch (CircularException)
            {
                Changed = originalChangedState;
                dependencies.ReplaceDependees(name, origDeps);
                cells = origCells;
                throw new CircularException();
            }
        }
Beispiel #4
0
 // ADDED FOR PS5
 /// <summary>
 /// If name is null or invalid, throws an InvalidNameException.
 /// 
 /// Otherwise, returns the value (as opposed to the contents) of the named cell.  The return
 /// value should be either a string, a double, or a SpreadsheetUtilities.FormulaError.
 /// </summary>
 public override object GetCellValue(string name)
 {
     name = Normalize(name);
     CheckValidCellName(name);
     Cell c = new Cell();
     if (cells.TryGetValue(name, out c))
         return c.Value;
     return "";
 }
Beispiel #5
0
        // MODIFIED PROTECTION FOR PS5
        /// <summary>
        /// If name is null or invalid, throws an InvalidNameException.
        /// 
        /// Otherwise, the contents of the named cell becomes number.  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, double number)
        {
            CheckValidCellName(name);
            Cell outCell = new Cell();
            if (cells.TryGetValue(name, out outCell))
            {
                cells[name].Content = number;
                dependencies.ReplaceDependees(name, new List<string>());
            }

            else
            {
                cells.Add(name, new Cell(name, number, number));
            }

            Changed = true;

            return new HashSet<string>(GetCellsToRecalculate(name));
        }
        /// <summary>
        /// Takes in a cell name and a formula and returns the dependents
        /// Calculates the value of the formula then recalculates the value of any cell that depends directly or inderectly on it.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="formula"></param>
        /// <returns></returns>
        protected override ISet<string> SetCellContents(string name, Formula formula)
        {
            name = Normalize(name);
            HashSet<string> mySet = new HashSet<string>();
            HashSet<string> replaceSet = new HashSet<string>();

            if (Object.ReferenceEquals(formula, null))
            {
                throw new ArgumentNullException();
            }
            if (Object.ReferenceEquals(name, null))
            {
                throw new InvalidNameException();
            }
            if (!Regex.IsMatch(name, "^([a-z]|[A-Z])+\\d+$") | !IsValid(name))
            {
                throw new InvalidNameException();
            }
            try
            {

                foreach (string s in formula.GetVariables())
                {

                    replaceSet.Add(s);
                }

                // dependentCells.ReplaceDependees(name, mySet);
                dependentCells.ReplaceDependees(name, replaceSet);
                GetCellsToRecalculate(name);
            }
            catch (CircularException)
            {
                throw new CircularException();
            }
            Formula myEvl = new Formula(formula.ToString(), IsValid, Normalize);
            myCell = new Cell(formula, myEvl.Evaluate(myLookup));
            if (mySpreadsheet.ContainsKey(name))
            {
                mySpreadsheet[name] = myCell;
            }
            else
            {
                mySpreadsheet.Add(name, myCell);
            }
            mySet.Add(name);
            foreach (string s in GetCellsToRecalculate(name))
            {
                mySet.Add(s);
            }
            foreach (string s in mySet)
            {
                myCell = new Cell(GetCellContents(s), myEvaluate(s));
                mySpreadsheet[s] = myCell;
            }
            Changed = true;
            return mySet;
        }
        /// <summary>
        /// If name is invalid or null, throws InvalidNameException.
        /// contents of the named cell become a string.
        /// 
        /// 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>
        /// <param name="name"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        protected override ISet<string> SetCellContents(string name, string text)
        {
            //Replacing cell name with new content and value.
            cells[name] = new Cell(name, text, text);

            //spreadsheet has changed
            Changed = true;

            //recalculates all dependees of name.
            recalculateDependees(name, (LinkedList<string>)GetCellsToRecalculate(name));

            //remove all dependencies of name, since name is now a text cell and not a Formula.
            foreach (string el in dependencies.GetDependents(name))
            {
                dependencies.RemoveDependency(name, el);
            }

            //grabs name and dependees(indirect and direct) of name, puts them into a HashSet and returns them.
            return new HashSet<string>(GetCellsToRecalculate(name));
        }
        /// <summary>
        /// If the 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.  (No change is made to the spreadsheet.)
        /// 
        /// 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)
        {

            IEnumerable<String> dependee_list = dependency_graph.GetDependees(name);
            dependency_graph.ReplaceDependees(name, formula.GetVariables());

            try
            {
                HashSet<String> all_dependees = new HashSet<String>(GetCellsToRecalculate(name));

                if (cell.ContainsKey(name))
                {
                    cell[name] = new Cell(formula, LookupValue);
                }
                else
                {
                    cell.Add(name, new Cell(formula, LookupValue));
                }

                return all_dependees;
            }

            catch (CircularException)
            {
                dependency_graph.ReplaceDependees(name, dependee_list);
                throw new CircularException();
            }
        }
Beispiel #9
0
        // MODIFIED PROTECTION FOR PS5
        /// <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 name, SpreadsheetUtilities.Formula formula)
        {
            if (formula == null)
                throw new ArgumentNullException("Error: Formula paramter was null.");

            // Checks if cell name is valid and not null
            if (name == null || !ValidName(name))
                throw new InvalidNameException();

            List<string> cellNames = new List<string>();
            Cell cellValue;

            // Holds the cell names that will be returned
            HashSet<string> result = new HashSet<string>();

            // Holds the contents of the original cell
            object o = null;

            if (cells.ContainsKey(name)) {
                o = cells[name].Content;
                RemoveDependency(name);
            }

            // Save the content of the cell to store in the dictionary
            cellValue = new Cell(formula, GetCell);
            cells.Add(name, cellValue);

            // cellNames gets a list of all of the cell names in the formula and creates a list
            // to add to the dependency graph
            cellNames = formula.GetVariables().ToList();

            // Add the values associated to name to the dependency graph
            foreach (string n in cellNames) {
                dg.AddDependency(name, n);
            }

            try {
                //saves the direct and indirect values into tempI and then put them into my returnSet
                //also checks for circular dependency and recalculates the values in the cells associate with the name
                IEnumerable<string> tempI = GetCellsToRecalculate(name);//recalculates the values and checks for circular dependency
                foreach (string n in tempI)
                    result.Add(n);
            }
            catch (CircularException c) {

                //method comes here if a circularexeption is found when calling the GetCellsToRecalculate method
                //originalCellContent is saved earlier in the code to allow us to go back to the original values to get
                //rid of the circular dependency
                if (o != null) {
                    if (o is Formula) {
                        Formula originalFormula = new Formula(o.ToString());

                        SetCellContents(name, originalFormula);
                    }
                    else if (o is String) {
                        SetCellContents(name, o.ToString());
                    }
                    else if (o is double) {
                        SetCellContents(name, Convert.ToDouble(o));
                    }
                }
                else
                    SetCellContents(name, "");
                throw c;
            }
            return result;
        }
        /// <summary>
        /// If name is null or invalid, throws an InvalidNameException.
        /// 
        /// Otherwise, the contents of the named cell becomes number.  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.
        protected override ISet<string> SetCellContents(string name, double number)
        {

            if (cell.ContainsKey(name))
            {
                cell[name] = new Cell(number);
            }
            else
            {
                cell.Add(name, new Cell(number));
            }

            dependency_graph.ReplaceDependees(name, new HashSet<String>());
            HashSet<String> dependees = new HashSet<string>(GetCellsToRecalculate(name));
            return dependees;
        }
        /// <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.
        protected override ISet<string> SetCellContents(string name, string text)
        {

            if (cell.ContainsKey(name))
            {
                cell[name] = new Cell(text);
            }
            else
            {
                cell.Add(name, new Cell(text));
            }
            string cell_content = (String)cell[name].contents;

            if (cell_content.Equals(""))
                cell.Remove(name);

            dependency_graph.ReplaceDependees(name, new HashSet<String>());

            HashSet<String> dependees = new HashSet<string>(GetCellsToRecalculate(name));
            return dependees;
        }
Beispiel #12
0
        /// <summary>
        /// If name is null or invalid, throws an InvalidNameException.
        /// 
        /// Otherwise, returns the contents (as opposed to the value) of the named cell.  The return
        /// value should be either a string, a double, or a Formula.
        /// </summary>
        public override object GetCellContents(string name)
        {
            if (!CheckValidCellName(name))
                throw new InvalidNameException();

            Cell getContent = new Cell();
            if (cells.TryGetValue(name, out getContent))
            {
                return getContent.Content;
            }

            return "";
        }
Beispiel #13
0
        /// <summary>
        /// If name is null or invalid, throws an InvalidNameException.
        /// 
        /// Otherwise, the contents of the named cell becomes number.  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> SetCellContents(string name, double number)
        {
            if (!CheckValidCellName(name))
                throw new InvalidNameException();
            Cell outCell = new Cell();
            if (cells.TryGetValue(name, out outCell))
            {
                cells[name].Content = number;
                dependencies.ReplaceDependees(name, new List<string>());
            }

            else
            {
                cells.Add(name, new Cell(name, number, number));
            }

            return new HashSet<string>(GetCellsToRecalculate(name));
        }
        /// <summary>
        /// If the formula parameter is null, throws an ArgumentNullException.
        /// 
        /// Otherwise, if name is null or invalid, throws an InvalidNameException.
        /// 
        /// contents of the named cell become a 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>
        /// <param name="name"></param>
        /// <param name="formula"></param>
        /// <returns></returns>
        protected override ISet<string> SetCellContents(string name, Formula formula)
        {
            LinkedList<string> cellsToRecalc;
            cellsToRecalc = (LinkedList<string>)GetCellsToRecalculate(name);

            //Testing for CircularExceptions, does not affect cells so no need to backup old cell.
            foreach (string el in cellsToRecalc)
            {
                if (formula.GetVariables().Contains(el))
                    throw new CircularException();
            }

            //Replacing cell name with new content and value.
            try
            {
                cells[name] = new Cell(name, formula, formula.Evaluate(lookup));
            }
            catch (System.ArgumentException e)
            {
                cells[name] = new Cell(name, formula, new FormulaError());
            }

            //spreadsheet has changed
            Changed = true;

            //recalculates the dependees of name.
            recalculateDependees(name, cellsToRecalc);

            //replace all dependents of name with new formulas variables.
            dependencies.ReplaceDependents(name, formula.GetVariables());

            //grabs name and dependees(direct and indirect) of name and puts them into a HashSet and returns them.
            return new HashSet<string>(cellsToRecalc);
        }
Beispiel #15
0
 /// <summary>
 /// This provides a function to be used as a lookup function for the evaluator.
 /// </summary>
 /// <param name="s">Returns a value associated with a cell</param>
 /// <returns></returns>
 private double GetValue(string s)
 {
     Cell c = new Cell();
     if (!cells.TryGetValue(s, out c))
         throw new ArgumentException();
     if (!(c.Value is double))
         throw new ArgumentException();
     return (double)c.Value;
 }
Beispiel #16
0
 public void CellConstructorTest()
 {
     Cell target = new Cell(22,22);
     Assert.AreEqual(22, target.getContents());
     Assert.AreEqual(22, target.getValue());
 }
        /// <summary>
        /// Takes in a cell name and the text of a cell and returns dependents and sets cell value
        /// </summary>
        /// <param name="name"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        protected override ISet<string> SetCellContents(string name, string text)
        {
            name = Normalize(name);
            HashSet<string> mySet = new HashSet<string>();
            HashSet<string> replaceSet = new HashSet<string>();
            myCell = new Cell(text, text);

            if (Object.ReferenceEquals(text, null))
            {
                throw new ArgumentNullException();
            }
            if (text == "")
            {
                if (mySpreadsheet.ContainsKey(name))
                {
                    mySpreadsheet[name] = myCell;
                }
                return mySet;
            }
            if (Object.ReferenceEquals(name, null))
            {
                throw new InvalidNameException();
            }
            if (!Regex.IsMatch(name, "^([a-z]|[A-Z])+\\d+$") | !IsValid(name))
            {
                throw new InvalidNameException();
            }
            if (mySpreadsheet.ContainsKey(name))
            {
                mySpreadsheet[name] = myCell;

            }
            else
            {
                mySpreadsheet.Add(name, myCell);
            }
            mySet.Add(name);
            dependentCells.ReplaceDependees(name, replaceSet);
            foreach (string s in GetCellsToRecalculate(name))
            {
                mySet.Add(s);
            }
            foreach (string s in mySet)
            {
                if (s == name)
                {
                    mySpreadsheet[s] = myCell;
                }
                else
                {
                    myCell = new Cell(GetCellContents(s), myEvaluate(s));
                    mySpreadsheet[s] = myCell;
                }

            }
            Changed = true;
            return mySet;
        }
Beispiel #18
0
        /// <summary>
        /// If name is null or invalid, throws an InvalidNameException.
        /// 
        /// Otherwise, returns the contents (as opposed to the value) of the named cell.  The return
        /// value should be either a string, a double, or a Formula.
        /// </summary>
        public override object GetCellContents(string name)
        {
            name = Normalize(name);
            CheckValidCellName(name);

            Cell getContent = new Cell();
            if (cells.TryGetValue(name, out getContent))
            {
                return getContent.Content;
            }

            return "";
        }
Beispiel #19
0
        /// <summary>
        /// Returns the cell associated to name. If there is no cell associated with name, returns null.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        protected Cell GetCell(string name)
        {
            name = CorrectInput(name);
            //Checks to see if there's a cell associated with name. If not, creates an empty cell and associates to name.
            if (!cells.ContainsKey(name))
            {
                cells[name] = new Cell("", "");
            }

            //Gets the cell associated with name.
            return cells[name];
        }
        /// <summary>
        /// If name is invalid or null, throws InvalidNameException.
        /// contents of the named cell become a double.
        /// 
        /// 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>
        /// <param name="name"></param>
        /// <param name="number"></param>
        /// <returns></returns>
        protected override ISet<string> SetCellContents(string name, double number)
        {
            //adds new cell "name". Parsing double to correct formatting. 5.0000 == 5.0
            cells[name] = new Cell(name, number, double.Parse(number.ToString()));
            Changed = true;

            //fixes all dependees of name
            recalculateDependees(name, (LinkedList<string>)GetCellsToRecalculate(name));

            //removes all dependents of name since name isnt a formula
            foreach (string el in dependencies.GetDependents(name))
            {
                dependencies.RemoveDependency(name, el);
            }

            //grabs name and dependees(direct and indirect) of name, puts them into a HashSet and returns them.
            return new HashSet<string>(GetCellsToRecalculate(name));
        }