/// <summary>
 /// Get the code (number) as string of the specified <paramref name="periodCode"/>
 /// </summary>
 /// <param name="periodCode">
 /// The <see cref="EdiTimeFormat"/>
 /// </param>
 /// <returns>
 /// The code (number) as string of the specified <paramref name="periodCode"/>
 /// </returns>
 public static string GetTimeFormatCode(EdiTimeFormat periodCode)
 {
     return periodCode.ToString("D");
 }
        /// <summary>
        /// Parses the range.
        /// </summary>
        /// <param name="ediTimeFormat">The EDI time format.</param>
        /// <param name="dateString">The date string.</param>
        /// <param name="range">The range.</param>
        /// <returns>
        /// The <see cref="DateTime" />.
        /// </returns>
        /// <exception cref="SdmxNotImplementedException">The <paramref name="ediTimeFormat" /> is not supported.</exception>
        /// <exception cref="SdmxSemmanticException">Time Period not consistent with time format code.</exception>
        private static DateTime ParseRange(EdiTimeFormat ediTimeFormat, string dateString, int range)
        {
            int dateLength;
            EdiTimeFormat tf;
            switch (ediTimeFormat)
            {
                case EdiTimeFormat.RangeDaily:
                    dateLength = 8;
                    tf = EdiTimeFormat.DailyFourDigYear;
                    break;
                case EdiTimeFormat.RangeHalfOfYear:
                    dateLength = 5;
                    tf = EdiTimeFormat.HalfOfYear;
                    break;
                case EdiTimeFormat.RangeMonthly:
                    dateLength = 6;
                    tf = EdiTimeFormat.Month;
                    break;
                case EdiTimeFormat.RangeQuarterOfYear:
                    dateLength = 5;
                    tf = EdiTimeFormat.QuarterOfYear;
                    break;
                case EdiTimeFormat.RangeWeekly:
                    dateLength = 6;
                    tf = EdiTimeFormat.Week;
                    break;
                case EdiTimeFormat.RangeYear:
                    dateLength = 4;
                    tf = EdiTimeFormat.Year;
                    break;
                default:
                    throw new SdmxNotImplementedException("Edi date format : " + ediTimeFormat.ToString("D"));
            }

            // NOTE (.NET). From what I understood here the range can either 1 or 0. When it is 0 we get the first half of the EDI time range(date string), i.e. the start date
            // When it is 1 we get the second half i.e. end date. 
            int startIdx = range * dateLength;
            int endIdx = startIdx + dateLength;

            if (dateString.Length >= endIdx)
            {
                string split = dateString.Substring(startIdx, dateLength);
                return ParseDate(split, tf);
            }

            string errorMessage = string.Format("Time Period not consistent with time format code. Time period \'{0}\'. Time format code \'{1}\'", dateString, ediTimeFormat);
            throw new SdmxSemmanticException(errorMessage);
        }
        /// <summary>
        /// The convert to single time format.
        /// </summary>
        /// <param name="ediTimeFormat">
        /// The edi time format.
        /// </param>
        /// <returns>
        /// The <see cref="EdiTimeFormat"/>.
        /// </returns>
        private static EdiTimeFormat ConvertToSingleTimeFormat(EdiTimeFormat ediTimeFormat)
        {
            EdiTimeFormat timeFormat = ediTimeFormat;
            switch (ediTimeFormat)
            {
                case EdiTimeFormat.RangeDaily:
                    timeFormat = EdiTimeFormat.DailyFourDigYear;
                    break;
                case EdiTimeFormat.RangeMonthly:
                    timeFormat = EdiTimeFormat.Month;
                    break;
                case EdiTimeFormat.RangeHalfOfYear:
                    timeFormat = EdiTimeFormat.HalfOfYear;
                    break;
                case EdiTimeFormat.RangeQuarterOfYear:
                    timeFormat = EdiTimeFormat.QuarterOfYear;
                    break;
                case EdiTimeFormat.RangeWeekly:
                    timeFormat = EdiTimeFormat.Week;
                    break;
                case EdiTimeFormat.RangeYear:
                    timeFormat = EdiTimeFormat.Year;
                    break;
            }

            return timeFormat;
        }
        /// <summary>
        /// Parses the date.
        /// </summary>
        /// <param name="ediDateString">The EDI date string.</param>
        /// <param name="timeFormat">The time format.</param>
        /// <returns>
        /// The <see cref="DateTime" />.
        /// </returns>
        /// <exception cref="SdmxNotImplementedException"> <paramref name="timeFormat"/> value not supported. </exception>
        /// <exception cref="SdmxSemmanticException">
        /// Could not parse date  in <paramref name="ediDateString"/> with EDI time format in <paramref name="timeFormat"/>  and is a range, and is therefore expected to provide a date with X characters  
        /// or
        /// Could not parse date  in <paramref name="ediDateString"/>  with EDI time format in <paramref name="timeFormat"/>' relates to  + timeFormat.GetSdmxTimeFormat().ReadableCode
        ///                     +  data is expected to provide a date with ' + expectedLength + ' characters 
        /// </exception>
        private static DateTime ParseDate(string ediDateString, EdiTimeFormat timeFormat)
        {
            try
            {
                switch (timeFormat)
                {
                    case EdiTimeFormat.DailyFourDigYear:
                        return EDIDateUtil.DateFormatDailyLongYear.Parse(ediDateString);

                    case EdiTimeFormat.DailyTwoDigYear:
                        return EDIDateUtil.DateFormatDailyShortYear.Parse(ediDateString);

                    case EdiTimeFormat.HalfOfYear:
                        return ParseHalfYear(ediDateString);

                    case EdiTimeFormat.MinuteFourDigYear:
                        return EDIDateUtil.DateFormatMinuteLongYear.Parse(ediDateString);

                    case EdiTimeFormat.MinuteTwoDigYear:
                        return EDIDateUtil.DateFormatMinuteShortYear.Parse(ediDateString);

                    case EdiTimeFormat.Month:
                        return EDIDateUtil.DateFormatMonthly.Parse(ediDateString);

                    case EdiTimeFormat.Week:
                        return EDIDateUtil.DateFormatWeekly.Parse(ediDateString);

                    case EdiTimeFormat.Year:
                        return EDIDateUtil.DateFormatYearly.Parse(ediDateString);

                    case EdiTimeFormat.QuarterOfYear:
                        return ParseQuarterYear(ediDateString);

                    default:
                        throw new SdmxNotImplementedException("Edi date format : " + timeFormat);
                }
            }
            catch (FormatException e)
            {
                int expectedLength = timeFormat.GetExpectedLength();
                if (timeFormat.IsRange())
                {
                    throw new SdmxSemmanticException(
                        "Could not parse date '" + ediDateString + "' edi time format '" + timeFormat.GetEdiValue() + "' relates to " + timeFormat.GetSdmxTimeFormat().ReadableCode
                        + " data, and is a range, and is therefore expected to provide a date with '" + expectedLength + "' characters  ", 
                        e);
                }

                throw new SdmxSemmanticException(
                    "Could not parse date '" + ediDateString + "' edi time format '" + timeFormat.GetEdiValue() + "' relates to " + timeFormat.GetSdmxTimeFormat().ReadableCode
                    + " data is expected to provide a date with '" + expectedLength + "' characters ", 
                    e);
            }
        }
        /// <summary>
        /// Processes the observations by storing the observation dates in a list in the order in which the observations are
        ///     reported.
        ///     <p/>
        ///     If there are no observations to process (as this could be a delete message deleting a series, or a group of series)
        ///     then the <c>obsDates</c> list will be empty
        /// </summary>
        /// <param name="dataLineSplit">
        /// The data line split.
        /// </param>
        private void ProcessObservations(IList<string> dataLineSplit)
        {
            this._obsDates = new List<string>();
            if (dataLineSplit.Count > this._dimensions.Length)
            {
                string reportedDate = dataLineSplit[this._dimensions.Length];
                string dateFormat = dataLineSplit[this._dimensions.Length + 1];
                this._ediTimeFormat = EdiTimeFormatExtension.ParseString(dateFormat);

                // If there are no observations but we have a time range and this is a delete message,
                // then create observations with no value for each of the entries in the time range.
                if (this._observations == null && this._ediTimeFormat.IsRange() && this.CurrentDatasetHeader.Action.EnumType == DatasetActionEnumType.Delete)
                {
                    var startDate = this._ediTimeFormat.ParseDate(reportedDate);
                    var endDate = this._ediTimeFormat.ParseEndDate(reportedDate);
                    this._obsDates = DateUtil.CreateTimeValues(startDate, endDate, this._ediTimeFormat.GetSdmxTimeFormat());
                }
                else
                {
                    if (this._observations != null && this._observations.Length > 1)
                    {
                        this.ProcessObservationRange(reportedDate);
                    }
                    else
                    {
                        this.ProcessSingleObservation(reportedDate);
                    }
                }
            }
        }