public static DataTranslator LoadTranslatorFromFile(string FileToLoad = "translator.trs")
        {
            if (File.Exists(FileToLoad))
            {
                Dictionary <string, AttributeInfoBase> attributeInfos = new Dictionary <string, AttributeInfoBase>();
                using (XmlReader reader = XmlReader.Create(FileToLoad))
                {
                    reader.MoveToContent();
                    reader.MoveToContent();
                    reader.Read();
                    reader.Read();
                    reader.Read();

                    string currentKey = "";

                    while (!reader.EOF)
                    {
                        while (reader.Name != "key" && !reader.EOF)
                        {
                            reader.Read();
                        }
                        if (reader.EOF)
                        {
                            break;
                        }

                        reader.Read();
                        currentKey = reader.ReadContentAsString();
                        reader.MoveToContent();

                        while (reader.Name != "value")
                        {
                            reader.Read();
                        }
                        reader.Read();
                        reader.Read();
                        string type = reader.Name;

                        AttributeInfoBase thisAttributeInfo;
                        switch (type)
                        {
                        case "AttributeInfoBoolean":
                            thisAttributeInfo = new AttributeInfoBoolean(currentKey);
                            break;

                        case "AttributeInfoEnumerated":
                            thisAttributeInfo = new AttributeInfoEnumerated(currentKey, new string[0]);
                            break;

                        case "AttributeInfoNumeric":
                            thisAttributeInfo = new AttributeInfoNumeric(currentKey, 0, 0);
                            break;

                        default:
                            throw new Exception("Incorrect attribute type.");
                        }
                        using (XmlReader subReader = reader.ReadSubtree())
                        {
                            thisAttributeInfo.ReadXml(subReader);
                        }
                        attributeInfos.Add(thisAttributeInfo.AttributeName, thisAttributeInfo);
                    }
                }
                return(new DataTranslator()
                {
                    attributeInfo = attributeInfos
                });
            }
            else
            {
                throw new Exception("File does not exist: " + FileToLoad);
            }
        }
        public void CreateOrUpdateTranslator(DataWarehouse InputWH)
        {
            foreach (string attribute in InputWH.Attributes)
            {
                if (attribute != InputWH.ClassificationAttribute && attribute != InputWH.IDAttribute)
                {
                    if (!attributeInfo.ContainsKey(attribute))
                    {
                        string[] uniqueValues = InputWH.GetRecords().Select(r => r.GetAttributeValue(attribute)).Distinct().ToArray();
                        //Check if boolean
                        if (uniqueValues.Count() == 2)
                        {
                            if (uniqueValues.Contains("True") && uniqueValues.Contains("False"))
                            {
                                attributeInfo.Add(attribute, new AttributeInfoBoolean(attribute, "true", "false"));
                            }
                            if (uniqueValues.Contains("true") && uniqueValues.Contains("false"))
                            {
                                attributeInfo.Add(attribute, new AttributeInfoBoolean(attribute));
                            }
                            else if (uniqueValues.Contains("Yes") && uniqueValues.Contains("No"))
                            {
                                attributeInfo.Add(attribute, new AttributeInfoBoolean(attribute, "Yes", "No"));
                            }
                            else if (uniqueValues.Contains("yes") && uniqueValues.Contains("no"))
                            {
                                attributeInfo.Add(attribute, new AttributeInfoBoolean(attribute, "yes", "no"));
                            }
                        }
                        if (!attributeInfo.ContainsKey(attribute))
                        {
                            //Check if all values can be made numeric.
                            if (uniqueValues.Where(v => !decimal.TryParse(v, out decimal dummy)).Count() == 0)
                            {
                                decimal[] uniqueDecimals = Array.ConvertAll(uniqueValues, s => decimal.Parse(s));
                                decimal   min            = uniqueDecimals.Min();
                                decimal   max            = uniqueDecimals.Max();
                                attributeInfo.Add(attribute, new AttributeInfoNumeric(attribute, min, max));
                            }
                            else //Must be enum
                            {
                                attributeInfo.Add(attribute, new AttributeInfoEnumerated(attribute, uniqueValues.ToArray()));
                            }
                        }
                    }
                    else
                    {
                        if (attributeInfo[attribute].AttributeType == EAttributeType.Enumerated)
                        {
                            string[] suppliedPrecedence       = ((AttributeInfoEnumerated)attributeInfo[attribute]).ValuePrecedence;
                            string[] suppliedPrecedenceSorted = new string[suppliedPrecedence.Length];
                            Array.Copy(suppliedPrecedence, suppliedPrecedenceSorted, suppliedPrecedence.Length);
                            Array.Sort(suppliedPrecedenceSorted);

                            string[] uniqueValues = InputWH.GetRecords().Select(r => r.GetAttributeValue(attribute)).Distinct().ToArray();
                            Array.Sort(uniqueValues);

                            if (!suppliedPrecedenceSorted.SequenceEqual(uniqueValues))
                            {
                                IEnumerable <string> removedValues = suppliedPrecedence.Where(v => !uniqueValues.Contains(v));
                                IEnumerable <string> newValues     = uniqueValues.Where(v => !suppliedPrecedence.Contains(v));

                                List <string> newPrecedenceList = new List <string>();
                                newPrecedenceList.AddRange(suppliedPrecedence);
                                newPrecedenceList.AddRange(newValues);
                                foreach (string s in removedValues)
                                {
                                    newPrecedenceList.Remove(s);
                                }

                                string[] newPrecedenceArray = newPrecedenceList.ToArray();

                                if (newPrecedenceArray.Length == 2 &&
                                    ((newPrecedenceArray.Contains("True") || newPrecedenceArray.Contains("true") || newPrecedenceArray.Contains("yes") || newPrecedenceArray.Contains("Yes")) &&
                                     ((newPrecedenceArray.Contains("False") || newPrecedenceArray.Contains("false") || newPrecedenceArray.Contains("No") || newPrecedenceArray.Contains("no")))))
                                {
                                    string[] newPrecedenceArraySorted = newPrecedenceList.ToArray();
                                    Array.Sort(newPrecedenceArraySorted);
                                    string[] yesNoVals = (newPrecedenceArraySorted.Reverse().ToArray());
                                    attributeInfo[attribute] = new AttributeInfoBoolean(attribute, yesNoVals[1], yesNoVals[0]);

                                    Console.ForegroundColor = ConsoleColor.Black;
                                    Console.BackgroundColor = ConsoleColor.Yellow;
                                    Console.WriteLine("[WARNING] boolean/enumaration mis-match, type changed to boolean: ");
                                    Console.WriteLine("\tAttribute: " + attribute);
                                }
                                else
                                {
                                    ((AttributeInfoEnumerated)attributeInfo[attribute]).ValuePrecedence = newPrecedenceArray;

                                    Console.ForegroundColor = ConsoleColor.Black;
                                    Console.BackgroundColor = ConsoleColor.Yellow;
                                    Console.WriteLine("[WARNING] Precedence value mis-match, new enumerated value(s) added/removed: ");
                                    Console.WriteLine("\tAttribute: " + attribute);
                                    Console.Write("\tOld Values/Precedence: ");
                                    foreach (string s in suppliedPrecedence)
                                    {
                                        Console.Write(s + ',');
                                    }
                                    Console.WriteLine();
                                    Console.Write("\tNew Values: ");
                                    foreach (string s in newValues)
                                    {
                                        Console.Write(s + ',');
                                    }
                                    Console.WriteLine();
                                    Console.Write("\tRemoved Values: ");
                                    foreach (string s in removedValues)
                                    {
                                        Console.Write(s + ',');
                                    }
                                    Console.WriteLine();
                                    Console.Write("\tNew Precendence: ");
                                    foreach (string s in newPrecedenceArray)
                                    {
                                        Console.Write(s + ',');
                                    }
                                    Console.WriteLine();

                                    if (newValues.Count() > 0)
                                    {
                                        Console.WriteLine("Consider re-arranging precedence order for this attribute in the translator file (.trs).");
                                    }
                                    Console.ResetColor();
                                }
                                Console.WriteLine();
                            }
                        }
                        else if (attributeInfo[attribute].AttributeType == EAttributeType.Numeric)
                        {
                            string[]  uniqueValues   = InputWH.GetRecords().Select(r => r.GetAttributeValue(attribute)).Distinct().ToArray();
                            decimal[] uniqueDecimals = Array.ConvertAll(uniqueValues, s => decimal.Parse(s));

                            decimal currentMin = uniqueDecimals.Min();
                            decimal currentMax = uniqueDecimals.Max();

                            if (((AttributeInfoNumeric)attributeInfo[attribute]).Min != currentMin ||
                                ((AttributeInfoNumeric)attributeInfo[attribute]).Max != currentMax)
                            {
                                Console.ForegroundColor = ConsoleColor.Black;
                                Console.BackgroundColor = ConsoleColor.Yellow;
                                Console.WriteLine("Min/Max values changed: ");
                                Console.WriteLine("\tOld Min/Max: "
                                                  + ((AttributeInfoNumeric)attributeInfo[attribute]).Min
                                                  + "/"
                                                  + ((AttributeInfoNumeric)attributeInfo[attribute]).Max);
                                Console.WriteLine("\tNew Min/Max: "
                                                  + currentMin
                                                  + "/"
                                                  + currentMax);
                                Console.ResetColor();
                                Console.WriteLine();

                                ((AttributeInfoNumeric)attributeInfo[attribute]).Min = currentMin;
                                ((AttributeInfoNumeric)attributeInfo[attribute]).Max = currentMax;
                            }
                        }
                        else if (attributeInfo[attribute].AttributeType == EAttributeType.Boolean)
                        {
                            if (((AttributeInfoBoolean)attributeInfo[attribute]).ValuePrecedence.Length != 2 ||
                                !((((AttributeInfoBoolean)attributeInfo[attribute]).ValuePrecedence.Contains("True") ||
                                   ((AttributeInfoBoolean)attributeInfo[attribute]).ValuePrecedence.Contains("true") ||
                                   ((AttributeInfoBoolean)attributeInfo[attribute]).ValuePrecedence.Contains("yes") ||
                                   ((AttributeInfoBoolean)attributeInfo[attribute]).ValuePrecedence.Contains("Yes")) &&
                                  ((AttributeInfoBoolean)attributeInfo[attribute]).ValuePrecedence.Contains("False") ||
                                  ((AttributeInfoBoolean)attributeInfo[attribute]).ValuePrecedence.Contains("false") ||
                                  ((AttributeInfoBoolean)attributeInfo[attribute]).ValuePrecedence.Contains("No") ||
                                  ((AttributeInfoBoolean)attributeInfo[attribute]).ValuePrecedence.Contains("no")))
                            {
                                attributeInfo[attribute] = new AttributeInfoEnumerated(
                                    attribute,
                                    ((AttributeInfoBoolean)attributeInfo[attribute]).ValuePrecedence);
                            }
                        }
                    }
                }
            }