/// <summary>
        /// Construct EDI representation of document (current transaction set
        /// along with header segments)
        /// </summary>
        /// <param name="ediDelimiters"></param>
        /// <returns></returns>
        public string ToEDI(Delimiters ediDelimiters)
        {
            ILogger logger = LoggerFactory.Logger;

            string ediDocument = RootFragment.ToEDI(ediDelimiters, false);

            return(ediDocument);
        }
        /// <summary>
        /// Construct EDI representation of this fragment
        /// </summary>
        /// <param name="ediDelimiters"></param>
        /// <param name="internalSegment"></param>
        /// <returns></returns>
        public string ToEDI(Delimiters ediDelimiters, bool internalSegment)
        {
            if (Children == null)
            {
                return(string.Empty);
            }

            StringBuilder segment = new StringBuilder();

            string componentDelimiter = ((char)ediDelimiters.ComponentSeperator).ToString();
            string fieldDelimiter     = ((char)ediDelimiters.FieldSeperator).ToString();
            string delimiter          = internalSegment == true ? componentDelimiter : fieldDelimiter;

            // construct segment only for parent with at least 1 leaf node
            if (Children.Any(c => c.Pluglet.PlugletType == PlugletType.Data))
            {
                if (internalSegment == false)
                {
                    segment.AppendFormat("{0}", Pluglet.Tag);
                }

                foreach (IDocumentFragment child in Children)
                {
                    if (child.Pluglet.PlugletType == PlugletType.Data)
                    {
                        if (segment.Length != 0 || internalSegment == false)
                        {
                            segment.AppendFormat("{0}{1}", delimiter, child.Value);
                        }
                        else
                        {
                            segment.AppendFormat("{0}", child.Value);
                        }
                    }
                    else
                    {
                        segment.AppendFormat("{0}{1}", fieldDelimiter, child.ToEDI(ediDelimiters, true));
                    }
                }
            }
            else
            {
                string childSegment;

                StringBuilder segmentB = new StringBuilder(3);
                segmentB.Append((char)ediDelimiters.SegmentDelimiter);
                if (ediDelimiters.SegmentDelimiterSuffix1 != -1)
                {
                    segmentB.Append((char)ediDelimiters.SegmentDelimiterSuffix1);
                }
                if (ediDelimiters.SegmentDelimiterSuffix2 != -1)
                {
                    segmentB.Append((char)ediDelimiters.SegmentDelimiterSuffix2);
                }
                string segmentDelimiter = segmentB.ToString();


                foreach (IDocumentFragment child in Children)
                {
                    childSegment = child.ToEDI(ediDelimiters, false);
                    segment.AppendFormat("{0}{1}"
                                         , string.IsNullOrEmpty(segment.ToString()) ? string.Empty : segmentDelimiter
                                         , childSegment);
                }

                IDocumentFragment firstChild = Children[0];
                // Special case for ading SE/GE/IEA segments
                switch (firstChild.Pluglet.Tag)
                {
                case "ST":
                    string txnSetNumber = "";
                    int    segmentCount = 0;
                    if (firstChild.Children != null && firstChild.Children.Count > 1)
                    {
                        txnSetNumber = firstChild.Children[1].Value;
                    }
                    // Set segmentCount to child count of X12_00401_850
                    segmentCount = this.CountAllChilds() + 1;     // +1 for SE segment
                    //segment.AppendFormat("{0}SE{1}{2}{3}{4}", segmentDelimiter, fieldDelimiter, segmentCount, fieldDelimiter, txnSetNumber);

                    //segment.AppendFormat("{0}GE{1}1{2}1", segmentDelimiter, fieldDelimiter, fieldDelimiter);
                    //segment.AppendFormat("{0}IEA{1}1{2}{3}", segmentDelimiter, fieldDelimiter, fieldDelimiter, "NNNN");

                    break;
                }
            }

            return(segment.ToString());
        }
        /// <summary>
        /// Construct DocumentFragment for leaf node parent and then create and attach leaf nodes to it.
        /// </summary>
        /// <param name="pluglet"></param>
        /// <param name="segmentDetails"></param>
        /// <param name="internalSegment"></param>
        /// <param name="ediDelimiters"></param>
        /// <param name="segmentStartIndex"></param>
        /// <param name="segmentEndIndex"></param>
        /// <param name="ediErrors"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static DocumentFragment ConstructDocumentFragment(this IPluglet pluglet, string[] segmentDetails, bool internalSegment, Delimiters ediDelimiters,
                                                                 int segmentSeqNumber, long segmentStartIndex, long segmentEndIndex, ref InterchangeErrors ediErrors, out string error)
        {
            if (pluglet == null)
            {
                throw new ArgumentNullException("pluglet");
            }

            if (segmentDetails == null)
            {
                throw new ArgumentNullException("segmentDetails");
            }

            LoggerFactory.Logger.Info("PlugletExtensions.ConstructDocumentFragment", "Constructing {0} instance", pluglet.Tag);

            if (pluglet.Children == null)
            {
                error = string.Format("Pluglet {0} does not have childrens", pluglet.Name);
                return(null);
            }

            // -1 is required since SegmentDetails[0] is the SegmentName
            if (pluglet.Children.Count < segmentDetails.Length - 1)
            {
                error = string.Format("Document has {1} data elements, it is less than segment children count {2} as described in Spec",
                                      pluglet.Name, pluglet.Children.Count, segmentDetails.Length);
                return(null);
            }

            error = string.Empty;
            ++pluglet.CurrentOccurrences;
            DocumentFragment documentFragment = new DocumentFragment()
            {
                Pluglet        = pluglet,
                Children       = new List <IDocumentFragment>(),
                SequenceNumber = segmentSeqNumber,
                StartOffset    = segmentStartIndex,
                EndOffset      = segmentEndIndex,
            };

            int plugletNum = 0;
            DocumentFragment dataFragment;
            IPluglet         plugletChild;
            bool             validateValue;

            long currentSegmentFieldStartIndex = segmentStartIndex;

            //SegmentNum start from 1 since SegmentDetails[0] is Segment name
            int segmentNum = 1;

            // if this is internal segment (composite segment - segment handing data and segment as children) then
            // start segmentDetails from 0
            if (internalSegment == true)
            {
                segmentNum = 0;
            }

            EdiErrorType errorType = pluglet.IsIgnore ? EdiErrorType.Warning : EdiErrorType.Error;

            for (; segmentNum < segmentDetails.Length; segmentNum++, plugletNum++)
            {
                if (segmentNum != 0)
                {
                    currentSegmentFieldStartIndex += segmentDetails[segmentNum - 1].Length + 1;
                }

                validateValue = false;
                plugletChild  = pluglet.Children[plugletNum];

                if (plugletChild.PlugletType == PlugletType.Data)
                {
                    dataFragment = new DocumentFragment()
                    {
                        Parent  = documentFragment,
                        Pluglet = plugletChild,
                        Value   = segmentDetails[segmentNum],

                        /*SequenceNumber = segmentSeqNumber,
                         * StartOffset = currentSegmentFieldStartIndex,
                         * EndOffset = currentSegmentFieldStartIndex + segmentDetails[segmentNum].Length,*/
                    };

                    validateValue = true;
                }
                else if (plugletChild.PlugletType == PlugletType.Segment)
                {
                    if (string.IsNullOrEmpty(segmentDetails[segmentNum]) == false)
                    {
                        string segmentError = string.Empty;

                        string [] internalSegmentDetails = segmentDetails[segmentNum].Split((char)ediDelimiters.ComponentSeperator);

                        dataFragment = plugletChild.ConstructDocumentFragment(internalSegmentDetails, true, ediDelimiters, segmentSeqNumber, currentSegmentFieldStartIndex,
                                                                              currentSegmentFieldStartIndex + segmentDetails[segmentNum].Length, ref ediErrors, out segmentError);

                        if (string.IsNullOrEmpty(segmentError) == false)
                        {
                            if (string.IsNullOrEmpty(error) == true)
                            {
                                error = string.Format("ConstructDocumentSegmentInstance: Pluglet {0}: ", pluglet.Name);
                            }

                            error = string.Format("{0} Error constructing {1}: {2}", error, plugletChild.Name, segmentError);
                        }
                    }
                    else
                    {
                        dataFragment = new DocumentFragment()
                        {
                            Parent  = documentFragment,
                            Pluglet = plugletChild,
                            Value   = segmentDetails[segmentNum],
                        };
                    }
                }
                else
                {
                    error = string.Format("ConstructDocumentSegmentInstance: Error constructing SegmentInstance. Pluglet {0} is of type {1}",
                                          pluglet.Name, plugletChild.Name);
                    return(null);
                }

                if (validateValue == true && plugletChild.DataType != null && string.IsNullOrEmpty(segmentDetails[segmentNum]) == false)
                {
                    FieldError fieldError = plugletChild.DataType.ValidateValue(new StringBuilder(segmentDetails[segmentNum]));
                    if (fieldError != null)
                    {
                        if (string.IsNullOrEmpty(error) == true)
                        {
                            error = string.Format("ConstructDocumentSegmentInstance: Pluglet {0}: ", pluglet.Name);
                        }

                        error = string.Format("{0} Error data validation failed {1}: {2} ({3})", error, plugletChild.Name, fieldError.Description, fieldError.DataValue);

                        ediErrors.AddFieldError(segmentDetails[0], plugletChild.Tag, fieldError.ErrorCode, fieldError.Description, segmentSeqNumber, segmentNum, segmentDetails[segmentNum], currentSegmentFieldStartIndex,
                                                currentSegmentFieldStartIndex + segmentDetails[segmentNum].Length - 1, errorType);
                    }
                }

                //TODO: Add validation (extension method)
                documentFragment.Children.Add(dataFragment);

                if (string.IsNullOrEmpty(segmentDetails[segmentNum]) && plugletChild.IsMandatory == true)
                {
                    if (string.IsNullOrEmpty(error) == true)
                    {
                        error = string.Format("ConstructDocumentSegmentInstance: Pluglet {0}: ", pluglet.Name);
                    }

                    error = string.Format("{0} Child {1} is mandatory but missing", error, plugletChild.Name);

                    ediErrors.AddFieldError(segmentDetails[0], plugletChild.Tag, X12ErrorCode.DeMandatoryDataElementMissingCode,
                                            X12ErrorCode.GetDataElementErrorDescription(X12ErrorCode.DeMandatoryDataElementMissingCode), segmentSeqNumber, segmentNum, string.Empty,
                                            currentSegmentFieldStartIndex, currentSegmentFieldStartIndex, errorType);
                }
            }

            for (; segmentNum <= pluglet.Children.Count; segmentNum++, plugletNum++)
            {
                plugletChild = pluglet.Children[plugletNum];
                if (plugletChild.IsMandatory == true)
                {
                    if (string.IsNullOrEmpty(error) == true)
                    {
                        error = string.Format("ConstructDocumentSegmentInstance: Pluglet {0}: ", pluglet.Name);
                    }

                    error = string.Format("{0} Child {1} is mandatory but missing", error, plugletChild.Name);

                    ediErrors.AddFieldError(segmentDetails[0], plugletChild.Tag, X12ErrorCode.DeMandatoryDataElementMissingCode,
                                            X12ErrorCode.GetDataElementErrorDescription(X12ErrorCode.DeMandatoryDataElementMissingCode), segmentSeqNumber, segmentNum, string.Empty,
                                            currentSegmentFieldStartIndex, currentSegmentFieldStartIndex, errorType);
                }
            }

            return(documentFragment);
        }