/// <summary>
        /// Gets the correct schema definition depending on the version.
        /// </summary>
        /// <param name="schemaDefinitions">All the schema definitions.</param>
        /// <returns>The schema definition that corresponds to the XML file.</returns>
        /// <exception cref="CriticalFileReadException">Thrown when the version
        /// from the XML file is not supported.</exception>
        private CalculationConfigurationSchemaDefinition GetSchemaDefinition(IEnumerable <CalculationConfigurationSchemaDefinition> schemaDefinitions)
        {
            int versionNumber;

            try
            {
                var combinedXmlSchemaDefinition = new CombinedXmlSchemaDefinition(Resources.VersieSchema, new Dictionary <string, string>());
                combinedXmlSchemaDefinition.Validate(xmlDocument);

                versionNumber = GetVersionNumber();
            }
            catch (XmlSchemaValidationException)
            {
                versionNumber = 0;
            }

            CalculationConfigurationSchemaDefinition schemaDefinition = schemaDefinitions.SingleOrDefault(sd => sd.VersionNumber == versionNumber);

            if (schemaDefinition == null)
            {
                string message = new FileReaderErrorMessageBuilder(xmlFilePath)
                                 .Build(Resources.CalculationConfigurationReader_GetSchemaDefinition_Not_supported_version);

                throw new CriticalFileReadException(message);
            }

            return(schemaDefinition);
        }
        /// <summary>
        /// Creates a new instance of <see cref="CalculationConfigurationReader{TReadCalculation}"/>.
        /// </summary>
        /// <param name="xmlFilePath">The file path to the XML file.</param>
        /// <param name="schemaDefinitions">The array of <see cref="CalculationConfigurationSchemaDefinition"/>.</param>
        /// <exception cref="ArgumentNullException">Thrown when <paramref name="schemaDefinitions"/>
        /// is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">Thrown when:
        /// <list type="bullet">
        /// <item><paramref name="xmlFilePath"/> is invalid.</item>
        /// <item><see cref="CalculationConfigurationSchemaDefinition.MainSchemaDefinition"/> is invalid.</item>
        /// <item><see cref="CalculationConfigurationSchemaDefinition.NestedSchemaDefinitions"/> contains invalid schema definition values.</item>
        /// <item><see cref="CalculationConfigurationSchemaDefinition.MainSchemaDefinition"/>, all together with its referenced
        /// <see cref="CalculationConfigurationSchemaDefinition.NestedSchemaDefinitions"/>, contains an invalid schema definition.</item>
        /// <item><see cref="CalculationConfigurationSchemaDefinition.NestedSchemaDefinitions"/> contains schema definitions that are not
        /// referenced by the <see cref="CalculationConfigurationSchemaDefinition.MainSchemaDefinition"/>.</item>
        /// <item><see cref="CalculationConfigurationSchemaDefinition.MainSchemaDefinition"/> does not reference the default schema definition
        /// <c>ConfiguratieSchema.xsd</c>.</item>
        /// </list>
        /// </exception>
        /// <exception cref="CriticalFileReadException">Thrown when:
        /// <list type="bullet">
        /// <item><paramref name="xmlFilePath"/> points to a file that does not exist.</item>
        /// <item><paramref name="xmlFilePath"/> points to a file that does not contain valid XML.</item>
        /// <item><paramref name="xmlFilePath"/> points to a file that does not pass the schema validation.</item>
        /// <item><paramref name="xmlFilePath"/> points to a file that does not contain configuration elements.</item>
        /// <item>something goes wrong while migrating.</item>
        /// </list>
        /// </exception>
        protected CalculationConfigurationReader(string xmlFilePath, CalculationConfigurationSchemaDefinition[] schemaDefinitions)
        {
            if (schemaDefinitions == null)
            {
                throw new ArgumentNullException(nameof(schemaDefinitions));
            }

            IOUtils.ValidateFilePath(xmlFilePath);

            this.xmlFilePath = xmlFilePath;

            ValidateFileExists();

            xmlDocument = LoadDocument();

            CalculationConfigurationSchemaDefinition schemaDefinition = GetSchemaDefinition(schemaDefinitions);

            ValidateToSchema(schemaDefinition.MainSchemaDefinition, schemaDefinition.NestedSchemaDefinitions);

            ValidateNotEmpty();

            MigrateWhenNeeded(schemaDefinitions, schemaDefinition);
        }
        /// <summary>
        /// Migrates the XML document to newer versions when needed.
        /// </summary>
        /// <param name="schemaDefinitions">All the schema definitions.</param>
        /// <param name="schemaDefinition">The schema definition corresponding to the version
        /// of the XML document.</param>
        /// <exception cref="CriticalFileReadException">Thrown when something goes wrong
        /// while migrating.</exception>
        private void MigrateWhenNeeded(CalculationConfigurationSchemaDefinition[] schemaDefinitions, CalculationConfigurationSchemaDefinition schemaDefinition)
        {
            int index = Array.IndexOf(schemaDefinitions, schemaDefinition);

            for (int i = index + 1; i < schemaDefinitions.Length; i++)
            {
                MigrateToNewSchema(schemaDefinitions[i].MigrationScript);
            }
        }