/// <summary>
        /// Create a New Contact
        /// </summary>        
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="contact">Contact to be created</param>        
        /// <remarks>The POST data presents only values for EmailAddress, FirstName, LastName, OptInSource and ContactLists elements</remarks>        
        /// <exception cref="ArgumentNullException">Thrown if specified Contact is null</exception>
        /// <exception cref="ArgumentException">Thrown if E-mail Address of specified Contact is null or empty</exception>
        /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
        /// or other related with the response from server or if specified Contact does not belongs to any list
        /// or if ApiKey, Username or Password are null or empty</exception>
        /// <returns>Newly created Contact</returns>
        public static Contact CreateNewContact(AuthenticationData authenticationData, Contact contact)
        {
            ValidateAuthenticationData(authenticationData);

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

            if (string.IsNullOrEmpty(contact.EmailAddress))
            {
                throw new ArgumentException("Contact E-mail Address cannot be null or empty", "contact");
            }

            if (null == contact.ContactLists
                || contact.ContactLists.Count == 0)
            {
                throw new ConstantException("Contact does not belongs to any contact list");
            }

            // get the Atom entry for specified Contact
            StringBuilder data = ContactComponent.CreateNewContact(contact, authenticationData.AccountContactListsUri);

            Stream stream = Stream.Null;
            try
            {
                // post the Atom entry at specified Uri and save the response stream
                stream = PostInformation(authenticationData, new Uri(authenticationData.AccountContactsUri),
                                         data.ToString());

                // return newly created Contact
                return ContactComponent.GetContactDetails(stream);
            }
            catch (Exception e)
            {
                throw new ConstantException(e.Message, e);
            }
            finally
            {
                // close the response stream
                stream.Close();
            }
        }
        /// <summary>
        /// Update a Contact
        /// </summary>
        /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
        /// <param name="contact">Contact to be updated</param>
        /// <exception cref="ArgumentNullException">Thrown if specified Contact is null</exception>
        /// <exception cref="ArgumentException">Thrown if Id or Email Address of specified Contact is null or empty</exception>        
        /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
        /// or other related with the response from server, if no Contact with specified Id exists 
        /// or if Contact cannot be updated (it belongs to the Do-Not-Mail list)
        /// or if ApiKey, Username or Password are null or empty</exception>        
        private static void UpdateContact(AuthenticationData authenticationData, Contact contact)
        {
            bool fullUpdate = true;
            ValidateAuthenticationData(authenticationData);

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

            if (string.IsNullOrEmpty(contact.Id))
            {
                throw new ArgumentException("Contact Id cannot be null or empty", "contact");
            }

            if (string.IsNullOrEmpty(contact.EmailAddress))
            {
                throw new ArgumentException("Contact Email Address cannot be null or empty", "contact");
            }

            // create the URI for specified Contact Id
            string completeUri = String.Format(CultureInfo.InvariantCulture, "{0}{1}",
                                               AuthenticationData.HostAddress, contact.Link);

            // get the Atom entry for specified Contact
            StringBuilder data = ContactComponent.UpdateContact(contact, authenticationData.ApiRootUri,
                                                                authenticationData.AccountContactListsUri, fullUpdate);

            try
            {
                // put the Atom entry at specified Uri
                PutInformation(authenticationData, new Uri(completeUri), data.ToString());
            }
            catch (Exception e)
            {
                if (string.Compare(e.Message, WebExceptionCode404Message) == 0)
                {
                    throw new ConstantException(String.Format(CultureInfo.InvariantCulture,
                                                              "Contact with Id '{0}' does not exist.", contact.Id));
                }
                if (string.Compare(e.Message, WebExceptionCode403Message) == 0)
                {
                    throw new ConstantException("Contact cannot be updated. It belongs to the Do-Not-Mail list.");
                }

                throw new ConstantException(e.Message, e);
            }
        }
        /// <summary>
        /// Retrieves all list members of selected node.
        /// </summary>
        /// <remarks>Constant Contact server provides paged collections</remarks>
        /// <param name="link">Link to target list</param>   
        /// <param name="Authdata">Authentication data (username, password and API Key)</param>
        /// <param name="nextChunk">Link to the next chunk data</param>       
        /// <returns>The collection of Contact List Members</returns>
        public static IList<Contact> getListMembers(string link, AuthenticationData Authdata, out string nextChunk)
        {
            if (string.IsNullOrEmpty(link))
            {
                throw new ArgumentException("list link cannot be null or empty", "link");
            }
            //Create new xmldocument, create memberslist uri, GET, load XML.
            XmlDocument xDoc = new XmlDocument();
            //If initial chunk, append /members to URI, if next link, no need to append /members, use link as is.
            string membersURI;
            if (link.Contains("next") == true)
            {
                membersURI = link;
            }
            else
            {
                membersURI = "https://api.constantcontact.com" + link + "/members";
            }
            try
            {
                xDoc.LoadXml(Utility.httpGet(Authdata, membersURI));
                //Define namespaces
                XmlNamespaceManager xnsmgr = new XmlNamespaceManager(xDoc.NameTable);
                xnsmgr.AddNamespace("ns1", "http://www.w3.org/2005/Atom");
                xnsmgr.AddNamespace("ns2", "http://ws.constantcontact.com/ns/1.0/");
                //Check for link to next chunk of data. If no next chunk, return empty string.
                nextChunk = "";
                XmlNodeList xnlLinks = xDoc.SelectNodes("//ns1:link", xnsmgr);
                foreach (XmlNode xnLink in xnlLinks)
                {
                    if (xnLink.Attributes["rel"] != null)
                    {
                        if (xnLink.Attributes["rel"].Value == "next")
                        {
                            nextChunk = xnLink.Attributes["href"].Value;
                        }
                    }
                }
                //Select nodes
                XmlNodeList xnlListMembers = xDoc.SelectNodes("//ns2:ContactListMember", xnsmgr);
                //parse XML for ID, EMail address, Name info
                IList<Contact> listmembers = new List<Contact>();
                foreach (XmlNode xnMember in xnlListMembers)
                {
                    XmlNode xnLink = xnMember.SelectSingleNode("../../ns1:link", xnsmgr);
                    string sLink = xnLink.Attributes["href"].Value;

                    XmlNode xnID = xnMember.SelectSingleNode("../../ns1:id", xnsmgr);
                    string sID = xnID.InnerText;

                    XmlNode xnEmailAddress = xnMember.SelectSingleNode("ns2:EmailAddress", xnsmgr);
                    string sEmailAddress = xnEmailAddress.InnerText;

                    XmlNode xnName = xnMember.SelectSingleNode("ns2:Name", xnsmgr);
                    string sName = xnName.InnerText;

                    Contact listmember = new Contact();
                    listmember.Link = sLink;
                    listmember.Id = sID;
                    listmember.Name = sName;
                    listmember.EmailAddress = sEmailAddress;
                    listmembers.Add(listmember);
                }
                //return list of listmembers
                return listmembers;
            }
            catch (Exception e)
            {
                if (string.Compare(e.Message, WebExceptionCode404Message) == 0)
                {
                    throw new ConstantException(String.Format(CultureInfo.InvariantCulture,
                                                              "Link to '{0}' does not exist.", link));
                }

                throw new ConstantException(e.Message, e);
            }
        }
 /// <summary>
 /// Update a Contact using the full form. All Contact fields will be updated
 /// </summary>
 /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
 /// <param name="contact">Contact to be updated</param>
 /// <exception cref="ArgumentNullException">Thrown if specified Contact is null</exception>
 /// <exception cref="ArgumentException">Thrown if Id or Email Address of specified Contact is null or empty</exception>        
 /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
 /// or other related with the response from server, if no Contact with specified Id exists 
 /// or if Contact cannot be updated (it belongs to the Do-Not-Mail list)
 /// or if ApiKey, Username or Password are null or empty</exception>        
 public static void UpdateContactFullForm(AuthenticationData authenticationData, Contact contact)
 {
     UpdateContact(authenticationData, contact);
 }
 /// <summary>
 /// Update a Contact using the simplified form. Only the following fields will be updated: 
 /// EmailAddress, FirstName, LastName, MiddleName, HomePhone, Addr1, Addr2, Addr3,
 /// City, StateCode, StateName, CountryCode, CountryName, PostalCode, SubPostalCode
 /// </summary>
 /// <param name="authenticationData">Authentication data (username, password and API Key)</param>
 /// <param name="contact">Contact to be updated</param>
 /// <exception cref="ArgumentNullException">Thrown if specified Contact is null</exception>
 /// <exception cref="ArgumentException">Thrown if Id or Email Address of specified Contact is null or empty</exception>        
 /// <exception cref="ConstantException">Thrown if communication error with Constant server occur 
 /// or other related with the response from server, if no Contact with specified Id exists 
 /// or if Contact cannot be updated (it belongs to the Do-Not-Mail list)
 /// or if ApiKey, Username or Password are null or empty</exception>        
 public static void UpdateContactSmallForm(AuthenticationData authenticationData, Contact contact)
 {
     UpdateContact(authenticationData, contact, false);
 }