Beispiel #1
0
        /// <summary>
        /// Sets the cell contents with a Formula. Throws CircularException if a circular dependency is established.
        /// </summary>
        /// <param name="name">Name of the cell to set contents inside of</param>
        /// <param name="formula">Formula to place in cell</param>
        /// <returns>ISet<string> of all the cells that need to be updated</string></returns>
        protected override ISet <string> SetCellContents(string name, SpreadsheetUtilities.Formula formula)
        {
            IEnumerable <string> variables = formula.GetVariables();

            foreach (String variable in variables)
            {
                if (!IsValid(variable))
                {
                    throw new FormulaFormatException("Invalid cell name.");
                }
                cellDependency.AddDependency(Normalize(variable), name);
            }

            try
            {
                IEnumerable <string> cellsToRecalculate = GetCellsToRecalculate(name);
            }
            //Oops there's been a circular exception, restore the dependencies
            catch (CircularException)
            {
                foreach (String variable in variables)
                {
                    cellDependency.RemoveDependency(Normalize(variable), name);
                }

                //Now that the dependencies are restored, we can throw the exception out
                throw new CircularException();
            }

            //No exception, change the cell to the formula and evaluate the formula also
            //cells[name] = new Cell(formula, formula.Evaluate(s => (double)cells[s].value));
            cells[name] = new Cell(formula, formula.Evaluate(VariableLookup));

            return(new HashSet <string>(GetCellsToRecalculate(name)));
        }
Beispiel #2
0
        /// <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>
        /// <param name="name">cellname</param>
        /// <param name="formula">content is formula</param>
        /// <returns></returns>
        protected override ISet <string> SetCellContents(string name, SpreadsheetUtilities.Formula formula)
        {
            // check check check
            //if (ReferenceEquals(formula, null)) { throw new ArgumentNullException(); }
            //if (name == null) { throw new InvalidNameException(); }
            //if (!IsValid(name)) { throw new InvalidNameException(); }

            // initialized result and tempDependent
            HashSet <string> result = new HashSet <string>();
            // store the name's Dependents in temporary hashset to prepare the circular dependency case
            HashSet <string> tempDependents = new HashSet <string>(DG.GetDependents(name));

            // this try-catch statement will check circular dependency
            try
            {
                // input the empty hashset for dependent.
                if (sheet.ContainsKey(name))
                {
                    DG.ReplaceDependents(name, new HashSet <string>());
                }
                // we have to return all veriables like set {A1, B1, C1} and store into DG
                foreach (String s in formula.GetVariables())
                {
                    DG.AddDependency(name, s);
                }
                //recalculate the cellname's contents
                result = new HashSet <string>(GetCellsToRecalculate(name));
            }
            catch (CircularException e)
            {
                //just keep tracking previous dependents..
                DG.ReplaceDependents(name, tempDependents);
                throw e;
            }

            // Now, set the sheet!
            if (sheet.ContainsKey(name))
            {
                sheet.Remove(name);     //make sure
                sheet[name] = new Cell(name, formula, lookup);
            }
            else
            {
                sheet.Add(name, new Cell(name, formula, lookup));
            }

            //update if the cell has a formula!
            foreach (String s in result)
            {
                if (sheet.ContainsKey(s) && sheet[s].getContent() is Formula)
                {
                    //For re-Evaluate
                    Cell c = new Cell(s, sheet[s].getContent(), lookup);
                    sheet.Remove(s);
                    sheet.Add(s, c);
                }// exception handle??
            }

            return(result);
        }
Beispiel #3
0
        static void Main(string[] args)
        {
            String lpPattern = @"\(";
            String rpPattern = @"\)";
            String opPattern = @"[\+\-*/]";
            String varPattern = @"[a-zA-Z_](?: [a-zA-Z_]|\d)*";
            //String doublePattern = @"(?: \d+\.\d* | \d*\.\d+ | \d+ ) (?: [eE][\+-]?\d+)?";
            String doublePattern = @"^[0-9\.]*$";
            String spacePattern = @"\s+";

            // Overall pattern
            String pattern = String.Format("({0}) | ({1}) | ({2}) | ({3}) | ({4}) | ({5})",
                                            lpPattern, rpPattern, opPattern, varPattern, doublePattern, spacePattern);

            Formula f = new Formula("2.0 + x7 + b6+9- c");
               String s = f.GetVariables().ToList().ToString();
            Debug.WriteLine(s);
        }
        /// <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 #5
0
        /// <summary>
        /// Returns the formula with all the variables replaced with their normalized counterpart.
        /// </summary>
        /// <param name="f"></param>
        /// <returns></returns>
        protected Formula NormalizeFormula(Formula f)
        {
            IEnumerable<string> e = f.GetVariables();
            foreach (string s in e)
            {
                f = new Formula(Regex.Replace(f.ToString(), s, Normalize(s)));
            }

            return f;
        }
Beispiel #6
0
        public void Test53()
        {
            Formula f = new Formula("2+X1", s => "" + s + "_", s => true);
            HashSet<string> variables = new HashSet<string> { "X1_" };


            Assert.IsTrue(variables.SetEquals(f.GetVariables()));
        }
Beispiel #7
0
 public void Test49()
 {
     Formula f = new Formula("2*X2+X2");
     List<string> actual = new List<string>(f.GetVariables());
     HashSet<string> expected = new HashSet<string>() { "X2" };
     Assert.AreEqual(actual.Count, 1);
     Assert.IsTrue(expected.SetEquals(actual));
 }
        /// <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;
        }
 public void GetVariables3()
 {
     Formula testFormula = new Formula("(3+x)*y", s => s.ToUpper(), s => (Regex.IsMatch(s, @"[A-Z]")));
     foreach (string s in testFormula.GetVariables())
         Assert.IsTrue(Regex.IsMatch(s, @"[XY]"));
 }
Beispiel #10
0
 public void PublicTestGetVariables2()
 {
     List<string> expected = new List<string>();
     expected.Add("X");
     expected.Add("Y");
     Formula f1 = new Formula("X + x + Y", s => s.ToUpper(), s => true);
     List<string> actual = new List<string>(f1.GetVariables());
     CollectionAssert.AreEqual(expected, actual);
 }
Beispiel #11
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 #12
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 (!Cell.validName(name))
            {
                throw new InvalidNameException();
            }

            HashSet<string> dependents = new HashSet<string>();
            List<string> dependentCells = GetCellsToRecalculate(name).ToList();

            // If cell doesn't exist, add it
            if (!allCells.ContainsKey(name))
            {
                allCells.Add(name, new Cell(name, number));
                foreach (string s in dependentCells)
                {
                    dependents.Add(s);
                }
                dependents.Add(name);
                return dependents;
            }

            // If cell exists, overwrite it
            Cell temp;
            if (allCells.TryGetValue(name, out temp))
            {
                string content = temp.getContents().ToString();
                temp.setContents(number);

                // remove dependencies, if they exist
                Formula f = new Formula(content);
                foreach (string s in f.GetVariables())
                {
                    if (s.Equals(name))
                    {
                        graph.RemoveDependency(name, s);
                    }
                }
            }
            // Get all dependents, indirect and direct, and then add them to a List which is then
            // added to the returned HashSet
            dependents.Add(name);
            foreach (string s in dependentCells)
            {
                dependents.Add(s);
            }
            return dependents;
        }
Beispiel #13
0
        /// <summary>
        /// sets the cell, name, to contain a specified formula
        /// </summary>
        /// <remarks>
        ///  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.
        /// circ dependency example:
        /// when setting b1 to a1
        /// a1 = b1		DG has pair (b1,a1)
        /// b1 = a1		DG can't be allowed to add(a1,b1)
        /// </remarks>
        /// <exception cref="ArgumentNullException"> If the formula parameter is null, throws an ArgumentNullException.</exception>
        /// <exception cref="InvalidNameException"> Otherwise, if name is null or invalid, throws an InvalidNameException.</exception>
        /// <exception cref="CircularException">
        /// 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.) 
        /// </exception>
        /// <returns>
        /// 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.
        /// </returns>
        protected override ISet<string> SetCellContents(string name, Formula formula)
        {
            //If the formula parameter is null, throws an ArgumentNullExceptio
            if (formula == null)
            {
                throw new ArgumentNullException();
            }
            //If name is null or invalid, throws an InvalidNameException
            if (name == null || !Regex.IsMatch(name, @"[a-zA-Z]+\d+"))
            {
                throw new InvalidNameException();
            }
            IEnumerable<string> storedDents = DG.GetDependents(name);
            DG.ReplaceDependents(name, new HashSet<string>());
            foreach (string var in formula.GetVariables())
            {
                try
                {
                    DG.AddDependency(name, var);
                }
                catch (InvalidOperationException)
                {
                    DG.ReplaceDependents(name, storedDents);
                    throw new CircularException();
                }
            }

            if (Sheet.ContainsKey(name))
                Sheet[name].Contents = formula;
            else
                Sheet.Add(name, new Cell(name, formula,lookerupper));
            foreach (string nombre in GetCellsToRecalculate(name))
            {
                //contents setter recalculates value.
                Sheet[nombre].Contents = Sheet[nombre].Contents;
            }
            Changed = true;
            HashSet<string> toreturn = new HashSet<string>(GetCellsToRecalculate(name));
            toreturn.Add(name);
            return toreturn;
        }
        /// <summary>
        /// Sets the contents of the cell. Determines whether the
        /// contents are a string, double, or formula and sets each
        /// appropriately
        /// </summary>
        /// <param name="name">Name of cell whose contents are to be set</param>
        /// <param name="content"></param>
        /// <returns></returns>
        public override ISet<string> SetContentsOfCell(string name, string content)
        {
            if (content == null)
                throw new ArgumentNullException();
            if (name == null || !IsValid(name))
                throw new InvalidNameException();
            name = removeNewLines(name);
            content = removeNewLines(content);

            name = Normalize(name);
            if(IsValid(name))
            {
                double doubleValue = 0.0;
                bool isDouble = double.TryParse(content, out doubleValue);
                HashSet<string> cellsToRecalc;

                if (isDouble)
                    cellsToRecalc = (HashSet<string>)SetCellContents(name, doubleValue);
                else if (Regex.IsMatch(content, @"[\+\-\*\/=]"))
                {
                    char[] splitFormula = content.ToCharArray();
                    string newFormula = "";
                    for (int i = 0; i < splitFormula.Length; i++)
                    {
                        if (splitFormula[i] != '=')
                            newFormula += splitFormula[i];
                    }
                    newFormula = Normalize(newFormula);
                    Formula f = new Formula(newFormula);
                    foreach (string s in f.GetVariables())
                    {
                        if (!IsValid(s))
                            throw new FormulaFormatException("One or more variables is not valid");
                    }
                    cellsToRecalc = (HashSet<string>)SetCellContents(name, f);
                }
                else
                    cellsToRecalc = (HashSet<string>)SetCellContents(name, content);
                return cellsToRecalc;
            }
            else
                throw new InvalidNameException();
        }
Beispiel #15
0
        /// <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)
        {
            //check if name is valid
            IsValidInput(name, formula);

           
            //Save state of old dependency graph
            SSCell oldCell = null;
            IEnumerable<string> oldDependees = new HashSet<string>();
            if (nameContentDict.TryGetValue(name, out oldCell))
            { 
                oldDependees = depenGraph.GetDependees(oldCell.Name);
            }
            depenGraph.ReplaceDependees(name, formula.GetVariables());

            //check for circular dependiencies
            try
            {
                //check for circular dependeinces
                ISet<string> returnSet = GetAllDepdendents(name);
                // if we get here no circular dependency was found
                AddToGraphAndDict(name, formula);

                //reevaluate all dependents
                foreach (string cellName in returnSet)
                {
                    nameContentDict[cellName].ReEvaluate(Lookup);
                }
                return returnSet;
            }
            catch (CircularException)
            {
                //restore dependecy graph
                depenGraph.ReplaceDependees(name, oldDependees);
                throw new CircularException();
            }


        }
Beispiel #16
0
        // ADDED FOR PS5
        /// <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.  There are then three possibilities:
        /// 
        ///   (1) If the remainder of content cannot be parsed into a Formula, a 
        ///       SpreadsheetUtilities.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)
        {
            //spreadsheet has been changed
            Changed = true;
            
            //check input and Normalize name
            string normalizedName = IsValidInput(name, content);

            if (content.Equals(""))
            {
                //if an empty string is recieved the graph must be updated
                if (nameContentDict.ContainsKey(name))
                {
                    //any cell that dependends on this is know a formula error
                    
                    foreach(string cell in GetAllDepdendents(name))
                    {
                        nameContentDict[cell].Value = new FormulaError();
                    }
                    depenGraph.RemoveDependency(name, content);
                    nameContentDict.Remove(name);
                }
                
                return new HashSet<string>();
            }

            //see if content is a double, if so get value return
            double d;
            if (double.TryParse(content, out d))
            {
                //add to dependen graph and name, cell to the Dcitonary, return dependents
                return SetCellContents(normalizedName, d);
            }
            //if is it a formula
            else if (content[0] == '=')
            {
                //get the rest of the string after the "="//double check off by one error here
                string formulaString = content.Substring(1, content.Length - 1);
                Formula formula;
                try
                {
                    formula = new Formula(formulaString, Normalize, IsValid);
                    //PS3 has different requirments for variables so check new standards here
                    foreach( string str in formula.GetVariables())
                        IsValidName(str);
                    //add to dependen graph and name, cell to the Dcitonary, return dependents
                    return SetCellContents(normalizedName, formula);
                }
                //catch the invalid name exception
                catch (InvalidNameException) { throw new FormulaFormatException("bad formula"); }
            
            }
            else
                //it is a string, add to dependen graph and name, cell to the Dcitonary, return dependents
                return SetCellContents(normalizedName, content);
        }
Beispiel #17
0
        /// <summary>
        /// If name is null, throws an ArgumentNullException.
        /// 
        /// Otherwise, if name isn't a valid cell name, throws an InvalidNameException.
        /// 
        /// Otherwise, returns an enumeration, without duplicates, of the names of all cells whose
        /// values depend directly on the value of the named cell.  In other words, returns
        /// an enumeration, without duplicates, of the names of all cells that contain
        /// formulas containing name.
        /// 
        /// For example, suppose that
        /// A1 contains 3
        /// B1 contains the formula A1 * A1
        /// C1 contains the formula B1 + A1
        /// D1 contains the formula B1 - C1
        /// The direct dependents of A1 are B1 and C1
        /// </summary>
        protected override IEnumerable<string> GetDirectDependents(string name)
        {
            if (name == null)
            {
                throw new ArgumentNullException();
            }

            if (!Cell.validName(name))
            {
                throw new InvalidNameException();
            }

            // Loop over every cell in spreadsheet, checking for dependents of name by looking for
            // cells that contain name
            HashSet<string> dependents = new HashSet<string>();
            foreach (KeyValuePair<string, Cell> kvp in allCells)
            {
                // Turn name into a string, convert to a formula and call get variables on the formula
                // if there are variables in the formula (the contents of the cell) and one of those
                // variables is name, add the name of the cell that contains name to the dependents list
                if (kvp.Value.getContents() is Formula)
                {
                    string content = kvp.Value.getContents().ToString();
                    Formula f = new Formula(content, Normalize, IsValid);
                    foreach (string str in f.GetVariables())
                    {
                        if (str.Equals(name))
                        {
                            dependents.Add(kvp.Key);
                        }
                    }
                }
            }
            return dependents;
        }
        /// <summary>
        /// Verifies that no circular exception will be created and then sends CHANGE request to server.
        /// </summary>
        /// <param name="name">The cell to be changed</param>
        /// <param name="content">The candidate contents of the cell</param>
        public void Change(string name, string content)
        {
            // If we're waiting for a change to be confirmed by the server, don't take a new change.
            if (_currentChangeCell != null)
            {
                return;
            }
            var normalizedName = Normalize(name);

            // Check if content is null.
            if (content == null)
            {
                throw new ArgumentNullException();
            }
            // Check if name is null or invalid.
            if (normalizedName == null || !_validCellNameRegex.IsMatch(normalizedName) || !IsValid(normalizedName))
            {
                throw new InvalidNameException();
            }
            if (content.StartsWith("="))
            {
                Formula formula = new Formula(content.Substring(1), IsValid, Normalize);

                // The HashSet dependents contains name and all of name's direct and indirect dependents.
                var dependents = new HashSet<string>(GetCellsToRecalculate(normalizedName));

                // Variables contains name's new dependees.
                var variables = formula.GetVariables();

                // Checking if any of name's new dependees are already its dependents
                // or if name is its own new dependee.
                if (dependents.Overlaps(variables))
                {
                    throw new CircularException();
                }
            }
            _currentChangeCell = normalizedName;
            _currentChangeContent = content;
            _socket.BeginSend("CHANGE\n" + _name + "\n" + _version + "\nCell:" + normalizedName + "\nLength:" + content.Length.ToString() + "\n" + content + "\n", (e, o) => { }, null);
        }
Beispiel #19
0
 public void GetVariables1()
 {
     Formula testFormula = new Formula("(3+x)*y");
     foreach (string s in testFormula.GetVariables())
         Assert.IsTrue(Regex.IsMatch(s, @"[xy]"));
 }
        /// <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)
        {
            // Normaling name.
            var normalizedName = Normalize(name);
            if (formula == null)
            {
                throw new ArgumentNullException();
            }
            if (normalizedName == null || !_validCellNameRegex.IsMatch(normalizedName) || !IsValid(normalizedName))
            {
                throw new InvalidNameException();
            }

            var cellsToRecalculate = GetCellsToRecalculate(normalizedName);
            var localCellsToRecalculate = cellsToRecalculate as string[] ?? cellsToRecalculate.ToArray();

            _cells[normalizedName] = new Cell(formula);

            // Replacing name's dependees.
            _dependencies.ReplaceDependees(normalizedName, formula.GetVariables());

            // Updating values (in order) of each affected cell.
            RecalculateCellValues(localCellsToRecalculate);

            Changed = true;
            return new HashSet<string>(localCellsToRecalculate);
        }
        /// <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 #22
0
        public void GetVariables2()
        {
            Formula testFormula = new Formula("(3+x)*y+x");
            int i = 0;
            foreach (string s in testFormula.GetVariables()){
                i++;
                Assert.IsTrue(Regex.IsMatch(s, @"[xy]"));
            }
            Assert.AreEqual(2, i);

        }
Beispiel #23
0
 public void GetVariablesTest2()
 {
     Formula f1 = new Formula("X+y+z+2");
     foreach (string var in f1.GetVariables())
     {
         Assert.IsTrue(Regex.IsMatch(var, @"[Xyz]"));
     }
 }
Beispiel #24
0
 public void GetVariables4()
 {
     Formula testFormula = new Formula("a1+b2*c3+d4/A2-Z7+a1/y8");
     List<string> variables = new List<string>(testFormula.GetVariables());
     HashSet<string> expected = new HashSet<string>() { "a1", "b2", "c3", "d4", "A2", "Z7", "y8" };
     Assert.AreEqual(variables.Count, 7);
     Assert.IsTrue(expected.SetEquals(variables));
 }
Beispiel #25
0
 public void GetVariablesTest3()
 {
     Formula f1 = new Formula("X+y+z+2",s=>s.ToUpper(),s=>(Regex.IsMatch(s,@"[A-Z]")));
     foreach (string var in f1.GetVariables())
     {
         Assert.IsTrue(Regex.IsMatch(var, @"[XYZ]"));
     }
 }
Beispiel #26
0
 public void Test46()
 {
     Formula f = new Formula("2*5");
     Assert.IsFalse(f.GetVariables().GetEnumerator().MoveNext());
 }
Beispiel #27
0
 public void GetVariablesTest4()
 {
     Formula f1 = new Formula("X+y+z+X+X");
     int i=0;
     foreach (string var in f1.GetVariables())
     {
         i++;
         Assert.IsTrue(Regex.IsMatch(var, @"[Xyz]"));
     }
     Assert.AreEqual(3, i);
 }
Beispiel #28
0
 public void Test50()
 {
     Formula f = new Formula("X1+Y2*X3*Y2+Z7+X1/Z8");
     List<string> actual = new List<string>(f.GetVariables());
     HashSet<string> expected = new HashSet<string>() { "X1", "Y2", "X3", "Z7", "Z8" };
     Assert.AreEqual(actual.Count, 5);
     Assert.IsTrue(expected.SetEquals(actual));
 }
Beispiel #29
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 name, string text)
        {
            if (text == null)
            {
                throw new ArgumentNullException();
            }

            if (!Cell.validName(name) || !IsValid(name))
            {
                throw new InvalidNameException();
            }

            // If cell doesn't exist, add it
            if (!allCells.ContainsKey(name))
            {
                allCells.Add(name, new Cell(name, text));
                isChanged = true;

                // Get all dependents, indirect and direct, and then add them to a List which is then
                // added to the returned HashSet
                HashSet<string> dependents = new HashSet<string>();
                List<string> dependentCells = GetCellsToRecalculate(name).ToList();

                dependents.Add(name);
                foreach (string str in dependentCells)
                {
                    allCells[str].eval(Lookup);
                    dependents.Add(str);
                }
                return dependents;
            }

            // If cell exists, overwrite it's content           
            Cell temp;
            if (allCells.TryGetValue(name, out temp))
            {
                string content = temp.getContents().ToString();
                temp.setContents(text);
                Formula f = new Formula(content);
                foreach (string str in f.GetVariables())
                {
                    if (str.Equals(name))
                    {
                        graph.RemoveDependency(name, str);
                    }
                }
            }

            // Get all dependents, indirect and direct, and then add them to a List which is then
            // added to the returned HashSet
            HashSet<string> dependent = new HashSet<string>();
            List<string> dependentCell = GetCellsToRecalculate(name).ToList();
            dependent.Add(name);
            foreach (string str in dependentCell)
            {
                allCells[str].eval(Lookup);
                dependent.Add(str);
            }
            return dependent;
        }
Beispiel #30
0
        /// <summary>
        /// An implementation of the abstract method in AbstractSpreadsheet.
        /// <seealso cref="AbstractSpreadsheet.SetContentsOfCell"/>
        /// </summary>
        /// <param name="name"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        public override ISet<string> SetContentsOfCell(string name, string content)
        {
            // Private Variable
            ISet<string> set;

            // If content is null, throws an ArgumentNullException.
            // Otherwise, if name is null or invalid, throws an InvalidNameException.
            name = CorrectInput(name, content);

            // Otherwise, if content parses as a double, the contents of the named
            // cell becomes that double.
            double d;
            if (Double.TryParse(content, out d))
                set = SetCellContents(name, d);

            // 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.
            else if (content.Length > 0 && content[0] == '=')
            {
                // There are then three possibilities:
                //   (1) If the remainder of content cannot be parsed into a Formula, a
                //       SpreadsheetUtilities.FormulaFormatException is thrown.
                //       Be sure to check the validity of and normalize any variables.
                //   (2) Otherwise, if changing the contents of the named cell to be f
                //       would cause a circular dependency, a CircularException is thrown.
                Formula f = new Formula(content.Substring(1));
                f = NormalizeFormula(f);
                try
                {
                    foreach (string v in f.GetVariables())
                        CorrectInput(v);
                }
                catch (InvalidNameException)
                {
                    throw new FormulaFormatException(
                        String.Format("One or more variables in the formula '{0}' contained in cell {1} aren't valid.", f.ToString(), name));
                }

                //   (3) Otherwise, the contents of the named cell becomes f.
                set = SetCellContents(name, f);
            }

            // Otherwise, the contents of the named cell becomes content.
            else
                set = SetCellContents(name, content);

            // Recalculate the values of any cell dependent on the named cell, including the named cell itself.
            CalculateCellValues(name);

            //Remove any name associations to cell, reset to how it was before the cell was added.
            if (content == "")
            {
                cells.Remove(name);
            }

            // 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.
            return set;
        }
Beispiel #31
0
        /// <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)
        {
            // If the formula parameter is null, throws an ArgumentNullException.
            if (formula.Equals(null))
            {
                throw new ArgumentNullException();
            }

            // Otherwise, if name is null or invalid, throws an InvalidNameException.
            if (!Cell.validName(name) || !IsValid(name))
            {
                throw new InvalidNameException();
            }

            // If cell doesn't exist, add it
            if (!allCells.ContainsKey(name))
            {
                // add new cell
                allCells.Add(name, new Cell(name, formula, Lookup));
                // if formula contained variables, setup new dependencies
                if (formula.GetVariables().Count() > 0)
                {
                    foreach (string str in formula.GetVariables())
                    {
                        graph.AddDependency(name, str);
                    }
                }
                HashSet<string> dependents = new HashSet<string>();
                List<string> dependentCells = GetCellsToRecalculate(name).ToList();

                dependents.Add(name);
                foreach (string str in dependentCells)
                {
                    allCells[str].eval(Lookup);
                    dependents.Add(str);
                }
                return dependents;

            }

            // 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.)
            GetCellsToRecalculate(name);

            // Otherwise, the contents of the named cell becomes formula.
            // If cell exists, overwrite it's content
            Cell temp;
            if (allCells.TryGetValue(name, out temp))
            {
                temp.setContents(formula);
                
            }

            // If the replacement formula has variables, replace the dependency of the old cell with 
            // new ones from the new formula.
            if (formula.GetVariables().Count() > 0)
            {
                List<string> variables = new List<string>();
                foreach (string str in formula.GetVariables())
                {
                    variables.Add(str);
                }
                graph.ReplaceDependents(name, variables);
            }

            // Get all dependents, indirect and direct, and then add them to a List which is then
            // added to the returned HashSet
            HashSet<string> dependent = new HashSet<string>();
            List<string> dependentCell = GetCellsToRecalculate(name).ToList();
            dependent.Add(name);
            foreach (string str in dependentCell)
            {
                allCells[str].eval(Lookup);
                dependent.Add(str);
            }
            return dependent;
        }
Beispiel #32
0
        /// <summary>
        /// An implementation of the abstract method in AbstractSpreadsheet.
        /// <seealso cref="AbstractSpreadsheet.SetCellContents(String, Formula)"/>
        /// </summary>
        /// <param name="name"></param>
        /// <param name="formula"></param>
        /// <returns></returns>
        protected override ISet<String> SetCellContents(String name, Formula formula)
        {
            // If formula parameter is null, throws an ArgumentNullException.
            // Otherwise, if name is null or invalid, throws an InvalidNameException.
            name = CorrectInput(name, formula);
            formula = NormalizeFormula(formula);

            // Otherwise, if changing the contents of the named cell to be the formula would cause a
            // circular dependency, throws a CircularException.
            IEnumerable<string> previous = dependencies.GetDependees(name);
            try
            {
                dependencies.ReplaceDependees(name, formula.GetVariables());
                GetCellsToRecalculate(name);
            }
            catch (CircularException)
            {
                dependencies.ReplaceDependees(name, previous);
                throw new CircularException();
            };

            //foreach (string v in formula.GetVariables())
            //    foreach (string d in GetCellsToRecalculate(v))
            //        if (name.Equals(d))
            //        {
            //            dependencies.ReplaceDependees(name, previous);
            //            throw new CircularException();
            //        }

            // Otherwise, the contents of the named cell becomes formula.
            Changed = true;
            GetCell(name).Contents = 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.
            return new HashSet<string>(GetCellsToRecalculate(name));
        }
        /// <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);
        }