using System;
using System.Net;
using System.Collections.Generic;
using System.Text;
using CookComputing.XmlRpc;

namespace TracProxy
{
    [XmlRpcUrl( "http://localhost/trac/login/xmlrpc" )]
    public interface ITicket : IXmlRpcProxy
    {
        [XmlRpcMethod( "ticket.query" )]
        int[] Query( string qstr );

        [XmlRpcMethod( "ticket.getRecentChanges" )]
        int[] GetRecentChanges( DateTime since );

        [XmlRpcMethod( "ticket.getAvailableActions" )]
        string[] GetAvailableActions( int id );

        [XmlRpcMethod( "ticket.getTicketFields" )]
        object[] GetTicketFields();

        [XmlRpcMethod( "ticket.create" )]
        int Create( string summary, string description, XmlRpcStruct attributes );

        [XmlRpcMethod( "ticket.get" )]
        object[] GetTicket( int id );

        [XmlRpcMethod( "ticket.delete" )]
        void Delete( int id );

        [XmlRpcMethod( "ticket.update" )]
        object[] Update( int id, string comment, XmlRpcStruct attributes );

        [XmlRpcMethod( "ticket.type.getAll" )]
        string[] GetAllTypes();

        [XmlRpcMethod( "ticket.resolution.getAll" )]
        string[] GetAllResolutions();

        [XmlRpcMethod( "ticket.priority.getAll" )]
        string[] GetAllPriorities();

        [XmlRpcMethod( "ticket.component.getAll" )]
        string[] GetAllComponents();

        [XmlRpcMethod( "ticket.version.getAll" )]
        string[] GetAllVersions();

        [XmlRpcMethod( "ticket.severity.getAll" )]
        string[] GetAllSeverities();

        [XmlRpcMethod( "ticket.milestone.getAll" )]
        string[] GetAllMilestones();

        [XmlRpcMethod( "ticket.status.getAll" )]
        string[] GetAllStatus();
    }

    public static class TicketAttributes
    {
        public const string Cc = "cc";
        public const string Keywords = "keywords";
        public const string Status = "status";
        public const string Type = "type";
        public const string Owner = "owner";
        public const string Version = "version";
        public const string Resolution = "resolution";
        public const string Reporter = "reporter";
        public const string Milestone = "milestone";
        public const string Component = "component";
        public const string Summary = "summary";
        public const string Description = "description";
        public const string Priority = "priority";
    }

    /// <summary>
    /// represents the information for a ticket
    /// </summary>
    public class TicketInfo
    {
        private int _ticketId;
        private DateTime _created;
        private DateTime _lastModified;
        private XmlRpcStruct _attributes;

        public TicketInfo()
        {
        }

        public TicketInfo( object[] values )
        {
            Update( values );
        }



        internal void Update( object[] values )
        {
            if ( values == null )
                throw new ArgumentNullException( "values" );

            if ( values.Length != 4 )
                throw new ArgumentException( "values should have 4 elements" );


            _ticketId = (int)values[0];

            //_created = DateHelper.ParseUnixTimestamp( (int)values[1] );

            //_lastModified = DateHelper.ParseUnixTimestamp( (int)values[2] );

            _attributes = (XmlRpcStruct)values[3];

        }

        /// <summary>
        /// The identifier for this ticket
        /// </summary>
        public int TicketId
        {
            get
            {
                return _ticketId;
            }

            set
            {
                _ticketId = value;
            }
        }

        /// <summary>
        /// date and time the ticket was created
        /// </summary>
        public DateTime Created
        {
            get
            {
                return _created;
            }

            set
            {
                _created = value;
            }
        }


        /// <summary>
        /// date and time the ticket was last modified
        /// </summary>
        public DateTime LastModified
        {
            get
            {
                return _lastModified;
            }

            set
            {
                _lastModified = value;
            }
        }

        /// <summary>
        /// The attributes for this ticket, this will include any additional fields
        /// that aren't defined explicitly as members of this class.
        /// </summary>
        public XmlRpcStruct Attributes
        {
            get
            {
                if ( _attributes == null )
                    _attributes = new XmlRpcStruct();

                return _attributes;
            }

            set
            {
                _attributes = value;
            }
        }

        public string Cc
        {
            get
            {
                return GetAttribute( TicketAttributes.Cc );
            }

            set
            {
                SetAttribute( TicketAttributes.Cc, value );
            }
        }

        public string Keywords
        {
            get
            {
                return GetAttribute( TicketAttributes.Keywords );
            }

            set
            {
                SetAttribute( TicketAttributes.Keywords, value );
            }
        }

        public string Status
        {
            get
            {
                return GetAttribute( TicketAttributes.Status );
            }

            set
            {
                SetAttribute( TicketAttributes.Status, value );
            }
        }

        public string Type
        {
            get
            {
                return GetAttribute( TicketAttributes.Type );
            }

            set
            {
                SetAttribute( TicketAttributes.Type, value );
            }
        }

        public string Owner
        {
            get
            {
                return GetAttribute( TicketAttributes.Owner );
            }

            set
            {
                SetAttribute( TicketAttributes.Owner, value );
            }
        }



        public string Version
        {
            get
            {
                return GetAttribute( TicketAttributes.Version );
            }

            set
            {
                SetAttribute( TicketAttributes.Version, value );
            }
        }

        public string Resolution
        {
            get
            {
                return GetAttribute( TicketAttributes.Resolution );
            }

            set
            {
                SetAttribute( TicketAttributes.Resolution, value );
            }
        }

        public string Reporter
        {
            get
            {
                return GetAttribute( TicketAttributes.Reporter );
            }

            set
            {
                SetAttribute( TicketAttributes.Reporter, value );
            }
        }

        public string Milestone
        {
            get
            {
                return GetAttribute( TicketAttributes.Milestone );
            }

            set
            {
                SetAttribute( TicketAttributes.Milestone, value );
            }
        }

        public string Component
        {
            get
            {
                return GetAttribute( TicketAttributes.Component );
            }

            set
            {
                SetAttribute( TicketAttributes.Component, value );
            }
        }

        public string Summary
        {
            get
            {
                return GetAttribute( TicketAttributes.Summary );
            }

            set
            {
                SetAttribute( TicketAttributes.Summary, value );
            }
        }

        public string Description
        {
            get
            {
                return GetAttribute( TicketAttributes.Description );
            }

            set
            {
                SetAttribute( TicketAttributes.Description, value );
            }
        }

        public string Priority
        {
            get
            {
                return GetAttribute( TicketAttributes.Priority );
            }

            set
            {
                SetAttribute( TicketAttributes.Priority, value );
            }
        }

        #region Support methods
        private string GetAttribute( string name )
        {
            if ( Attributes.Contains( name ) ) {
                return Convert.ToString( Attributes[name] );
            }

            return null;
        }

        private void SetAttribute( string name, string value )
        {
            if ( Attributes.Contains( name ) ) {
                Attributes[name] = value;
            }
            else {
                Attributes.Add( name, value );
            }
        }

        #endregion
    }

    public class TicketManager
    {
        private ITicket _ticket;

        public ITicket Ticket
        {
            get
            {
                return _ticket;
            }
        }

        public void Connect( string url, string userName, string password )
        {
            _ticket = (ITicket)XmlRpcProxyGen.Create( typeof( ITicket ) );
            _ticket.Url = url;
            _ticket.PreAuthenticate = true;
            _ticket.Credentials = new NetworkCredential( userName, password );
        }

        public string[] GetAvailableActions( int id )
        {
            return _ticket.GetAvailableActions( id );
        }

        public string[] GetAvailableActions( TicketInfo ticket )
        {
            ValidateTicket( ticket );
            return _ticket.GetAvailableActions( ticket.TicketId );
        }

        public int[] GetRecentChanges( DateTime since )
        {
            return _ticket.GetRecentChanges( since );
        }



        public void DeleteTicket( int ticketId )
        {
            _ticket.Delete( ticketId );
        }

        public void DeleteTicket( TicketInfo ticket )
        {
            ValidateTicket( ticket );
            DeleteTicket( ticket.TicketId );
        }

        public void UpdateTicket( TicketInfo ticket, string comment )
        {
            ValidateTicket( ticket );
            object[] values = _ticket.Update( ticket.TicketId, comment, ticket.Attributes );
            ticket.Update( values );
        }

        public void CreateTicket( TicketInfo ticket )
        {
            if ( string.IsNullOrEmpty( ticket.Summary ) )
                throw new ArgumentNullException( "ticket.Summary" );

            if ( string.IsNullOrEmpty( ticket.Description ) )
                throw new ArgumentNullException( "ticket.Description" );

            if ( string.IsNullOrEmpty( ticket.Type ) )
                throw new ArgumentNullException( "ticket.Type" );

            if ( string.IsNullOrEmpty( ticket.Priority ) )
                throw new ArgumentNullException( "ticket.Priority" );

            if ( string.IsNullOrEmpty( ticket.Component ) )
                throw new ArgumentNullException( "ticket.Component" );

            XmlRpcStruct tempAttributes = new XmlRpcStruct();
            foreach ( object key in ticket.Attributes.Keys ) {
                if ( (((string)key) != TicketAttributes.Description) && (((string)key) != TicketAttributes.Summary) ) {
                    tempAttributes.Add( key, ticket.Attributes[key] );
                }
            }

            int id = _ticket.Create( ticket.Summary, ticket.Description, ticket.Attributes );
            ticket.TicketId = id;
        }

        private void ValidateTicket( TicketInfo ticket )
        {
            if ( ticket == null )
                throw new ArgumentNullException( "ticket" );

            if ( ticket.TicketId <= 0 )
                throw new ArgumentException( "ticketId must be greater then 0" );
        }
    }
}
