/// <summary>
        /// Gets an array of identifiable id from the specified <paramref name="xref"/>
        /// </summary>
        /// <param name="xref">
        /// The cross reference. 
        /// </param>
        /// <returns>
        /// The an array of identifiable id from the specified <paramref name="xref"/> ; otherwise null 
        /// </returns>
        public static string[] GetIdentifiableIds(IIdentifiableRefObject xref)
        {
            if (xref == null)
            {
                return null;
            }

            var ids = new List<string>();
            while (xref.ChildReference != null)
            {
                ids.Add(xref.ChildReference.Id);
            }

            return ids.ToArray();
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="IdentifiableRefObjetcImpl"/> class.
        /// </summary>
        /// <param name="parentReference">
        /// The parent reference.
        /// </param>
        /// <param name="id">
        /// The id.
        /// </param>
        /// <param name="currentDepth">
        /// The current depth.
        /// </param>
        /// <param name="targetStructureEnumType">
        /// The target structure enum type.
        /// </param>
        private IdentifiableRefObjetcImpl(
            IIdentifiableRefObject parentReference, 
            IList<string> id, 
            int currentDepth, 
            SdmxStructureType targetStructureEnumType)
        {
            this._parentReference = parentReference;
            this._id = id[currentDepth];
            this._structureEnumType = SetStructureType(targetStructureEnumType, currentDepth);
            currentDepth++;
            if (currentDepth < id.Count)
            {
                this._childReference = new IdentifiableRefObjetcImpl(this, id, currentDepth, targetStructureEnumType);
            }

            Validate();
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="IdentifiableRefObjetcImpl"/> class.
        /// </summary>
        /// <param name="maintainableParent">
        /// The maintainable parent.
        /// </param>
        /// <param name="idArr">
        /// The id arr.
        /// </param>
        /// <param name="targetStructureEnumType">
        /// The target structure enum type.
        /// </param>
        public IdentifiableRefObjetcImpl(
            IStructureReference maintainableParent, IList<string> idArr, SdmxStructureType targetStructureEnumType)
        {
            this._structureEnumType = SetStructureType(targetStructureEnumType, 0);
            this._maintainableParent = maintainableParent;

            if (this._structureEnumType.HasFixedId)
            {
                if (!idArr[0].Equals(this._structureEnumType.FixedId))
                {
                    //Change the id array by inserting a new fixed id
                    string[] tempArray = new string[idArr.Count + 1];
                    tempArray[0] = this._structureEnumType.FixedId;

                    for (int i = 0; i < idArr.Count; i++)
                    {
                        tempArray[i + 1] = idArr[i];
                    }

                    idArr = tempArray;
                }
            }

            this._id = idArr[0];
            if (idArr.Count > 1)
            {
                this._childReference = new IdentifiableRefObjetcImpl(this, idArr, 1, targetStructureEnumType);
            }

            Validate();
        }
        /// <summary>
        /// Write the CategoryID element from the given CategoryIDBean object
        /// </summary>
        /// <param name="categoryID">
        /// The CategoryIDBean object to write
        /// </param>
        private void WriteCategoryID(IIdentifiableRefObject categoryID)
        {
            int open = 0;

            IIdentifiableRefObject current = categoryID;
            while (current != null)
            {
                this.WriteStartElement(this.DefaultPrefix, ElementNameTable.CategoryID);
                open++;
                this.TryToWriteElement(this.DefaultPrefix, ElementNameTable.ID, current.Id);
                current = current.ChildReference;
            }

            while (open > 0)
            {
                this.WriteEndElement();
                open--;
            }
        }
        /// <summary>
        /// Sets the information.
        /// </summary>
        /// <param name="agencyId">
        /// The agency id. 
        /// </param>
        /// <param name="maintainableId">
        /// The maintainable id. 
        /// </param>
        /// <param name="version">
        /// The version. 
        /// </param>
        /// <param name="targetStructureEnum">
        /// The target structure. 
        /// </param>
        /// <param name="identfiableIds">
        /// The identifiable ids. 
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="targetStructureEnum"/>
        /// is null
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Can not create reference, target structure is not maintainable, and no identifiable reference parameters present
        /// </exception>
        private void SetInformationFromList(
            string agencyId,
            string maintainableId,
            string version,
            SdmxStructureType targetStructureEnum,
            IList<string> identfiableIds)
        {
            this._agencyId = agencyId;
            this._maintainableId = maintainableId;

            if (!string.IsNullOrWhiteSpace(version))
            {
                this._version = VersionableUtil.FormatVersion(version);
            }

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

            if (!ObjectUtil.ValidCollection(identfiableIds) && !targetStructureEnum.IsMaintainable
                && targetStructureEnum.EnumType != SdmxStructureEnumType.Any)
            {
                throw new ArgumentException(
                    "Can not create reference, target structure is not maintainable, and no identifiable reference parameters present");
            }

            this._targetStructureType = targetStructureEnum;

            if (!targetStructureEnum.IsMaintainable && targetStructureEnum.IsIdentifiable)
            {
                if (identfiableIds != null && identfiableIds.Count > 0)
                {
                    //// TODO set this._childReference only on ctor to make it read-only for hash method
                    this._childReference = new IdentifiableRefObjetcImpl(this, identfiableIds, targetStructureEnum);
                }

                while (true)
                {
                    targetStructureEnum = targetStructureEnum.ParentStructureType;
                    if (targetStructureEnum.IsMaintainable)
                    {
                        this._structureEnumType = targetStructureEnum;
                        break;
                    }
                }
            }
            else
            {
                this._structureEnumType = targetStructureEnum;
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="StructureReferenceImpl"/> class.
        /// </summary>
        /// <param name="urn">
        /// The urn. 
        /// </param>
        public StructureReferenceImpl(Uri urn)
        {
            if (urn == null)
            {
                throw new ArgumentNullException("urn");
            }

            // TODO make UrnUtil work with Uri
            string urnvalue = urn.ToString();
            this._hashcode = -1;
            SdmxStructureType targetStructureEnum = UrnUtil.GetIdentifiableType(urnvalue);
            UrnUtil.ValidateURN(urnvalue, targetStructureEnum);
            string[] components = UrnUtil.GetUrnComponents(urnvalue);
            this._agencyId = components[0];
            this._maintainableId = components[1];
            this._version = UrnUtil.GetVersionFromUrn(urnvalue);
            if (string.IsNullOrEmpty(this._version))
            {
                this._version = MaintainableObject.DefaultVersion;
            }

            this._targetStructureType = targetStructureEnum;

            if (!targetStructureEnum.IsMaintainable && targetStructureEnum.IsIdentifiable)
            {
                var identfiableIds = new string[components.Length - 2];

                // $$$ String[] identfiableIds = Arrays.copyOfRange(components, 2, components.length);
                Array.ConstrainedCopy(components, 2, identfiableIds, 0, components.Length - 2);
                this._childReference = new IdentifiableRefObjetcImpl(this, identfiableIds, targetStructureEnum);
                while (true)
                {
                    targetStructureEnum = targetStructureEnum.ParentStructureType;
                    if (targetStructureEnum.IsMaintainable)
                    {
                        this._structureEnumType = targetStructureEnum;
                        break;
                    }
                }
            }
            else
            {
                this._structureEnumType = targetStructureEnum;
            }
        }