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

namespace pmsDataGridView
{
    public class ProductRef
    {
        #region Constructor and Destructor

        public ProductRef() { }
        public ProductRef(string name, string id, int ind, int qty)
        {
            this.name = name;
            ID = id;
            index = ind;
            quantity = qty;
        }
        ~ProductRef() { }

        #endregion

        //Methods
        public void copy(ProductRef sample)
        {
            this.name = sample.name;
            this.ID = sample.ID;
            this.index = sample.index;
            this.quantity = sample.quantity;
        }
        //Variables
        public string name;
        public string ID = null; //or part number
        public int index = -1; //index in the master product list
        public int quantity = 0;

    }

    public class ClusterTable
    {
        #region Constructor and Distructor
        public ClusterTable()
        {
            subItemList = new ArrayList();
        }
        public ClusterTable(string name, string id, int ind)
        {
            this.ClusterName = name;
            ClusterProductID = id;
            ClusterProductIndex = ind;
            subItemList = new ArrayList();
        }
        ~ClusterTable() { }
        #endregion

        #region Methods

        public void add(ProductRef b)
        {
            subItemList.Add(b); //add to list
        }


        public ProductRef get_ProductRef(int location) //0 based index  
        {
            if (location < subItemList.Count)
            {
                return (ProductRef)subItemList[location];
            }
            else return null;
        }

        public int Count
        {
            get { return subItemList.Count; }
        }

        public void remove(int location) //0 based index  
        {
            if (location < subItemList.Count)
            {
                subItemList.RemoveAt(location);
            }
            else return;
        }

        public void copy(ClusterTable sample)
        {
            this.ClusterName = sample.ClusterName;
            this.subItemList = sample.subItemList;
            this.ClusterProductID = sample.ClusterProductID;
            this.ClusterProductIndex = sample.ClusterProductIndex;
            this.commonDBdirectory = sample.commonDBdirectory;
        }

        #endregion

        #region XML read and write methods
        
        //Indexer
        public ProductRef this[int location]
        {
            get { return (ProductRef)subItemList[location]; }
            set { subItemList[location] = value; }
        }
        
        [XmlElement("Cluster_Table")]
        //this is a property, when use: item.items[0], returns an item
        public ProductRef[] ProductRefs
        {
            get
            {
                ProductRef[] ProductRefs = new ProductRef[subItemList.Count];
                subItemList.CopyTo(ProductRefs);
                return ProductRefs;
            }

            set
            {
                if (value == null) return;
                ProductRef[] ProductRefs = (ProductRef[])value;
                subItemList.Clear();
                foreach (ProductRef b in ProductRefs)
                {
                    subItemList.Add(b);
                    //this Add is the built-in method of arraylist, not my own method in the ClusterTable class
                }
            }
        }
        
        public virtual void save_as(string filename)
        {
            string FilePath = commonDBdirectory + filename;
            // Serialization
            XmlSerializer ser = new XmlSerializer(typeof(ClusterTable));
            TextWriter xml_write = new StreamWriter(FilePath);

            ser.Serialize(xml_write, this);
            xml_write.Close();
        }

        public virtual void load(string filename)
        {
            string FilePath = commonDBdirectory + filename;
            ClusterTable temp = new ClusterTable();
            // Deserialization             
            XmlSerializer ser = new XmlSerializer(typeof(ClusterTable));

            if (FilePath != null)
            {
                TextReader xml_read = new StreamReader(FilePath);

                temp = (ClusterTable)ser.Deserialize(xml_read);

                copy(temp);
                xml_read.Close();
            }

        }

        #endregion

        #region Private variables

        //public ArrayList clusterlookuptables;
        private ArrayList subItemList;
        public string ClusterName;
        public string ClusterProductID;
        public int ClusterProductIndex; //index in the master product list
        [XmlIgnore]
        public string commonDBdirectory = "../../ProgramData/";     
        #endregion
    }

    public class ClusterTableList
    {
        #region Constructor and Distructor
        public ClusterTableList()
        {
            tables = new ArrayList();
        }
        ~ClusterTableList() { }
        #endregion

        #region Methods

        public void add(ClusterTable b)
        {
            tables.Add(b); //add to list
        }

        public ClusterTable get_ClusterTable(int location) //0 based index  
        {
            if (location < tables.Count)
            {
                return (ClusterTable)tables[location];
            }
            else return null;
        }

        public int Count
        {
            get { return tables.Count; }
        }

        public void remove(int location) //0 based index  
        {
            if (location < tables.Count)
            {
                tables.RemoveAt(location);
            }
            else return;
        }

        public void copy(ClusterTableList sample)
        {
            this.tables = sample.tables;
        }

        public void update_tables_from_txt_file(ProductList bearinglist)
        {//it also update the indices of the sub item for each clustered product
            string FilePath = commonDBdirectory + "clusters.txt";
            //if file doesn't exist, create one
            if (File.Exists(FilePath)==false)
            {
                File.CreateText(FilePath);                                             
            }             
            StreamReader sr = new StreamReader(FilePath);
            //clear the current table, and fill in based on the txt file
            tables.Clear();
            while (sr.EndOfStream == false)
            {
                string str = sr.ReadLine();
                if (str != "")//means a new cluster starts
                {
                    //get the clustered product's name
                    Product clustered_product = search_product(str, bearinglist);
                    ClusterTable ct = new ClusterTable(clustered_product.name, clustered_product.ID, clustered_product.MasterListIndex);
                    //read the next line
                    str = sr.ReadLine();
                    while (str != "")
                    {
                        Product sub_item = search_product(str, bearinglist);
                        //read quantity
                        int qty = Convert.ToInt32(sr.ReadLine());
                        ProductRef pr = new ProductRef(sub_item.name, sub_item.ID, sub_item.MasterListIndex, qty);
                        ct.add(pr);
                        //read the next line before going back to the while loop
                        str = sr.ReadLine();
                    }
                    tables.Add(ct);
                }

            }

            sr.Close();
        }

        public Product search_product(string name, ProductList bearinglist)
        {
            Product b = new Product();
            for (int i = 0; i < bearinglist.Count; i++)
            {
                if (bearinglist[i].name == name)
                {
                    b.copy(bearinglist[i]);
                    break;
                }
            }
            return b;
        }
        
        #endregion

        #region XML read and write methods

        //Indexer
        public ClusterTable this[int location]
        {
            get { return (ClusterTable)tables[location]; }
            set { tables[location] = value; }
        }

        [XmlElement("Cluster_Table_List")]
        //this is a property, when use: item.items[0], returns an item
        public ClusterTable[] ClusterTables
        {
            get
            {
                ClusterTable[] ClusterTables = new ClusterTable[tables.Count];
                tables.CopyTo(ClusterTables);
                return ClusterTables;
            }

            set
            {
                if (value == null) return;
                ClusterTable[] ClusterTables = (ClusterTable[])value;
                tables.Clear();
                foreach (ClusterTable b in ClusterTables)
                {
                    tables.Add(b);
                    //this Add is the built-in method of arraylist, not my own method in the ClusterTableList class
                }
            }
        }

        public virtual void save_as(string filename)
        {
            string FilePath = commonDBdirectory + filename;
            // Serialization
            XmlSerializer ser = new XmlSerializer(typeof(ClusterTableList));
            TextWriter xml_write = new StreamWriter(FilePath);

            ser.Serialize(xml_write, this);
            xml_write.Close();
        }

        public virtual void load(string filename)
        {
            string FilePath = commonDBdirectory + filename;
            ClusterTableList temp = new ClusterTableList();
            // Deserialization             
            XmlSerializer ser = new XmlSerializer(typeof(ClusterTableList));

            if (FilePath != null && File.Exists(FilePath))
            {
                TextReader xml_read = new StreamReader(FilePath);

                temp = (ClusterTableList)ser.Deserialize(xml_read);

                copy(temp);
                xml_read.Close();
            }

        }

        #endregion

        #region Private variables

        //public ArrayList clusterlookuptables;
        private ArrayList tables;
        public string commonDBdirectory = "../../ProgramData/";
        public string DatabaseName;
        #endregion
    }
}
