/// <summary>
        /// The main.
        /// </summary>
        /// <param name="args">
        /// The args.
        /// </param>
        public static void Main(string[] args)
        {
            // 1. We need a IDataStructureObject. In this example we read it from a file. Alternative we could build it from a mutable object.
            IDataStructureObject dataStructure;
            using (IReadableDataLocation readable = new FileReadableDataLocation("ESTAT+STS+2.0.xml"))
            {
                IStructureWorkspace structureWorkspace = _parsingManager.ParseStructures(readable);

                ISdmxObjects structureObjects = structureWorkspace.GetStructureObjects(false);
                dataStructure = structureObjects.DataStructures.FirstOrDefault();
            }

            if (dataStructure == null)
            {
                throw new InvalidOperationException("Could not build dataStructure object");
            }

            using (var writer = File.CreateText("re-using-gesmes-writer.ges"))
            {
                IDataWriterEngine dataWriterEngine = new GesmesTimeSeriesWriter(writer, true);

                // write header
                dataWriterEngine.WriteHeader(new HeaderImpl("ZZ9", "ZZ9"));

                // start dataset
                dataWriterEngine.StartDataset(null, dataStructure, null);

                // write dataset attributes
                dataWriterEngine.WriteAttributeValue("TITLE", "GESMES test");

                // write 2 group entries
                dataWriterEngine.StartGroup("SIBLING");
                dataWriterEngine.WriteGroupKeyValue("REF_AREA", "EL");
                dataWriterEngine.WriteGroupKeyValue("STS_INDICATOR", "PROD");
                dataWriterEngine.WriteGroupKeyValue("STS_ACTIVITY", "NS0030");
                dataWriterEngine.WriteGroupKeyValue("STS_INSTITUTION", "1");
                dataWriterEngine.WriteGroupKeyValue("ADJUSTMENT", "N");
                dataWriterEngine.WriteAttributeValue("COMPILATION", "test");

                dataWriterEngine.StartGroup("SIBLING");
                dataWriterEngine.WriteGroupKeyValue("REF_AREA", "EL");
                dataWriterEngine.WriteGroupKeyValue("STS_INDICATOR", "IND");
                dataWriterEngine.WriteGroupKeyValue("STS_ACTIVITY", "NS0030");
                dataWriterEngine.WriteGroupKeyValue("STS_INSTITUTION", "1");
                dataWriterEngine.WriteGroupKeyValue("ADJUSTMENT", "N");
                dataWriterEngine.WriteAttributeValue("COMPILATION", "test2");

                // write a series entry
                dataWriterEngine.StartSeries();
                dataWriterEngine.WriteSeriesKeyValue("FREQ", "A");
                dataWriterEngine.WriteSeriesKeyValue("REF_AREA", "EL");
                dataWriterEngine.WriteSeriesKeyValue("STS_INDICATOR", "PROD");
                dataWriterEngine.WriteGroupKeyValue("STS_ACTIVITY", "NS0030");
                dataWriterEngine.WriteGroupKeyValue("STS_INSTITUTION", "1");
                dataWriterEngine.WriteGroupKeyValue("ADJUSTMENT", "N");

                // write 2 observations for the abose series
                dataWriterEngine.WriteObservation("2001", "1.23");
                dataWriterEngine.WriteAttributeValue("OBS_STATUS", "A");
                dataWriterEngine.WriteAttributeValue("OBS_CONF", "F");

                dataWriterEngine.WriteObservation("2002", "4.56");
                dataWriterEngine.WriteAttributeValue("OBS_STATUS", "A");
                dataWriterEngine.WriteAttributeValue("OBS_CONF", "F");

                // write another series entry
                dataWriterEngine.StartSeries();
                dataWriterEngine.WriteSeriesKeyValue("FREQ", "A");
                dataWriterEngine.WriteSeriesKeyValue("REF_AREA", "EL");
                dataWriterEngine.WriteSeriesKeyValue("STS_INDICATOR", "IND");
                dataWriterEngine.WriteGroupKeyValue("STS_ACTIVITY", "NS0030");
                dataWriterEngine.WriteGroupKeyValue("STS_INSTITUTION", "1");
                dataWriterEngine.WriteGroupKeyValue("ADJUSTMENT", "N");

                // write 1 observation for the abose series
                dataWriterEngine.WriteObservation("2001", "7.89");
                dataWriterEngine.WriteAttributeValue("OBS_STATUS", "A");
                dataWriterEngine.WriteAttributeValue("OBS_CONF", "F");

                // close compact Writer
                dataWriterEngine.Close();
            }
        }
        public void TestEdiDataWriter(bool useTimeRangeTechnique)
        {
            IConceptSchemeMutableObject conceptScheme = new ConceptSchemeMutableCore { Id = "CONCEPTS_TEST", AgencyId = "TEST" };
            conceptScheme.AddName("en", "Dummy concept scheme build for this tests");

            ////conceptScheme.Annotations.Add(new AnnotationMutableCore() { Id = "ANNOTABLETEST", Title = "Test", Type = "ATYPE" });
            conceptScheme.FinalStructure = TertiaryBool.GetFromEnum(TertiaryBoolEnumType.True);

            IConceptSchemeObject parent = conceptScheme.ImmutableInstance;

            IConceptObject freqConcept = CreateConcept(parent, "FREQ", "Frequency");

            IConceptObject adjustmentConcept = CreateConcept(parent, "ADJUSTMENT", "The Adjustment");

            IConceptObject activityConcpet = CreateConcept(parent, "STS_ACTIVITY", "Name of activity ");

            IConceptObject timeDimensionConcpet = CreateConcept(parent, "TIME_PERIOD", "Name of  Time Period");
            IConceptObject decimalsConcept = CreateConcept(parent, "DECIMALS", "Name of concept");

            IConceptObject obsConcept = CreateConcept(parent, "OBS_VALUE", "Name of  observation value");
            IConceptObject obsStatusConcept = CreateConcept(parent, "OBS_STATUS", "Name of  observation value");

            ICodelistObject freqCl = CreateCodelist("CL_FREQ", "Freq codelist", "Q", "A", "M");
            ICodelistObject adjCl = CreateCodelist("CL_ADJUSTMENT", "Adjustment codelist", "N", "S", "W");
            ICodelistObject actCl = CreateCodelist("CL_ACTIVITY", "Activity codelist", "A", "B", "C");
            ICodelistObject deciCl = CreateCodelist("CL_DECIMALS", "DECIMALS codelist", "1", "2", "0");
            ICodelistObject obsStatusCl = CreateCodelist("CL_OBS_STATUS", "Obs status codelist", "A", "M", "L");

            IDataStructureMutableObject mutable = new DataStructureMutableCore { Id = "TEST_DSD", AgencyId = "TEST" };
            mutable.AddName("en", "FOO BAR");
            mutable.AddDimension(
                new DimensionMutableCore { ConceptRef = freqConcept.AsReference, FrequencyDimension = true, Representation = new RepresentationMutableCore { Representation = freqCl.AsReference } });
            mutable.AddDimension(new DimensionMutableCore { ConceptRef = adjustmentConcept.AsReference, Representation = new RepresentationMutableCore { Representation = adjCl.AsReference } });
            mutable.AddDimension(new DimensionMutableCore { ConceptRef = activityConcpet.AsReference, Representation = new RepresentationMutableCore { Representation = actCl.AsReference } });
            mutable.AddDimension(new DimensionMutableCore { ConceptRef = timeDimensionConcpet.AsReference, TimeDimension = true });

            IList<string> dimList = new List<string> { freqConcept.Id, adjustmentConcept.Id, adjustmentConcept.Id };
            var attributeMutableCore = new AttributeMutableCore
                                           {
                                               ConceptRef = decimalsConcept.AsReference, 
                                               Representation = new RepresentationMutableCore { Representation = deciCl.AsReference }, 
                                               AttachmentLevel = AttributeAttachmentLevel.DimensionGroup, 
                                               AssignmentStatus = AttributeAssignmentStatus.Mandatory.ToString()
                                           };
            attributeMutableCore.DimensionReferences.AddAll(dimList);
            mutable.AddAttribute(attributeMutableCore);

            var obsStatusMutable = new AttributeMutableCore
                                       {
                                           ConceptRef = obsStatusConcept.AsReference, 
                                           Representation = new RepresentationMutableCore { Representation = obsStatusCl.AsReference }, 
                                           AttachmentLevel = AttributeAttachmentLevel.Observation, 
                                           AssignmentStatus = AttributeAssignmentStatus.Mandatory.ToString()
                                       };
            mutable.AddAttribute(obsStatusMutable);

            mutable.PrimaryMeasure = new PrimaryMeasureMutableCore { ConceptRef = obsConcept.AsReference };
            IDataStructureObject dataStructureObject = mutable.ImmutableInstance;
            IList<IDatasetStructureReference> structures = new List<IDatasetStructureReference> { new DatasetStructureReferenceCore(dataStructureObject.AsReference) };
            IList<IParty> receiver = new List<IParty> { new PartyCore(new List<ITextTypeWrapper>(), "ZZ9", new List<IContact>(), null) };
            var sender = new PartyCore(new List<ITextTypeWrapper> { new TextTypeWrapperImpl("en", "TEST SENDER", null) }, "ZZ1", null, null);
            IHeader header = new HeaderImpl(
                null, 
                structures, 
                null, 
                DatasetAction.GetFromEnum(DatasetActionEnumType.Information), 
                "TEST_DATAFLOW", 
                "DATASET_ID", 
                null, 
                DateTime.Now, 
                DateTime.Now, 
                null, 
                null, 
                new List<ITextTypeWrapper> { new TextTypeWrapperImpl("en", "test header name", null) }, 
                new List<ITextTypeWrapper> { new TextTypeWrapperImpl("en", "source 1", null) }, 
                receiver, 
                sender, 
                true);
            
            var sw = new Stopwatch();
            sw.Start();
            var series = from f in freqCl.Items from ad in adjCl.Items from ac in actCl.Items select new { f, ad, ac };

            sw.Stop();
            Trace.WriteLine(sw.Elapsed);
            sw.Reset();

            var startTime = new DateTime(2005, 1, 1);
            sw.Start();
            using (StreamWriter stream = File.CreateText("gesmes-ts-data-writer-tr-" + useTimeRangeTechnique + ".ges"))
            {
                IDataWriterEngine dataWriter = new GesmesTimeSeriesWriter(stream, useTimeRangeTechnique);
                dataWriter.WriteHeader(header);

                dataWriter.StartDataset(null, dataStructureObject, null);
                foreach (var key in series)
                {
                    dataWriter.StartSeries();
                    dataWriter.WriteSeriesKeyValue(freqConcept.Id, key.f.Id);
                    dataWriter.WriteSeriesKeyValue(adjustmentConcept.Id, key.ad.Id);
                    dataWriter.WriteSeriesKeyValue(activityConcpet.Id, key.ac.Id);

                    Func<int, string> getPeriod = null;
                    switch (key.f.Id)
                    {
                        case "Q":
                            getPeriod = i =>
                                {
                                    DateTime months = startTime.AddMonths(3 * i);
                                    return DateUtil.FormatDate(months, TimeFormatEnumType.QuarterOfYear);
                                };
                            dataWriter.WriteAttributeValue(decimalsConcept.Id, "1");
                            break;
                        case "A":
                            getPeriod = i =>
                                {
                                    DateTime months = startTime.AddMonths(12 * i);
                                    return DateUtil.FormatDate(months, TimeFormatEnumType.Year);
                                };
                            dataWriter.WriteAttributeValue(decimalsConcept.Id, "0");
                            break;
                        case "M":
                            getPeriod = i =>
                                {
                                    DateTime months = startTime.AddMonths(i + 1);
                                    return DateUtil.FormatDate(months, TimeFormatEnumType.Month);
                                };
                            dataWriter.WriteAttributeValue(decimalsConcept.Id, "2");
                            break;
                        default:
                            Assert.Fail("Test bug. Check CL_FREQ codes");
                            break;
                    }

                    for (int i = 0; i < 100; i++)
                    {
                        string period = getPeriod(i);
                        dataWriter.WriteObservation(period, i.ToString(CultureInfo.InvariantCulture));
                        dataWriter.WriteAttributeValue(obsStatusConcept.Id, "A");
                    }
                }

                dataWriter.Close();

                sw.Stop();
                Trace.WriteLine(sw.Elapsed);
            }
        }