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


namespace pmsDataGridView
{
    public class AccountRecord
    {// if I pay money, 'payee' refers to the person I pay to
     //if I receive money, 'Payee' refers to the person who pays me
        #region Constructor and Destructor
        
        public AccountRecord() { }
        public AccountRecord(string payee, int cidx, double amount, bool moneyin, string description) 
        {
            this.Date = DateTime.Now;
            this.Payee = payee;
            this.c_idx = cidx;
            this.Amount = amount;
            this.MoneyIn = moneyin;
            this.Description = description;
            //Work out the ID
            this.ID = Date.Year + Date.Month.ToString("00") + Date.Day.ToString("00") + Date.Hour.ToString("00")
                + Date.Minute.ToString("00") + Date.Second.ToString("00");
        }
        public AccountRecord(SaleRecord sale, string payee)
            : this(payee, 0, sale.Payable, true, "Product sale")
        {
            CustomerIndex = sale.CustomerIndex;
            SaleIndex = sale.Index;
            SaleID = sale.ID;         
        }

        ~AccountRecord() { }

        #endregion

        //Methods

        //Variables  
        public string ID;
        public DateTime Date; //date when money is received / spent
        public int Index=-1; //this transaction'tr index in the transaction list
        public int c_idx; //the index of the category array
        //so Category[c_idx] returns a string of the corresponding category
        public double Amount; //the transaction amount
        public double Balance = -1;
        public string Description; // or note
        public bool MoneyIn; // Money in or out
        //public string MoneyFrom; //name of customer
        public string SaleID; //if this is a sale
        public int CustomerIndex = -1; //the index in customer list
        public int SaleIndex = -1; //the index in sale list
        public string Payee;       
    }

    public class AccountLogList
    {
        #region Constructor and Distructor
        public AccountLogList()
        {
            AccountLoglist = new ArrayList();
            Categorylist = new ArrayList(); //this is a string array
            UnpaidIndex = new ArrayList();
        }
        ~AccountLogList() { }
        #endregion

        #region Methods

        public void refresh_balance()
        {//refresh the balance for each transaction
            if (this[0].MoneyIn == true)
            {
                this[0].Balance = reconciled_balance + this[0].Amount;
            }
            else //if money out
            {
                this[0].Balance = reconciled_balance - this[0].Amount;
            }
            for (int i = 1; i < Count; i++)
            {
                if (this[i].MoneyIn == true)
                {
                    this[i].Balance = this[i - 1].Balance + this[i].Amount;
                }
                else //if money out
                {
                    this[i].Balance = this[i - 1].Balance - this[i].Amount;
                }
            }
            Final_balance = this[Count - 1].Balance;
        }

        public void update_balance()
        {//add the last tansaction to the existing ones
            if (this[0].MoneyIn == true)
            {
                this[0].Balance = reconciled_balance + this[0].Amount;
            }
            else //if money out
            {
                this[0].Balance = reconciled_balance - this[0].Amount;
            }
            if (this[Count - 1].Balance == -1) //make sure it'tr a new transaction
            {                
                if (this[Count - 1].MoneyIn == true)
                {
                    this[Count - 1].Balance = this[Count - 2].Balance  + this[Count - 1].Amount;
                }
                else//if money out
                {
                    this[Count - 1].Balance = this[Count - 2].Balance - this[Count - 1].Amount;
                }                
            }
        }
        public void add(AccountRecord tr)
        {
            AccountLoglist.Add(tr);
            tr.Index = Count - 1;
            update_balance(); 
        }

        public void check_and_update_from_sale(SaleLogList sl, CustomerList cl)
        {//from the sale list, check if any new payments have been made.
            int i = this[Count - 1].SaleIndex; // the sale index of the last payment
            int j = sl[sl.Count - 1].Index; // the index of the last sale in the sale log
            if (i == j)
            {
                //if they are equal, no new sale payment need to be checked
                return;
            }
            else
            {
                for (int k = i + 1; k < j; k++)
                {
                    if (sl[k].Paid == true) //new payment is detected
                    {
                        AccountRecord ar = new AccountRecord(sl[k], cl[sl[k].CustomerIndex].Name);
                        add(ar);
                    }
                }
            }
        }

        public void refresh_unpaid_index(SaleLogList sl)
        {
            //clear the unpadi index list
            UnpaidIndex.Clear();
            for (int i = 0; i < sl.Count; i++)
            {
                if (sl[i].Paid == false)//if unpaid, jot down the index
                {
                    UnpaidIndex.Add(i);
                }
            }
        }
        public AccountRecord get_Transaction(int location) //0 based index  
        {
            if (location < AccountLoglist.Count)
            {
                return (AccountRecord)AccountLoglist[location];
            }
            else return null;
        }

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

        public void remove(int location) //0 based index  
        {
            if (location < AccountLoglist.Count)
            {
                AccountLoglist.RemoveAt(location);
                
                for (int i = location; i < Count; i++) //decrement indices of accountrecords after 'location' 
                {
                    this[i].Index--;
                }
                 
            }
            else return;
        }

        public void copy(AccountLogList sample)
        {
            this.AccountLoglist = sample.AccountLoglist;
            this.Categorylist = sample.Categorylist;
            this.UnpaidIndex = sample.UnpaidIndex;
            this.reconciled_balance = sample.reconciled_balance;
            this.Final_balance = sample.Final_balance;
        }

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

        [XmlIgnore]
        public string data_path
        {
            get { return FilePath; }
            set { FilePath = value; }
        }

        #endregion

        #region XML read and write methods

        [XmlElement("Transaction")]
        //this is a property, when use: item.items[0], returns an item
        public AccountRecord[] AccountRecords
        {
            get
            {
                AccountRecord[] accountrecords = new AccountRecord[AccountLoglist.Count];
                AccountLoglist.CopyTo(accountrecords);
                return accountrecords;
            }

            set
            {
                if (value == null) return;
                AccountRecord[] accountrecords = (AccountRecord[])value;
                AccountLoglist.Clear();
                foreach (AccountRecord b in accountrecords)
                {
                    AccountLoglist.Add(b);
                }
            }
        } 

        public virtual void save()
        {

            // Serialization
            XmlSerializer ser = new XmlSerializer(typeof(AccountLogList));
            TextWriter xml_write = new StreamWriter(FilePath);

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

        public virtual void load()
        {
            AccountLogList temp = new AccountLogList();
            // Deserialization

            XmlSerializer ser = new XmlSerializer(typeof(AccountLogList));

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

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

                copy(temp);
                xml_read.Close();
            }
            else //dont find the xml file, so creat an empty transaction list anyway
            {
                copy(temp);
            }
        }

        #endregion

        #region Private variables

        private ArrayList AccountLoglist;
        public ArrayList Categorylist;
        public ArrayList UnpaidIndex;
        public double reconciled_balance = 0;
        public double Final_balance;
        private string FilePath = @"../../ProgramData/AccountData.xml";

        #endregion
 
  

    }
}
