using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Collections;
using Yaulw.Tools;
using System.IO;

namespace Installables.All
{
    /// <summary>
    /// Serializable Xml Object used to store all Configuration data
    /// </summary>
    [XmlRoot("ComponentConfig", Namespace = "BridgeConnect", IsNullable = false)]
    public class ComponentConfig
    {
        public ComponentW BinaryComponents = null;
        public ComponentW SetupComponents = null;

        /// <summary>
        /// XML Embedded Component Configuration
        /// </summary>
        public ComponentConfig()
        {
            BinaryComponents = new ComponentW();
            SetupComponents = new ComponentW();
        }

        /// <summary>
        ///  Wrapper class for multiple Components
        /// </summary>
        public class ComponentW
        {
            private ArrayList m_ArrayList;
            public ComponentW()
            {
                m_ArrayList = new ArrayList();
            }

            [XmlElement("Component")]
            public Component[] Components
            {
                get
                {
                    Component[] components = new Component[m_ArrayList.Count];                    
                    m_ArrayList.CopyTo(components);
                    return components;
                }
                set
                {
                    if (value == null) return;
                    Component[] components = (Component[])value;
                    m_ArrayList.Clear();
                    foreach (Component component in components)
                             AddUpdateComponent(component.UniqueLabel, component.Version, component.FileName);
                }
            }

            #region Public Helpers

            /// <summary>
            /// Call this function to Add/Update a component
            /// </summary>
            /// <param name="UniqueLabel">unique label used to identify a component</param>
            /// <param name="Version">Version of the component</param>
            /// <param name="FileName">FileName of the component</param>            
            public void AddUpdateComponent(string UniqueLabel, string Version, string FileName)
            {
                int nIndex = GetIndexForComponent(UniqueLabel);
                if (nIndex != -1)
                {
                    Component component = ((Component)m_ArrayList[nIndex]);
                    component.UniqueLabel = UniqueLabel;
                    component.Version = Version;
                    component.FileName = FileName;
                }
                else
                {
                    m_ArrayList.Add(new Component(UniqueLabel, Version, FileName));
                }
            }

            /// <summary>
            /// Call this function to remove a component from the list
            /// </summary>
            /// <param name="UniqueLabel">unique label used to identify a component</param>
            public void RemoveComponent(string UniqueLabel)
            {
                int nIndex = GetIndexForComponent(UniqueLabel);
                if (nIndex != -1)
                    m_ArrayList.RemoveAt(nIndex);
            }

            /// <summary>
            /// Checks to see if a component already exists
            /// </summary>
            /// <param name="UniqueLabel">unique name identifying the component</param>
            /// <returns>true for yes, no otherwise</returns>
            public bool ComponentExists(string UniqueLabel)
            {
                return (GetIndexForComponent(UniqueLabel) != -1);
            }

            /// <summary>
            /// Retrieves the component for the specified UniqueLabel
            /// </summary>
            /// <param name="UniqueLabel">unique name identifying the component</param>
            /// <returns>the Component for the Label, or null if not found</returns>
            public Component GetComponent(string UniqueLabel)
            {
                int nIndex = GetIndexForComponent(UniqueLabel);
                if (nIndex != -1)
                    return (Component) m_ArrayList[nIndex];
                else
                    return null;
            }

            #endregion

            #region Internal & Private Helpers

            /// <summary>
            /// gets the index in the array list for the specified component
            /// </summary>
            /// <param name="UniqueLabel">unique name identifying the component</param>
            /// <returns>index >= 0  or -1 if not found</returns>
            private int GetIndexForComponent(string UniqueLabel)
            {
                for (int i = 0; i < m_ArrayList.Count; ++i)
                {
                    Component component = (Component)m_ArrayList[i];
                    if (String.Compare(component.UniqueLabel, UniqueLabel, true) == 0)
                        return i;
                }
                return -1;
            }

            #endregion
        }

        /// <summary>
        /// specify the Component
        /// </summary>
        public class Component : IComparable
        {
            public Component() { }
            public Component(string UniqueLabel, string Version, string FileName) { this.UniqueLabel = UniqueLabel; this.Version = Version; this.FileName = FileName; }

            [XmlText]
            public string FileName = "";

            /// <summary>
            /// In case a component has multiple files, seperated by a ';', internally we should always call this
            /// </summary>
            public string[] FileNames
            {
                get
                {
                    if (!String.IsNullOrEmpty(FileName))
                    {
                        if (FileName.Contains(';'))
                            return FileName.Split(';');
                        else
                            return new string[] { FileName };
                    }
                    return new string[] { };
                }
            }

            [XmlAttribute("UniqueLabel")]
            public string UniqueLabel = "";

            [XmlAttribute("Version")]
            public string Version = "";

            /// <summary>
            /// In case a component has multiple files, seperated by a ';', internally we should always call this
            /// </summary>
            public string[] TempFileNamesNPath
            {
                get
                {
                    string[] files = FileNames;
                    List<string> tFiles = new List<string>();
                    if (files != null)
                    {
                        string strPath = PathNaming.PathEndsWithSlash(Path.GetTempPath());
                        foreach (string file in files)
                                 tFiles.Add(strPath + file);
                        return tFiles.ToArray();
                    }
                    return new string[] { };
                }
            }

            #region IComparable Members

            /// <summary>
            /// Compares the Components Unique Label and Version
            /// </summary>
            /// <param name="obj"></param>
            /// <returns></returns>
            public int CompareTo(object obj)
            {
                if (obj is Component)
                {
                    Component c = (Component)obj;
                    int nCompare = String.Compare(this.UniqueLabel, c.UniqueLabel, true);
                    if (nCompare == 0)
                        nCompare = String.Compare(this.Version, c.Version, true);
                    return nCompare;
                }
                else
                {
                    throw new ArgumentException("object is not a Component");
                }
            }

            #endregion
        }
    }
}
