/* Copyright (c) 2006 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/
#region Using directives

#define USE_TRACING

using System;
using System.Xml;
using System.IO; 
using System.Globalization;
using System.ComponentModel;
using System.Runtime.InteropServices;

#endregion

//////////////////////////////////////////////////////////////////////
// <summary>Contains AtomSource, an object to represent the atom:source
// element.</summary> 
//////////////////////////////////////////////////////////////////////
namespace Google.GData.Client
{
#if WindowsCE || PocketPC
#else
    //////////////////////////////////////////////////////////////////////
    /// <summary>TypeConverter, so that AtomHead shows up in the property pages
    /// </summary> 
    //////////////////////////////////////////////////////////////////////
    [ComVisible(false)]
    public class AtomSourceConverter : ExpandableObjectConverter
    {
        ///<summary>Standard type converter method</summary>
        public override bool CanConvertTo(ITypeDescriptorContext context, System.Type destinationType) 
        {
            if (destinationType == typeof(AtomSource) || destinationType == typeof(AtomFeed))
                return true;

            return base.CanConvertTo(context, destinationType);
        }

        ///<summary>Standard type converter method</summary>
        public override object ConvertTo(ITypeDescriptorContext context,CultureInfo culture, object value, System.Type destinationType) 
        {
            AtomSource atomSource = value as AtomSource;

            if (destinationType == typeof(System.String) && atomSource != null)
            {
                return "Feed: " + atomSource.Title;
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }

    }
    /////////////////////////////////////////////////////////////////////////////
#endif 

    //////////////////////////////////////////////////////////////////////
    /// <summary>Represents the AtomSource object. If an atom:entry is copied from one feed 
    /// into another feed, then the source atom:feed's metadata (all child elements of atom:feed other
    /// than the atom:entry elements) MAY be preserved within the copied entry by adding an atom:source 
    /// child element, if it is not already present in the entry, and including some or all of the source
    /// feed's Metadata elements as the atom:source element's children. Such metadata SHOULD be preserved 
    /// if the source atom:feed contains any of the child elements atom:author, atom:contributor, 
    /// atom:rights, or atom:category and those child elements are not present in the source atom:entry.
    /// </summary> 
/*
atomSource =
    element atom:source {
       atomCommonAttributes,
       (atomAuthor?
        & atomCategory*
        & atomContributor*
        & atomGenerator?
        & atomIcon?
        & atomId?
        & atomLink*
        & atomLogo?
        & atomRights?
        & atomSubtitle?
        & atomTitle?
        & atomUpdated?
        & extensionElement*)
    }
*/
    //////////////////////////////////////////////////////////////////////
#if WindowsCE || PocketPC
#else
    [TypeConverterAttribute(typeof(AtomSourceConverter)), DescriptionAttribute("Expand to see the options for the feed")]
#endif
    public class AtomSource : AtomBase
    {
        /// <summary>author collection</summary> 
        private AtomPersonCollection authors;
        /// <summary>contributors collection</summary> 
        private AtomPersonCollection contributors;
        /// <summary>category collection</summary> 
        private AtomCategoryCollection categories;
        /// <summary>the generator</summary> 
        private AtomGenerator generator;
        /// <summary>icon, essentially an atom link</summary> 
        private AtomIcon icon;
        /// <summary>ID</summary> 
        private AtomId id;
        /// <summary>link collection</summary> 
        private AtomLinkCollection links;
        /// <summary>logo, essentially an image link</summary> 
        private AtomLogo logo;
        /// <summary>rights, former copyrights</summary> 
        private AtomTextConstruct rights;
        /// <summary>subtitle as string</summary> 
        private AtomTextConstruct subTitle;
        /// <summary>title property as string</summary> 
        private AtomTextConstruct title;
        /// <summary>updated time stamp</summary> 
        private DateTime updated;


        //////////////////////////////////////////////////////////////////////
        /// <summary>public void AtomSource()</summary> 
        //////////////////////////////////////////////////////////////////////
        public AtomSource()
        {
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>public AtomSource(AtomFeed feed)</summary> 
        //////////////////////////////////////////////////////////////////////
        public AtomSource(AtomFeed feed) : this()
        {
            Tracing.Assert(feed != null, "feed should not be null");
            if (feed == null)
            {
                throw new ArgumentNullException("feed"); 
            }
            
            // now copy them
            this.authors = feed.Authors;
            this.contributors = feed.Contributors;
            this.categories = feed.Categories;
            this.Generator = feed.Generator;
            this.Icon = feed.Icon;
            this.Logo = feed.Logo;
            this.Id = feed.Id;
            this.links = feed.Links;
            this.Rights = feed.Rights;
            this.Subtitle = feed.Subtitle;
            this.Title = feed.Title;
            this.Updated = feed.Updated;
        }
        /////////////////////////////////////////////////////////////////////////////



        //////////////////////////////////////////////////////////////////////
        /// <summary>accessor method public Contributors AtomPersonCollection</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public AtomPersonCollection Authors
        {
            get 
            {
                if (this.authors == null)
                {
                    this.authors = new AtomPersonCollection();
                }
                return this.authors; 
            }
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>accessor method public Contributors AtomPersonCollection</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public AtomPersonCollection Contributors
        {
            get 
            {
                if (this.contributors == null)
                {
                    this.contributors = new AtomPersonCollection();
                }
                return this.contributors; 
            }
        }
        /////////////////////////////////////////////////////////////////////////////



        //////////////////////////////////////////////////////////////////////
        /// <summary>accessor method public Links AtomLinkCollection</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public AtomLinkCollection Links
        {
            get 
            {
                if (this.links == null)
                {
                    this.links = new AtomLinkCollection();
                }
                return this.links; 
            }
        }
        /////////////////////////////////////////////////////////////////////////////



        //////////////////////////////////////////////////////////////////////
        /// <summary>returns the category collection</summary> 
        //////////////////////////////////////////////////////////////////////
        public AtomCategoryCollection Categories
        {
            get 
            {
                if (this.categories == null)
                {
                    this.categories = new AtomCategoryCollection();
                }
                return this.categories; 
            }
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>accessor method public FeedGenerator Generator</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public AtomGenerator Generator
        {
            get {return this.generator;}
            set {this.Dirty = true;  this.generator = value;}
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>accessor method public AtomIcon Icon</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public AtomIcon Icon
        {
            get {return this.icon;}
            set {this.Dirty = true;  this.icon = value;}
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>accessor method public AtomLogo Logo</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public AtomLogo Logo
        {
            get {return this.logo;}
            set {this.Dirty = true;  this.logo = value;}
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>accessor method public DateTime LastUpdated</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public DateTime Updated
        {
            get {return this.updated;}
            set {this.Dirty = true;  this.updated = value;}
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>accessor method public string Title</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public AtomTextConstruct Title
        {
            get {return this.title;}
            set {this.Dirty = true;  this.title = value;}
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>accessor method public string Subtitle</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public AtomTextConstruct Subtitle
        {
            get {return this.subTitle;}
            set {this.Dirty = true;  this.subTitle = value;}
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>accessor method public string Id</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public AtomId Id
        {
            get {return this.id;}
            set {this.Dirty = true;  this.id = value;}
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>accessor method public string Rights</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public AtomTextConstruct Rights
        {
            get {return this.rights;}
            set {this.Dirty = true;  this.rights = value;}
        }
        /////////////////////////////////////////////////////////////////////////////

        #region Persistence overloads

        //////////////////////////////////////////////////////////////////////
        /// <summary>Returns the constant representing this XML element.</summary> 
        //////////////////////////////////////////////////////////////////////
        public override string XmlName 
        {
            get { return AtomParserNameTable.XmlSourceElement; }
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>saves the inner state of the element</summary> 
        /// <param name="writer">the xmlWriter to save into </param>
        //////////////////////////////////////////////////////////////////////
        protected override void SaveInnerXml(XmlWriter writer)
        {
            base.SaveInnerXml(writer);
            // saving Authors
            foreach (AtomPerson person in this.Authors)
            {
                person.SaveToXml(writer);
            }
            // saving Contributors
            foreach (AtomPerson person in this.Contributors)
            {
                person.SaveToXml(writer);
            }
            // saving Categories
            foreach (AtomCategory category in this.Categories )
            {
                category.SaveToXml(writer);
            }
            // saving the generator
            if (this.Generator != null)
            {
                this.Generator.SaveToXml(writer);
            }
            // save the icon
            if (this.Icon != null)
            {
                this.Icon.SaveToXml(writer);
            }
            // save the logo
            if (this.Logo != null)
            {
                this.Logo.SaveToXml(writer);
            }
            // save the ID
            if (this.Id != null)
            {
                this.Id.SaveToXml(writer);
            }
            // save the Links
            foreach (AtomLink link in this.Links)
            {
                link.SaveToXml(writer);
            }
            if (this.Rights != null)
            {
                this.Rights.SaveToXml(writer);
            }
            if (this.Subtitle != null)
            {
                this.Subtitle.SaveToXml(writer);
            }
            if (this.Title != null)
            {
                this.Title.SaveToXml(writer);
            }
            // date time construct, save here.
            WriteLocalDateTimeElement(writer, AtomParserNameTable.XmlUpdatedElement, this.Updated);
        }
        /////////////////////////////////////////////////////////////////////////////
        #endregion


        #region overloaded for property changes, xml:base
        //////////////////////////////////////////////////////////////////////
        /// <summary>just go down the child collections</summary> 
        /// <param name="uriBase"> as currently calculated</param>
        //////////////////////////////////////////////////////////////////////
        internal override void BaseUriChanged(AtomUri uriBase)
        {
            base.BaseUriChanged(uriBase);

            foreach (AtomPerson person in this.Authors)
            {
                person.BaseUriChanged(uriBase);
            }
            // saving Contributors
            foreach (AtomPerson person in this.Contributors)
            {
                person.BaseUriChanged(uriBase);
            }
            // saving Categories
            foreach (AtomCategory category in this.Categories )
            {
                category.BaseUriChanged(uriBase);
            }
            // saving the generator
            if (this.Generator != null)
            {
                this.Generator.BaseUriChanged(uriBase);
            }
            // save the icon
            if (this.Icon != null)
            {
                this.Icon.BaseUriChanged(uriBase);
            }
            // save the logo
            if (this.Logo != null)
            {
                this.Logo.BaseUriChanged(uriBase);
            }
            // save the ID
            if (this.Id != null)
            {
                this.Id.BaseUriChanged(uriBase);
            }
            // save the Links
            foreach (AtomLink link in this.Links)
            {
                link.BaseUriChanged(uriBase);
            }

            if (this.Rights != null)
            {
                this.Rights.BaseUriChanged(uriBase);
            }
            if (this.Subtitle != null)
            {
                this.Subtitle.BaseUriChanged(uriBase);
            }
            if (this.Title != null)
            {
                this.Title.BaseUriChanged(uriBase);
            }

        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>calls the action on this object and all children</summary> 
        /// <param name="action">an IAtomBaseAction interface to call </param>
        /// <returns>true or false, pending outcome</returns>
        //////////////////////////////////////////////////////////////////////
        public override bool WalkTree(IBaseWalkerAction action)
        {
            if (base.WalkTree(action)==true)
            {
                return true;
            }

            foreach (AtomPerson person in this.Authors)
            {
                if (person.WalkTree(action)==true)
                {
                    return true;
                }
            }
            // saving Contributors
            foreach (AtomPerson person in this.Contributors)
            {
                if (person.WalkTree(action)==true)
                {
                    return true;
                }
            }
            // saving Categories
            foreach (AtomCategory category in this.Categories )
            {
                if (category.WalkTree(action)==true)
                {
                    return true;
                }

            }
            // saving the generator
            if (this.Generator != null)
            {
                if (this.Generator.WalkTree(action)==true)
                {
                    return true;
                }
            }
            // save the icon
            if (this.Icon != null)
            {
                if (this.Icon.WalkTree(action)==true)
                {
                    return true;
                }

            }
            // save the logo
            if (this.Logo != null)
            {
                if (this.Logo.WalkTree(action)==true)
                {
                    return true;
                }
            }
            // save the ID
            if (this.Id != null)
            {
                if (this.Id.WalkTree(action)==true)
                {
                    return true;
                }
            }
            // save the Links
            foreach (AtomLink link in this.Links)
            {
                
                if (link.WalkTree(action)==true)
                {
                    return true;
                }

            }

            if (this.Rights != null)
            {
                if (this.Rights.WalkTree(action)==true)
                {
                    return true;
                }

            }
            if (this.Subtitle != null)
            {
                if (this.Subtitle.WalkTree(action)==true)
                {
                    return true;
                }

            }
            if (this.Title != null)
            {
                if (this.Title.WalkTree(action)==true)
                {
                    return true;
                }
            }

            return false;
        }
        #endregion
    }
    /////////////////////////////////////////////////////////////////////////////
}    /////////////////////////////////////////////////////////////////////////////

