using System;
using System.IO;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Mail;
using System.Net;
using System.Web.UI;
using System.Drawing.Printing;
using pms_modal;


namespace pmsDataGridView
{
    public partial class MainForm : Form
    {
        public ProductList productlist = new ProductList();
        public SoldBearingList soldproductlist = new SoldBearingList();
        public SaleLogList salelist = new SaleLogList();
        public CustomerList customerlist = new CustomerList();
        public BuyinList buyinlist = new BuyinList();
        public AccountLogList transactionlist = new AccountLogList();        
        public enum TabIndexType { PRODUCT, SALELOG, CUSTOMERS, BUYIN, SALESUMMARY, FINANCIALREPORT }        
        //public enum SaleColumnType { ID, NAME, EMAIL, DATE, PAYABLE, PURCHASEEMAIL, PACKED, PAID, SENTEMAIL, INDEX }
        //public enum CustomerColumnType { NAME, USERNAME, EMAIL, FREQUENCY, ADDRESS, ADDRESSLINE1, ADDRESSLINE2, ADDRESSLINE3, COUNTRY, INDEX }
        //public enum CustomerColumnType { NAME, USERNAME, EMAIL, FREQUENCY, ADDRESS, COUNTRY, INDEX }        
        public enum SaleSummaryColumnType { ID, BEARING, QUANTITY, QTYPERMONTH, REVENUEPERMONTH, REVENUEPERYEAR, FREQUENCY, REVENUE }
        public enum TransactionColumnType { ID, DATE, CATEGORY, PAYEE, DESCRIPTION, MONEYOUT, MONEYIN, BALANCE, INDEX }
        public enum EmailType { UNSIGNED, PURCHASE, SENT }
        public bool DebugModeOn = false;
        public bool LoadingComplete = false;
        //public bool Filling_a_sale_to_list = false;
        public string barcode_input = null;
        public bool salerowdeletemode = false;
        public int TabIndexBeforeChanging = 0;
        public List<double> HighlightedNumbers = new List<double>();

        public MainForm()
        {
            InitializeComponent();
            OutputMsg1.BackColor = Color.Black;
            OutputMsg2.BackColor = Color.Black;
            OutputMsg3.BackColor = Color.Black;
            OutputMsg4.BackColor = Color.Black;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            if (InitConfig.Business == InitConfig.BusinessType.BEARING)
            {
                Text = "PMS - Bearings";
            }
            else if (InitConfig.Business == InitConfig.BusinessType.ELECTRONICS)
            {
                Text = "PMS - Electronics";
            }
            fillgrids();
        }

        #region My own functions
        private void fillgrids()
        {            
            //load productlist 
            productlist.load("ProductData.xml");
            productlist.fill_grid(ProductCatalogGrid);
            //soldbearings.save();

            //load customerlist
            customerlist.load();
            customerlist.fill_grid(CustomerGrid);
            //for (int i = 0; i < customerlist.Count; i++)
            //{               
            //    Customer c = customerlist.Customers[i];
            //    CustomerGrid.Rows.Add();
            //    fill_a_customer_to_row_i(c, i);
            //}
            //customerlist.save();
            //load salelist            
            salelist.load();
            Update_customer_index();
            salelist.fill_grid(SaleLogGrid, customerlist);
            //for (int i = 0; i < salelist.Count; i++)
            //{
            //    //salelist[last_sale_index].CustomerName = salelist[last_sale_index].Buyer.Name;                
            //    SaleRecord s = salelist.SaleRecords[i];
            //    SaleLogGrid.Rows.Add();
            //    fill_a_sale_to_row_i(s, i); 
            //}

            //load buy in
            buyinlist.load();
            //load sold bearing list                         
            soldproductlist.load();
            //soldproductlist.up_to_date_summary(productlist,salelist); //may not need to update at start up
            ShowSaleSummary();
           
            
            transactionlist.load();
            for (int i = 0; i < transactionlist.Count; i++)
            {
                //int selected_row_index = transactionlist[i].SaleIndex;
                //transactionlist[i].Payee = salelist[selected_row_index].CustomerName;
                TranscGrid.Rows.Add();                
                fill_a_transc_to_row_i(transactionlist[i], i);                               
            }

            //customerlist.add(new Customer("King Au","pkboy","kingau1999@gmail.com","ad1","ad2","ad3","New Zealand",""));
            //transactionlist.remove(77);
            LoadingComplete = true;            
        }

        private void refillgrids()
        {
            //this function is diff from fillgrids() in a way that it doens' load the database from xml files, instead, just
            //use the database in the memory
            //and currently this function only refill the three searchable lists: product, sale and customer
            productlist.fill_grid(ProductCatalogGrid);
            customerlist.fill_grid(CustomerGrid);
            salelist.fill_grid(SaleLogGrid, customerlist);            
        }

        public void load_for_blank_database()
        {
            //load transaction records
            string ca = "Sale";
            transactionlist.Categorylist.Add(ca);
            for (int i = 0; i < salelist.Count; i++)
            {
                if (salelist[i].Paid == true)
                {
                    AccountRecord ar = new AccountRecord(salelist[i], customerlist[salelist[i].CustomerIndex].Name);
                    transactionlist.add(ar);
                    int last_tran_index = transactionlist.Count - 1;
                    TranscGrid.Rows.Add();
                    fill_a_transc_to_row_i(transactionlist[last_tran_index], last_tran_index);
                }
                else //means unpaid, log it to unpaid list
                {
                    transactionlist.UnpaidIndex.Add(i);
                }
            }
        }

        //private void fill_a_sale_to_row_i(SaleRecord s, int i)
        //{//This function fills sale on a row, either replace an old sale or to add a new sale. 
        // //need to add a new row before calling this function if adding a new sale
        //    //when it's filling a sale to list, maybe due to search results, doesn't consider to change of value 
        //    //for the cell, hence shouldn't trigger SaleLogGrid_CellValueChanged
        //    Filling_a_sale_to_list = true;           
        //    //if not enought rows, add more
        //    if (i == SaleLogGrid.Rows.Count)
        //    {
        //        SaleLogGrid.Rows.Add();
        //    }
        //    //productlist.Bearings[last_sale_index].Index = last_sale_index; //reset all the indices
        //    SaleLogGrid.Rows[i].Cells[(int)SaleColumnType.ID].Value = s.ID;
        //    SaleLogGrid.Rows[i].Cells[(int)SaleColumnType.NAME].Value = customerlist[s.CustomerIndex].Name;
        //    SaleLogGrid.Rows[i].Cells[(int)SaleColumnType.EMAIL].Value = customerlist[s.CustomerIndex].Email;
        //    SaleLogGrid.Rows[i].Cells[(int)SaleColumnType.DATE].Value = s.Date.ToLongDateString();
        //    SaleLogGrid.Rows[i].Cells[(int)SaleColumnType.PAYABLE].Value = s.Payable.ToString("0.00");
        //    SaleLogGrid.Rows[i].Cells[(int)SaleColumnType.PURCHASEEMAIL].Value = s.PurchaseEmail;
        //    SaleLogGrid.Rows[i].Cells[(int)SaleColumnType.PAID].Value = s.Paid;
        //    SaleLogGrid.Rows[i].Cells[(int)SaleColumnType.PACKED].Value = s.Shipped;
        //    SaleLogGrid.Rows[i].Cells[(int)SaleColumnType.SENTEMAIL].Value = s.SentEmail;
        //    SaleLogGrid.Rows[i].Cells[(int)SaleColumnType.INDEX].Value = s.Index.ToString();
        //    Filling_a_sale_to_list = false; 
        //}

        //private void fill_a_customer_to_row_i(Customer c, int i)
        //{//This function fills sale on a row, either replace an old sale or to add a new sale. 
        //    //need to add a new row before calling this function if adding a new sale
        //    //if not enought rows, add more
        //    if (i == CustomerGrid.Rows.Count)
        //    {
        //        CustomerGrid.Rows.Add();
        //    }
        //    CustomerGrid.Rows[i].Cells[(int)CustomerColumnType.NAME].Value = c.Name;
        //    CustomerGrid.Rows[i].Cells[(int)CustomerColumnType.USERNAME].Value = c.UserName;
        //    CustomerGrid.Rows[i].Cells[(int)CustomerColumnType.EMAIL].Value = c.Email;
        //    CustomerGrid.Rows[i].Cells[(int)CustomerColumnType.ADDRESS].Value = c.Address;
        //    CustomerGrid.Rows[i].Cells[(int)CustomerColumnType.FREQUENCY].Value = c.Frequency;
        //    CustomerGrid.Rows[i].Cells[(int)CustomerColumnType.COUNTRY].Value = c.Country;
        //    CustomerGrid.Rows[i].Cells[(int)CustomerColumnType.INDEX].Value = c.Index;           
        //}

        public void ReFreshProductList()
        {
            ProductList newbl = new ProductList();
            //reindxing the bearings in the master list
            for (int i = 0; i < productlist.Count; i++)
            {
                //save_as/update the index of the bearings list as the current order appear in grid view
                int idx = Convert.ToInt32(ProductCatalogGrid.Rows[i].Cells[(int)pmsDataGridView.Product.GridColumnType.INDEX].Value);
                Product b = productlist.Bearings[idx];
                b.Index = i; //update the bearing index
                //the index and master list index in both productlist and soldproductlist should be the same
                b.MasterListIndex = i;
                newbl.add(b);
                //fill_a_product_to_row_i(b, i);
            }
            productlist = newbl;
            
            //load the Cluster Table txt file
            productlist.update_table_from_txt_file(); //cluster table is not saved, it's save when productlist is saved
            productlist.update_cluster_product_index();
            productlist.update_product_quantity();

            //update the product grid
            for (int i = 0; i < productlist.Count; i++)
            {
                productlist[i].fill_to_row_i(ProductCatalogGrid, i);
                //fill_a_product_to_row_i(productlist[i], i);
            }
            //refresh the indices of the soldproductlist
            //the index and master list index in soldproductlist should be the same
            //for (int i = 0; i < soldproductlist.Count; i++)
            //{
            //    soldproductlist[i].Index
            //}
            //refresh the master list index of the ordered bearing list in the sales
            for (int i = 0; i < salelist.Count; i++)
            {//for each sale
                for (int j = 0; j < salelist[i].BearingOrder.Count; j++)
                {//for each ordered bearing list
                    for (int k = 0; k < productlist.Count; k++)
                    {//search the match bearing from the bearing list
                        if (salelist[i].BearingOrder[j].ID == productlist[k].ID)
                        {
                            //in productlist, the index and master list index should always be the same
                            salelist[i].BearingOrder[j].MasterListIndex = productlist[k].Index;
                            break;
                        }
                    }
                }
            }
        }
        private void SaveBearings()
        {
            ReFreshProductList();
            productlist.save_as("ProductData.xml");            
        }

        private void SaveSaleLog()
        {
            //save_as/update the paid and Shipped check boxes
            //comment it out because don't want to mess up with all the packed, packed date logged as the 
            //boxes are ticked
            //for (int i = 0; i < salelist.Count; i++)
            //{
            //    update_paid_and_packed(i);
            //}
            salelist.save();
        }

        public void update_paid_and_packed(int row_index)
        {//read and update paid and ship in row last_sale_index
            int selected_sale_index = Convert.ToInt32(SaleLogGrid.Rows[row_index].Cells[(int)SaleRecord.SaleColumnType.INDEX].Value);
            object packed = SaleLogGrid.Rows[row_index].Cells[(int)SaleRecord.SaleColumnType.PACKED].Value;
            salelist.SaleRecords[selected_sale_index].Shipped = Convert.ToBoolean(packed);
            if (salelist.SaleRecords[selected_sale_index].Shipped == true) { salelist.SaleRecords[selected_sale_index].packedDate = DateTime.Now; }
            //update the sale log
            //fill_a_sale_to_row_i(salelist[selected_sale_index], row_index);

            object paid = SaleLogGrid.Rows[row_index].Cells[(int)SaleRecord.SaleColumnType.PAID].Value;
            salelist.SaleRecords[selected_sale_index].Paid = Convert.ToBoolean(paid);
            if (salelist.SaleRecords[selected_sale_index].Paid == true) { salelist.SaleRecords[selected_sale_index].paidConfirmedDate = DateTime.Now; }
            //object emailsent = SaleLogGrid.Rows[selected_sale_index].Cells[(int)SaleColumnType.SENTEMAIL].Value;
            //salelist.SaleRecords[selected_sale_index].SentEmail = Convert.ToBoolean(emailsent);
        }
        private void SaveCustomerList()
        {
            customerlist.save();
            //save_as the edited info note, when sorted in grid, the index will mess up
            //for (int last_sale_index = 0; last_sale_index < customerlist.count; last_sale_index++)
            //{
            //    customerlist[last_sale_index].name = customergrid.rows[last_sale_index].
            //}
        }

        private void SaveSaleSummary()
        {
            soldproductlist.save();
        }

        private void SaveTransactions()
        {
            transactionlist.save();
        }
        #endregion

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {

            switch (MessageBox.Show("Do you want to save the changes?",
                                        "Before closing...",
                                        MessageBoxButtons.YesNoCancel,
                                        MessageBoxIcon.Question))
            {
                case DialogResult.Yes:
                    // "Yes" save_as
                    //in case there is research result left in the box, refill all grids before saving
                    //fillgrids();
                    refillgrids();
                    SaveBearings();
                    SaveSaleLog();
                    SaveCustomerList();
                    buyinlist.save();
                    SaveSaleSummary();
                    SaveTransactions();
                    MessageBox.Show("All data have been saved");
                    break;

                case DialogResult.No:
                    // "No" don't save_as
                    break;

                case DialogResult.Cancel:
                    // "Cancel" closing form
                    e.Cancel = true;
                    break;
            }
        }

        private void toolStripButtonOpen_Click(object sender, EventArgs e)
        {
            openFileDialog1.Filter = "xml files (*.xml)|*.xml";
            openFileDialog1.RestoreDirectory = true;
            openFileDialog1.FileName = "";

            openFileDialog1.ShowDialog();
        }

        private void OrderOK_Click(object sender, EventArgs e)
        {
            //when the ok button on the order form is clicked
            
            //clear the search box to make sure all the list are in the right order and complete
            SearchTextBox.Text = "";
            ProductList OrderedBearings = new ProductList();
            for (int i = 0; i < productlist.Count; i++)
            {
                if (productlist[i].Order > 0)
                {
                    //create a temp b so that the quantity can be changed without affecting the qty of the productlist
                    Product tempb = new Product();
                    tempb.copy(productlist[i]);
                    tempb.quantity = tempb.Order;
                    OrderedBearings.add(tempb);                    
                }
            }
            /*
            for (int i = 0; i < ProductCatalogGrid.Rows.Count; i++)
            {
                //Grab the order amount in the cell
                object order_amount = ProductCatalogGrid.Rows[i].Cells[(int)GridColumnType.ORDER].Value;
                if (order_amount != null && Convert.ToInt32(order_amount) != 0)
                {
                    int idx =Convert.ToInt32(ProductCatalogGrid.Rows[i].Cells[(int)GridColumnType.INDEX].Value);
                    int ordered_quantity = Convert.ToInt32(order_amount);
                    //total_ordered_quantity += ordered_quantity;

                    //add this bearing to the ordered bearing list, and change the quantity to the ordered quantity
                    Bearing b = productlist.Bearings[idx];
                    //copy all the properties of the bearing except quantity, which should be the oredered amount
                    //can't directly equate the bearing from productlist and ordered_beairng because they have different index
                    Bearing ordered_bearing = new Bearing();
                    ordered_bearing.copy(b);
                    ordered_bearing.quantity = ordered_quantity;
                    //Bearing ordered_bearing = new Bearing(b.Inner, b.Outer, b.Thickness, b.Seal, b.Flanged, b.Brand, ordered_quantity, b.prime_cost, b.Price, b.comment);
                    //ordered_bearing.Code = b.Code;
                    OrderedBearings.add(ordered_bearing);
                }
            }    
             */
            //SaleEditForm SaleForm = new SaleEditForm(OrderedBearings,customerlist);
            //SaleForm.Show();
            //SaleForm.FormClosed += new FormClosedEventHandler(SaleEditForm_FormClosed);
            SaleEditForm_v2 SaleForm_v2 = new SaleEditForm_v2(OrderedBearings, customerlist);
            SaleForm_v2.Show();
            SaleForm_v2.FormClosed += new FormClosedEventHandler(SaleEditForm_v2_FormClosed);
        }

        private void AddToBuyinOk_Click(object sender, EventArgs e)
        {
            //clear the search box to make sure all the list are in the right order and complete
            SearchTextBox.Text = null;

            ProductList OrderedBearings = new ProductList();
            for (int i = 0; i < productlist.Count; i++)
            {
                if (productlist[i].Order > 0)
                {
                    //create a temp b so that the quantity can be changed without affecting the qty of the productlist
                    Product tempb = new Product();
                    tempb.copy(productlist[i]);
                    tempb.quantity = tempb.Order;
                    OrderedBearings.add(tempb);
                }
            }

        }

        private void SaleEditForm_v2_FormClosed(object sender, FormClosedEventArgs e)
        {
            //when a order is confirmed from the order form, and now comes back to the mainform
            SaleEditForm_v2 saleform_v2 = (SaleEditForm_v2)sender;
            if (saleform_v2.OKpressed)
            {

                //Process Customer List
                if (saleform_v2.knowncustomer)
                {
                    int ci = saleform_v2.customer_index;
                    customerlist[ci].Frequency++;
                    //make sure the row index is same as the customer list index, if the row is not resorted
                    //if the row is resorted, it should search for the name /or ID from the row, which is not implemented here yet.
                    /*
                    if (CustomerGrid.Rows[ci].Cells[(int)CustomerColumnType.NAME].Value == customerlist[ci].Name)
                    {
                        //update the customer frequency
                        fill_a_customer_to_row_i(customerlist[ci], ci);
                    }
                     * */
                }
                else
                {
                    //if go in here, don't use saleform_v2.customer_index, it's not updated yet
                    //add a new row in customer data grid    
                    //CustomerGrid.Rows.Add();
                    //customerlist.add(saleform_v2.customer);
                    //assign the index of the last customer to be the position it is in the list
                    //customerlist[customerlist.Count - 1].Index = customerlist.Count - 1;
                    //display it on the grid
                    //fill_a_customer_to_row_i(customerlist[customerlist.Count - 1], customerlist.Count - 1);                    
                }            
                //update the customer grid
                customerlist.fill_grid(CustomerGrid);
                //for (int i = 0; i < customerlist.Count; i++)
                //{
                //    fill_a_customer_to_row_i(customerlist[i], i); 
                //}
                //Process Sale List
                salelist.add(saleform_v2.sale);
                //assign the index of the last sale to be the position it is in the list
                int last_sale_index = salelist.Count - 1;
                salelist[last_sale_index].Index = last_sale_index;                
                //add a new row in sale log data grid
                //or just update the entire sale grid     
                salelist.fill_grid(SaleLogGrid, customerlist);
                //for (int i = 0; i < salelist.Count; i++)
                //{
                //    fill_a_sale_to_row_i(salelist[i], i);
                //}                  
                //SaleLogGrid.Rows.Add();
                //fill_a_sale_to_row_i(saleform_v2.sale, last_sale_index);
                //productlist.update_total_bearing_quantity();

                //the initial ordered quantity and unit price may be different after returning from SaleEditForm_v2
                ProductList ordered_list = saleform_v2.ordered_bearings;
                productlist.subtract_qty(ordered_list);
                
                //update the product catalog grid
                for (int i = 0; i < productlist.Count; i++)
                {
                    if (productlist[i].Order > 0)
                    {
                        productlist[i].Order = 0;
                    }
                    //update the product grid
                    productlist[i].fill_to_row_i(ProductCatalogGrid, i);
                    //fill_a_product_to_row_i(productlist[i], i);
                    //update the quantity column
                    //ProductCatalogGrid.Rows[i].Cells[(int)GridColumnType.QUANTITY].Value = productlist[i].quantity.ToString("000");
                    //clear the order cell
                    //ProductCatalogGrid.Rows[i].Cells[(int)GridColumnType.ORDER].Value = null;
                }
                /*
                for (int i = 0; i < ordered_list.Count; i++)
                {
                    int idx = ordered_list[i].MasterListIndex; //the bearing index relates to productlist (the main list)
                    int ordered_quantity = ordered_list[i].quantity;
                    //Subtract the bearings from bearing stock
                    productlist[idx].quantity -= ordered_quantity;
                    //update the remaining quantity
                    BearingCatalogGrid.Rows[idx].Cells[(int)GridColumnType.QUANTITY].Value = productlist.Bearings[idx].quantity.ToString("000");
                    //clear the order cell
                    BearingCatalogGrid.Rows[idx].Cells[(int)GridColumnType.ORDER].Value = null;
                }
                 * */
                productlist.update_total_bearing_quantity();

                //update the sale summary, includes this new sale
                soldproductlist.up_to_date_summary(productlist, salelist);
                ShowSaleSummary();

                //log the new sale as unpaidindex to transactions
                transactionlist.UnpaidIndex.Add(last_sale_index);

                
            }
        }
        private void toolStripButtonSave_Click(object sender, EventArgs e)
        {
            //SaveBearings();
            //save everything, just like when PMS is close 
            refillgrids();
            SaveBearings();
            SaveSaleLog();
            SaveCustomerList();
            buyinlist.save();
            SaveSaleSummary();
            SaveTransactions();
            MessageBox.Show("All data have been saved");
        }

        private void toolStripButtonAdd_Click(object sender, EventArgs e)
        {
            ProductEditForm AddForm = new ProductEditForm();
            AddForm.Show();
            AddForm.FormClosed += new FormClosedEventHandler(BearingEditForm_FormClosed);
        }

        private void BearingEditForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            ProductEditForm addform = (ProductEditForm)sender;
            if (addform.newproduct != null)
            {
                if (addform.EditMode == false) //that means its in add mode
                {                   
                    productlist.add(addform.newproduct);
                    int i = productlist.Count-1;
                    productlist[i].MasterListIndex = i;
                    ProductCatalogGrid.Rows.Add();
                    productlist[i].fill_to_row_i(ProductCatalogGrid, i);
                    //fill_a_product_to_row_i(productlist[i], i);
                }
                else //modify the edited bearing in the productlist
                {
                    int i = addform.newproduct.Index;
                    int row_index = addform.selected_bearing_row_index;
                    productlist[i] = addform.newproduct; //overrides the old bearing in list
                    addform.newproduct.fill_to_row_i(ProductCatalogGrid, row_index);// refresh the data grid
                    //fill_a_product_to_row_i(addform.newproduct, row_index);// refresh the data grid
                }
                productlist.update_total_bearing_quantity();
            }
        }

        private void TestStripButton_Click(object sender, EventArgs e)
        {            
            //productlist.update_table_from_txt_file();
            //productlist.update_cluster_product_index();
            //productlist.save_ClusterTable();
            //productlist.update_product_quantity();
            //productlist.subtract_qty(0, 2);
            //ClusterTableList ctl = new ClusterTableList();
            //ctl.update_tables_from_txt_file(productlist);
            //ctl.save_as("cluster_tables.xml");

            //DateTime d = new DateTime();
            //d = DateTime.Today;
            //d = DateTime.Now;            
            //OutputMsg1.Text = "year " + d.Year;
            //OutputMsg1.AppendText("\n month is" + d.Month);
            //OutputMsg1.AppendText("\n date is " + d.Day);
            //OutputMsg1.AppendText("\n time is " + d.Hour + d.Minute + d.Second.ToString("00"));
        }

        private void DeleteButtonBearingGrid_Click(object sender, EventArgs e)
        {
            //MessageBox.Show(BearingCatalogGrid.CurrentRow.Index.ToString());
            int si = ProductCatalogGrid.CurrentRow.Index; //the index of the selected bearing
            productlist.remove(si);
            ProductCatalogGrid.Rows.RemoveAt(si);

            //update all the subsequent rows
            for (int i = si; i < productlist.Count; i++)
            {
                productlist[i].fill_to_row_i(ProductCatalogGrid, i);
                //fill_a_product_to_row_i(productlist[i], i);
                //BearingCatalogGrid.Rows[last_sale_index].Cells[(int)GridColumnType.INDEX].Value = productlist.Bearings[last_sale_index].Index.ToString();
            }

        }

        private void BearingCatalogGrid_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            int selected_row_index = e.RowIndex;
            if (selected_row_index >= 0)
            {
                //selected_row_index is not necessarily the bearing index, e.g. after the rows are resorted
                int selected_item_index = Convert.ToInt32(ProductCatalogGrid.Rows[selected_row_index].Cells[(int)pmsDataGridView.Product.GridColumnType.INDEX].Value);
                ProductEditForm AddForm = new ProductEditForm(productlist[selected_item_index],selected_row_index);
                AddForm.Show();
                AddForm.FormClosed += new FormClosedEventHandler(BearingEditForm_FormClosed);
            }
        }

        private void BearingCatalogGrid_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            int sri = e.RowIndex;
            int selected_col = e.ColumnIndex;
            //this getting the list index from the row index should be written as a function for all the list and grid
            int spi = Convert.ToInt32(ProductCatalogGrid.Rows[sri].Cells[(int)pmsDataGridView.Product.GridColumnType.INDEX].Value);            
            if (DebugModeOn)
            {
                OutputMsg1.Text = "Edited row" + sri + ", column" + selected_col;
            }
            switch (selected_col)
            {
                case ((int)pmsDataGridView.Product.GridColumnType.ORDER):
                    productlist[spi].update_order_from_grid(ProductCatalogGrid, sri);
                    //object order_amount = ProductCatalogGrid.Rows[sri].Cells[(int)pmsDataGridView.Product.GridColumnType.ORDER].Value;
                    //if (order_amount != null && Convert.ToInt32(order_amount) != 0)
                    //{
                    //    //change the order field of the selected product
                    //    productlist[spi].Order = Convert.ToInt32(order_amount);
                    //}
                    //else
                    //{
                    //    productlist[spi].Order = 0;
                    //}
                    break;
                case ((int)pmsDataGridView.Product.GridColumnType.COST): productlist[spi].prime_cost = Convert.ToDouble(ProductCatalogGrid.Rows[sri].Cells[selected_col].Value);
                    if (DebugModeOn) OutputMsg1.AppendText("\n Cost of bearinglist[" + sri + "] is changed to " + productlist[sri].prime_cost); break;
                case ((int)pmsDataGridView.Product.GridColumnType.INDEX): productlist[spi].Index = Convert.ToInt32(ProductCatalogGrid.Rows[sri].Cells[selected_col].Value);
                    if (DebugModeOn) OutputMsg1.AppendText("\n Index of bearinglist[" + sri + "] is changed to " + productlist[sri].Index); break;
                case ((int)pmsDataGridView.Product.GridColumnType.PRICE): productlist[spi].Price = Convert.ToDouble(ProductCatalogGrid.Rows[sri].Cells[selected_col].Value);
                    if (DebugModeOn) OutputMsg1.AppendText("\n Price of bearinglist[" + sri + "] is changed to " + productlist[sri].Price); break;
                case ((int)pmsDataGridView.Product.GridColumnType.QUANTITY): productlist[spi].quantity = Convert.ToInt32(ProductCatalogGrid.Rows[sri].Cells[selected_col].Value);
                    if (DebugModeOn) OutputMsg1.AppendText("\n Quantity of bearinglist[" + sri + "] is changed to " + productlist[sri].quantity); break;
                default: return;
            }
        }

        private void DebugModeToggleButton_Click(object sender, EventArgs e)
        {
            if (DebugModeOn == false)
            {
                DebugModeOn = true;
                OutputMsg1.Text = "Debug mode is ON";
            }
            else
            {
                DebugModeOn = false;
                OutputMsg1.Text = "Debug mode is OFF";
            }
        }

        private void BearingCatalogGrid_CellEnter(object sender, DataGridViewCellEventArgs e)
        {
            int sri = e.RowIndex; //selected row index, 
            StringBuilder sb = new StringBuilder();
            int pi = Convert.ToInt32(ProductCatalogGrid.Rows[sri].Cells[(int)pmsDataGridView.Product.GridColumnType.INDEX].Value);
            sb.Append(productlist[pi].name + "\t\t" + productlist[pi].quantity.ToString() + Environment.NewLine);
            if (productlist[pi].cluster == true)
            {
                ProductList subitems = productlist.get_subitems(productlist[pi], true);
                for (int i = 0; i < subitems.Count; i++)
                { 
                    sb.Append("\t" + subitems[i].name + "\t" + subitems[i].quantity.ToString() + Environment.NewLine);
                }
            }
            OutputMsg1.Text = "Total item quantity\n" + productlist.TotalNumberOfBearings.ToString() + "\n";
            OutputMsg2.Text = sb.ToString();
            OutputMsg3.Text = productlist[pi].name + Environment.NewLine + productlist.ToPackListText(productlist[pi]);
            OutputMsg4.Text = productlist[pi].name + "\nComment\n" + productlist[pi].comment + Environment.NewLine + productlist[pi].Desription + Environment.NewLine;
            
            if (DebugModeOn) OutputMsg1.AppendText("\nPart Number " + productlist[pi].ID + "\nSelected row and bearing index in array " + pi + 
                "\nIndex Property " + productlist[pi].Index);

            //if the order cell is highlighted, then highlights the coresponding row
            if (e.ColumnIndex == (int)pmsDataGridView.Product.GridColumnType.ORDER)
            {
                ProductCatalogGrid.Rows[sri].Selected = true;
                /*
                //highlight product name field
                ProductCatalogGrid.Rows[sri].Cells[(int)pmsDataGridView.Product.GridColumnType.BEARING].Selected = true;
                if (InitConfig.Business == InitConfig.BusinessType.BEARING)
                {
                    //highlight Code field
                    ProductCatalogGrid.Rows[sri].Cells[(int)pmsDataGridView.Product.GridColumnType.CODE].Selected = true;
                }                
                //highlight quantity field
                ProductCatalogGrid.Rows[sri].Cells[(int)pmsDataGridView.Product.GridColumnType.QUANTITY].Selected = true;
                //highlight price field
                ProductCatalogGrid.Rows[sri].Cells[(int)pmsDataGridView.Product.GridColumnType.PRICE].Selected = true;
                */
            }
        }

        private void SaleLogGrid_CellEnter(object sender, DataGridViewCellEventArgs e)
        {
            if (salerowdeletemode == true)
            {
                salerowdeletemode = false;
                return;
            }            
            int sri = e.RowIndex; //selected row index, the index of the selected row of the grid          
            StringBuilder sb = new StringBuilder();
            int si = Convert.ToInt32(SaleLogGrid.Rows[sri].Cells[(int)SaleRecord.SaleColumnType.INDEX].Value);
            DateTime initialized_date = new DateTime();
            ProductList bl = salelist[si].BearingOrder;
            sb.Append("Item\tQuantity\tEach\tSubtotal\n");
            //print out the purchased bearings
            for (int i = 0; i < bl.Count; i++)
            {
                double subtotal = bl[i].quantity * bl[i].Price;
                //sb.Append(bl[i].name + "\t " + bl[i].quantity + "\t" + bl[i].Price.ToString("$0.00") + "\t" + subtotal.ToString("$0.00") + "\n");
                //the above line is broken down into 2 lines, mainly to insert the model number for bearings if the field is not empty
                sb.Append(bl[i].name);
                if (bl[i].Code != "")
                {
                    sb.Append(" (" + bl[i].Code + ")");
                }
                sb.Append("\t " + bl[i].quantity + "\t" + bl[i].Price.ToString("$0.00") + "\t" + subtotal.ToString("$0.00") + "\n");
            }
            sb.Append("shipping\t\t\t" + salelist[si].ShippingPayable.ToString("$0.00") + "\n");
            if (salelist[si].Discount != 0)
            {
                double discount_amount = (salelist[si].Payable-salelist[si].ShippingPayable) * (1 - 1 / (1 - salelist[si].Discount * 0.01));//note, payable is already the discounted figure
                sb.Append("discount\t\t" + salelist[si].Discount + "%\t" + discount_amount.ToString("$0.00") + "\n"); 
            }
            sb.Append("\nTotal\t" + salelist[si].BearingOrder.TotalNumberOfBearings.ToString() + "\t\t" + salelist[si].Payable.ToString("$0.00"));
            OutputMsg2.Text = sb.ToString();

            //print out address in the OutputMsg2   
            int ci = salelist[si].CustomerIndex;
            string packedDate = (salelist[si].packedDate == initialized_date) ? "Unknown" : salelist[si].packedDate.ToLongDateString();
            string shippedDate = (salelist[si].shippedDate == initialized_date) ? "Unknown" : salelist[si].shippedDate.ToLongDateString();
            string paidDate = (salelist[si].paidConfirmedDate == initialized_date) ? "Unknown" : salelist[si].paidConfirmedDate.ToLongDateString();
            OutputMsg1.Text = "Delivery address:\n" + customerlist[ci].Name + "\n" + customerlist[ci].Address + "\n" + customerlist[ci].Country + "\n\n"
                + "Packed: " + packedDate + "\n" + "Shipped: " + shippedDate + "\n" + "Paid confirmed: " + paidDate + "\n";
            OutputMsg3.Text = "To pack list: \n" + productlist.ToPackListText(salelist[si].BearingOrder);
            OutputMsg4.Text = "Comments \n" + salelist[si].Comment;
            OutputMsg4.AppendText("\n" + "Sale source" + "\n" + salelist[si].Source.ToString());
            if (DebugModeOn)
            {
                string str3 = "Selected row " + si + '\n' + "index is " + salelist[si].Index 
                    + '\n' + "customer index is " + salelist[si].CustomerIndex;
                OutputMsg4.AppendText('\n' + str3);
            }      
      
            //add all the highlighted number on the payable column
            Int32 selectedCellCount = SaleLogGrid.GetCellCount(DataGridViewElementStates.Selected);            

            //if the payable column is selected
            if (e.ColumnIndex == (int)pmsDataGridView.SaleRecord.SaleColumnType.PAYABLE)
            {
                //reset the list
                HighlightedNumbers.Clear();
                if (selectedCellCount > 0)
                {
                    for (int i = 0; i < selectedCellCount; i++)
                    {
                        int selected_row_index = SaleLogGrid.SelectedCells[i].RowIndex;
                        HighlightedNumbers.Add(Convert.ToDouble(SaleLogGrid.Rows[selected_row_index].Cells[(int)SaleRecord.SaleColumnType.PAYABLE].Value));                        
                    }
                    OutputMsg4.AppendText("\n" + "Selected total: " + HighlightedNumbers.Sum().ToString("0.00"));
                }

                /*
                if (selectedCellCount == 1)
                {
                    //reset the list
                    HighlightedNumbers.Clear();
                }
                HighlightedNumbers.Add(Convert.ToDouble(SaleLogGrid.Rows[sri].Cells[(int)SaleRecord.SaleColumnType.PAYABLE].Value));
                OutputMsg4.AppendText("\n" + HighlightedNumbers.Sum().ToString("0.00"));
                 * */
            }
            /*
            if (selectedCellCount > 0)
            {
                
            }
             * */

        }

        private void CustomerGrid_CellEnter(object sender, DataGridViewCellEventArgs e)
        {
            int si = e.RowIndex; //the index of the selected customer
            Customer c = customerlist[si];
            OutputMsg1.Text = c.Name + '\n' + c.UserName + '\n' + c.Email;
            OutputMsg3.Text = c.Address + '\n' + c.Country;
            OutputMsg4.Text = "Comments \n" + c.Comment;
            if (DebugModeOn)
            {                  
                string str3 = "Selected row " + si + '\n' + "index is " + customerlist[si].Index
                    + '\n' + "# of Buys " + customerlist[si].Frequency;
                OutputMsg4.AppendText('\n' + str3);
            } 
        }

        private void TestButton2_Click(object sender, EventArgs e)
        {
            //SaleRecord sl = new SaleRecord(DateTime.Now,false,2.00,.50,50,productlist,"blabla@bla","no comment");
            //SaleLogGrid.Rows.Add();
            //salelist.add(sl);
            //fill_a_sale_to_row_i(sl, 0);

            //salelist.load();
            //DateTime d = salelist[0].Date;
            //OutputMsg1.Text = "date is " + d;
            for (int i = 0; i < salelist.Count; i++)
            {
                salelist[i].BearingOrder.update_total_bearing_quantity();
            }
        }

        private void saveToolStripButton_Click(object sender, EventArgs e)
        {
            SaveSaleLog();
            MessageBox.Show("Sales data have been saved");
        }

        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            SaveCustomerList();
            MessageBox.Show("Customers data have been saved");
        }

        private void DeleteButtonSaleGrid_Click(object sender, EventArgs e)
        {
            //MessageBox.Show(BearingCatalogGrid.CurrentRow.Index.ToString());
            int selected_row_index = SaleLogGrid.CurrentRow.Index;//the index of the selected sale
            int selected_sale_index = Convert.ToInt32(SaleLogGrid.Rows[selected_row_index].Cells[(int)SaleRecord.SaleColumnType.INDEX].Value);

            
            //next, add the ordered bearing quantity back to bearing list
            productlist.returnOrderedItems(salelist[selected_sale_index].BearingOrder);
            /*
            for (int i = 0; i < salelist[selected_row_index].BearingOrder.Count; i++)
            {
                productlist[salelist[selected_row_index].BearingOrder[i].MasterListIndex].quantity += salelist[selected_row_index].BearingOrder[i].quantity;                
            }
            //add the subitems of the clustered product back to the list
            ProductList subitems = productlist.ToPackList(salelist[selected_row_index].BearingOrder);
            for (int i = 0; i < subitems.Count; i++)
            {
                productlist[subitems[i].MasterListIndex].quantity += subitems[i].quantity;
            }
            */
            //update the product catalog grid
            for (int i = 0; i < productlist.Count; i++)
            {
                productlist[i].fill_to_row_i(ProductCatalogGrid, i);
                //fill_a_product_to_row_i(productlist[i],i);
            }
            //if the reps of the customer is 1, then delete the customer, if it's more than 1, then subtract 1 from the reps
            //UPDATE: Don't remove customer, as this can screw up the customer index in the salelist
            /*
            if (customerlist[salelist[selected_row_index].CustomerIndex].Frequency < 2)//equal to 0 or 1
            {
                customerlist.remove(salelist[selected_row_index].CustomerIndex);
                //assume customer grid was not resorted, i.e. row index = customer list index
                CustomerGrid.Rows.RemoveAt(salelist[selected_row_index].CustomerIndex);
                //update all subsequency rows in customer grid
                for (int i = salelist[selected_row_index].CustomerIndex; i < customerlist.Count; i++)
                {
                    fill_a_customer_to_row_i(customerlist[i], i);
                }
            }
            else //reps is more than 2, so just simply subtract 1
            {
                customerlist[salelist[selected_row_index].CustomerIndex].Frequency--;
                //update the customer grid 
                fill_a_customer_to_row_i(customerlist[salelist[selected_row_index].CustomerIndex], salelist[selected_row_index].CustomerIndex);
            }
             * */
            customerlist[salelist[selected_sale_index].CustomerIndex].Frequency--;
            //update the customer grid 
            customerlist[salelist[selected_sale_index].CustomerIndex].fill_to_row_i(CustomerGrid, salelist[selected_sale_index].CustomerIndex);
            //fill_a_customer_to_row_i(customerlist[salelist[selected_sale_index].CustomerIndex], salelist[selected_sale_index].CustomerIndex);
            salelist.remove(selected_sale_index);
            salerowdeletemode = true;
            SaleLogGrid.Rows.RemoveAt(selected_row_index);
            
            //update all the subsequent rows
            //but this doesn't work if the rows are not sorted in the sequency of the index column
            //for (int i = selected_row_index; i < salelist.Count; i++)
            //{
            //    //int sale_row_index = Convert.ToInt32(SaleLogGrid.Rows[i].Cells[(int)SaleColumnType.INDEX].Value);
            //    fill_a_sale_to_row_i(salelist[i], i);                
            //}

            //refresh, and display the whole salelist in the index order, even though it was reordered or filtered by search results
            salelist.fill_grid(SaleLogGrid, customerlist);
            //for (int i = 0; i < salelist.Count; i++)
            //{                
            //    fill_a_sale_to_row_i(salelist[i], i);
            //}

            //refresh the unpaid index list of the transactionlist 
            transactionlist.refresh_unpaid_index(salelist);
            //delete the unpaid index if there is one in the transactionlist
            //if the sale is not paid, and is then deleted, the unpaid index in the transactionlist is to be removed
            //for (int i = 0; i < transactionlist.UnpaidIndex.Count; i++)
            //{
            //    if (Convert.ToInt32(transactionlist.UnpaidIndex[i]) == selected_row_index)
            //    {
            //        transactionlist.UnpaidIndex.RemoveAt(i);
            //        break;
            //    }
            //}
        }
        
        private void DeleteCustomer_Click(object sender, EventArgs e)
        {
            //MessageBox.Show(BearingCatalogGrid.CurrentRow.Index.ToString());
            int sri = CustomerGrid.CurrentRow.Index;//the index of the selected row
            //get the customer index
            int ci = Convert.ToInt32(CustomerGrid.Rows[sri].Cells[(int) Customer.CustomerColumnType.INDEX].Value);            
            customerlist.remove(ci);
            CustomerGrid.Rows.RemoveAt(ci);            

            //update all the subsequent rows
            for (int i = ci; i < customerlist.Count; i++)
            {
                customerlist[i].fill_to_row_i(CustomerGrid, i);
                //fill_a_customer_to_row_i(customerlist[i], i);                
            }
            Update_customer_index();
        }
        private void Update_customer_index()
        {
            for (int i = 0; i < salelist.Count; i++)
            {
                int ci = salelist[i].CustomerIndex;
                //avoid going into the for loop if the sale has got the right customer index
                if (salelist[i].CustomerName != customerlist[ci].Name)
                {
                    //if the index is wrong, search for the right one from the customer'tr list
                    for (int j = 0; j < customerlist.Count; j++)
                    {
                        if (salelist[i].CustomerName == customerlist[j].Name)
                        {
                            salelist[i].CustomerIndex = j;
                            break;
                        }                        
                    }
                }                
            }
        }

        private void BearingCatalogRefresh_Click(object sender, EventArgs e)
        {            
            ReFreshProductList();
        }

        private void SaleSummaryRefresh_Click(object sender, EventArgs e)
        {
            //DateTime start = new DateTime(Convert.ToInt32(FromYearTB.Text), Convert.ToInt32(FromMonthTB.Text), Convert.ToInt32(FromDateTB.Text));
            //DateTime end = new DateTime(Convert.ToInt32(ToYearTB.Text), Convert.ToInt32(ToMonthTB.Text), Convert.ToInt32(ToDateTB.Text),23,59,59);//in the last hour of the day            
            //soldproductlist.set_dates(start,end);
            if (InitConfig.Business == InitConfig.BusinessType.BEARING)
            {
                //doesn't seem to have any problem, so leave it
            }
            else if (InitConfig.Business == InitConfig.BusinessType.ELECTRONICS)
            {
                DateTime start = new DateTime(2011, 5, 1);
                //DateTime end = new DateTime(2011, 5, 15);                
                soldproductlist.set_dates(start, DateTime.Today.AddDays(1));
            }
            soldproductlist.refresh_summary(productlist,salelist);            
            ShowSaleSummary();
            
        }
        public void ShowSaleSummary()
        {
            SaleSummaryGrid.Rows.Clear();
            for (int i = 0; i < soldproductlist.Count; i++)
            {
                SaleSummaryGrid.Rows.Add();
                fill_a_soldbearing_to_row_i(soldproductlist[i], i);
            }            
        }
        public void fill_a_soldbearing_to_row_i(SoldBearing b, int i)
        {
            SaleSummaryGrid.Rows[i].Cells[(int)SaleSummaryColumnType.ID].Value = b.ID;
            SaleSummaryGrid.Rows[i].Cells[(int)SaleSummaryColumnType.BEARING].Value = b.name;
            SaleSummaryGrid.Rows[i].Cells[(int)SaleSummaryColumnType.QUANTITY].Value = b.quantity;
            SaleSummaryGrid.Rows[i].Cells[(int)SaleSummaryColumnType.QTYPERMONTH].Value = b.QtyPerMonth;
            SaleSummaryGrid.Rows[i].Cells[(int)SaleSummaryColumnType.REVENUEPERMONTH].Value = b.RevenuePerMonth.ToString("0.00");
            SaleSummaryGrid.Rows[i].Cells[(int)SaleSummaryColumnType.REVENUEPERYEAR].Value = b.RevenuePerYear.ToString("0.00");
            SaleSummaryGrid.Rows[i].Cells[(int)SaleSummaryColumnType.FREQUENCY].Value = b.frequency;
            SaleSummaryGrid.Rows[i].Cells[(int)SaleSummaryColumnType.REVENUE].Value = b.TotalRevenue.ToString("0.00");
        }

        private void SaleSummaryGrid_CellEnter(object sender, DataGridViewCellEventArgs e)
        {
            OutputMsg1.Clear();         
                OutputMsg2.Text = "Total Bearing Sold " + soldproductlist.TotalBearingSold.ToString() + "\nTotal Revenue per Month " + soldproductlist.RevenuePerMonth.ToString("0.00")
                + "\nTotal Revenue per Year " + soldproductlist.RevenuePerYear.ToString("0.00") + "\nTotal Revenue " + soldproductlist.TotalRevenue.ToString("0.00")
                + "\nRevenue2 " + soldproductlist.Revenue2.ToString("0.00");
            OutputMsg3.Clear();
            OutputMsg4.Clear();
        }

        public void RefreshCustomerFrequency()
        {
            for (int i = 0; i < salelist.Count; i++)
            {
                for (int j = 0; j < customerlist.Count; j++)
                {
                    if (string.Compare(salelist[i].CustomerName, customerlist[j].Name, true) == 0)
                    {
                        customerlist[j].Frequency++;
                        break;
                    }
                }
            }
        }

        public void fill_a_transc_to_row_i(AccountRecord transc, int i)
        {
            TranscGrid.Rows[i].Cells[(int)TransactionColumnType.ID].Value = transc.ID;
            TranscGrid.Rows[i].Cells[(int)TransactionColumnType.DATE].Value = transc.Date;
            TranscGrid.Rows[i].Cells[(int)TransactionColumnType.CATEGORY].Value = transactionlist.Categorylist[transc.c_idx];
            TranscGrid.Rows[i].Cells[(int)TransactionColumnType.PAYEE].Value = transc.Payee;            
            if (transc.MoneyIn == true)
            {                
                TranscGrid.Rows[i].Cells[(int)TransactionColumnType.MONEYIN].Value = transc.Amount.ToString("0.00");
            }
            else //money out
            {
                TranscGrid.Rows[i].Cells[(int)TransactionColumnType.MONEYOUT].Value = transc.Amount.ToString("0.00");
            }
            TranscGrid.Rows[i].Cells[(int)TransactionColumnType.DESCRIPTION].Value = transc.Description;
            TranscGrid.Rows[i].Cells[(int)TransactionColumnType.BALANCE].Value = transc.Balance.ToString("0.00");
            TranscGrid.Rows[i].Cells[(int)TransactionColumnType.INDEX].Value = transc.Index;
        }

        private void TabtableSelecting(object sender, TabControlCancelEventArgs e)
        {
            //clear the search, otherwise it would crash when it tries to save the search results
            //SearchTextBox.Text = null; //just discovered this didn't help
            //could have used refillgrids() to update all the lists, but for efficency sake, just update 
            //the last selected list
            switch (TabIndexBeforeChanging)
            {
                case ((int)TabIndexType.PRODUCT):
                    productlist.fill_grid(ProductCatalogGrid);                                       
                    break;                
                case ((int)TabIndexType.SALELOG):
                    salelist.fill_grid(SaleLogGrid, customerlist);
                    break;
                    case ((int)TabIndexType.CUSTOMERS):
                    customerlist.fill_grid(CustomerGrid);
                    break;
            }
            //update the index
            TabIndexBeforeChanging = Tabtable1.TabIndex;

            switch (Tabtable1.SelectedIndex)
            {
                case ((int)TabIndexType.FINANCIALREPORT):
                    {// if the financial table is selected, then see if there are any new payment, if so, add it to the transaction list
                        //first, check the unpaid list
                        //also needs to check if the transactionlist is empty i.e. a brandnew database
                        if (transactionlist.UnpaidIndex.Count == 0 || transactionlist.Count == 0)
                        {
                            //no due payments
                            return;
                        }
                        else
                        {
                            for (int i = 0; i < transactionlist.UnpaidIndex.Count; i++)
                            {
                                int unpaid_sale_index = (int)transactionlist.UnpaidIndex[i];
                                if (salelist[unpaid_sale_index].Paid == true) //new payment is detected
                                {
                                    AccountRecord ar = new AccountRecord(salelist[unpaid_sale_index], customerlist[salelist[unpaid_sale_index].CustomerIndex].Name);
                                    transactionlist.add(ar);
                                    TranscGrid.Rows.Add();
                                    int last_transc_index = transactionlist.Count - 1;
                                    fill_a_transc_to_row_i(transactionlist[last_transc_index], last_transc_index);
                                    transactionlist.UnpaidIndex.RemoveAt(i);
                                    i--;
                                }
                            }
                        }
                        break;
                    }
                case ((int)TabIndexType.SALELOG):                    
                    {
                        ////auto scroll to the last sale
                        //if (salelist.Count > 10) //10 is an arbitary number here, to avoid error when the salelist is empty
                        //{
                        //    SaleLogGrid.FirstDisplayedScrollingRowIndex = salelist.Count - 1;
                        //}
                        //break;
                        //auto scroll to the last sale
                        if ( SaleLogGrid.Rows.Count > 10 ) //10 is an arbitary number here, to avoid error when the salelist is empty
                        {
                            SaleLogGrid.FirstDisplayedScrollingRowIndex = SaleLogGrid.Rows.Count - 1;
                        }
                        //update the print address flags
                        loadPrintAdressFlags();
                        break;
                    }
            }
           
        }

        private void SaleLogGrid_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            //dynamically detect the tick boxes of paid and packed and update it to the sale list
            //checks it only when loading is completed, and if the indice of the row and the list are the same
            if (LoadingComplete == true && SaleRecord.Filling_a_sale_to_list == false)
            {
                if (e.ColumnIndex == (int)SaleRecord.SaleColumnType.PAID || e.ColumnIndex == (int)SaleRecord.SaleColumnType.PACKED)
                {
                    int sri = e.RowIndex; //selected row index, the index of the selected row of the grid                          
                    int si = Convert.ToInt32(SaleLogGrid.Rows[sri].Cells[(int)SaleRecord.SaleColumnType.INDEX].Value);                    
                    update_paid_and_packed(sri);
                }
            }
            
        }

        private void AddTranscButton_Click(object sender, EventArgs e)
        {
            AddTransactionForm AddForm = new AddTransactionForm(transactionlist);
            AddForm.Show();
            AddForm.FormClosed += new FormClosedEventHandler(AddTransactionForm_FormClosed);
        }

        public void AddTransactionForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            AddTransactionForm NewTranscForm = (AddTransactionForm)sender;
            if (NewTranscForm.OKpressed == true)
            {
                transactionlist = NewTranscForm.transactionlist;
                int i = transactionlist.Count - 1;
                TranscGrid.Rows.Add();
                fill_a_transc_to_row_i(transactionlist[i], i);
            }
            else //at least save the catalog list
            {
                transactionlist.Categorylist = NewTranscForm.transactionlist.Categorylist;
            }
        }

        private void TranscRefreshButton_Click(object sender, EventArgs e)
        {
            if (transactionlist.Count > 0)
            {
                transactionlist.refresh_balance();
            }
            for (int i = 0; i < transactionlist.Count; i++)
            {
                transactionlist[i].Index = i;
                fill_a_transc_to_row_i(transactionlist[i], i);               
            }
        }

        private void EmailButton_Click(object sender, EventArgs e)
        {//determine the row index of the selected cells    
            ArrayList selected_sale_indices = new ArrayList();
            ArrayList selected_salegrid_row_indices = new ArrayList();
            Int32 selectedCellCount = SaleLogGrid.GetCellCount(DataGridViewElementStates.Selected);
            EmailType emailtype = EmailType.UNSIGNED;
            if (selectedCellCount > 0)
            {
                System.Text.StringBuilder sb = new System.Text.StringBuilder();                
                for (int i = 0; i < selectedCellCount; i++)
                {
                    //the following two if conditions, don't want it to go into both, how to implement that?
                    if (SaleLogGrid.SelectedCells[i].ColumnIndex == (int)SaleRecord.SaleColumnType.PURCHASEEMAIL && emailtype != EmailType.SENT)
                    {
                        emailtype = EmailType.PURCHASE;
                        int selected_row_index = SaleLogGrid.SelectedCells[i].RowIndex;
                        int selected_sale_index = Convert.ToInt32(SaleLogGrid.Rows[selected_row_index].Cells[(int)SaleRecord.SaleColumnType.INDEX].Value);
                        selected_sale_indices.Add(selected_sale_index);
                        selected_salegrid_row_indices.Add(selected_row_index);
                        sb.Append("Selected Purchase Email column, Row: ");
                        sb.Append(selected_sale_index);
                        sb.Append(Environment.NewLine);
                    }

                    else if (SaleLogGrid.SelectedCells[i].ColumnIndex == (int)SaleRecord.SaleColumnType.SENTEMAIL && emailtype != EmailType.PURCHASE)
                    {
                        emailtype = EmailType.SENT;
                        int selected_row_index = SaleLogGrid.SelectedCells[i].RowIndex;
                        int selected_sale_index = Convert.ToInt32(SaleLogGrid.Rows[selected_row_index].Cells[(int)SaleRecord.SaleColumnType.INDEX].Value);
                        selected_sale_indices.Add(selected_sale_index);
                        selected_salegrid_row_indices.Add(selected_row_index);
                        sb.Append("Selected Sent Email column, Row: ");
                        sb.Append(selected_sale_index);
                        sb.Append(Environment.NewLine);
                    }

                }
                sb.Append("Total: " + selectedCellCount.ToString());
                OutputMsg4.Text=(sb.ToString()+ "Selected Rows");                
            }
            for (int i=0;i<selected_sale_indices.Count;i++)
            {
                int selected_sale_index = (int) selected_sale_indices[i]; 
                
                //send emails to the selected sale customers
                if ((salelist[selected_sale_index].PurchaseEmail == false && emailtype == EmailType.PURCHASE)||
                    (salelist[selected_sale_index].SentEmail == false && emailtype == EmailType.SENT))
                {
                    //send_shipped_email(selected_sale_index, emailtype);
                    AutoEmail automail =  new AutoEmail(salelist[selected_sale_index],customerlist[salelist[selected_sale_index].CustomerIndex]);
                    if (automail.send(emailtype) == 0)
                    {
                        //tick the box   
                        //!! assuming selected_sale_index is also the sale grid index here, can potentially casue a bug    
                        if (emailtype == EmailType.PURCHASE)
                        {
                            salelist[selected_sale_index].PurchaseEmail = true;
                            SaleLogGrid.Rows[(int)selected_salegrid_row_indices[i]].Cells[(int)SaleRecord.SaleColumnType.PURCHASEEMAIL].Value = true;                            
                        }
                        else if (emailtype == EmailType.SENT)
                        {
                            salelist[selected_sale_index].SentEmail = true;
                            SaleLogGrid.Rows[(int)selected_salegrid_row_indices[i]].Cells[(int)SaleRecord.SaleColumnType.SENTEMAIL].Value = true;
                            salelist[selected_sale_index].shippedDate = DateTime.Now;                            
                        }
                        OutputMsg4.AppendText("\nEmail sent successfully");
                    }
                    else if (automail.send(emailtype) == 2)
                    {
                        OutputMsg4.AppendText("\nfailed to send email, Configurations/email.txt missing");
                    }
                    else if (automail.send(emailtype) == 3)
                    {
                        OutputMsg4.AppendText("\nfailed to read some parameters from Configurations/email.txt");
                    }
                    else
                    {
                        OutputMsg4.AppendText("\nfailed to send email");
                    }
                }
            }
            

        }

        private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
        {

        }

        private void PrintAddress_Click(object sender, EventArgs e)
        {

            //int row_index = SaleLogGrid.SelectedCells[0].RowIndex; //note if more than 1 row is highlighted, only the first row is considered.
            //int selected_sale_index = Convert.ToInt32(SaleLogGrid.Rows[row_index].Cells[(int)SaleColumnType.INDEX].Value);
            //SaleRecord sale = salelist[selected_sale_index];
            //Customer customer = customerlist[sale.CustomerIndex];

            //PrintEngine printer = new PrintEngine(sale, customer, PrintEngine.PrintCommandType.TOANDFROM);
            //printer.Print();
            //determine the row index of the selected cells    
            ArrayList selected_sale_indices = new ArrayList();
            Int32 selectedCellCount = SaleLogGrid.GetCellCount(DataGridViewElementStates.Selected);
            if (selectedCellCount > 0)
            {
                SaleLogList selected_salelist = new SaleLogList();
                CustomerList selected_customerlist = new CustomerList();
                System.Text.StringBuilder sb = new System.Text.StringBuilder();
                for (int i = 0; i < selectedCellCount; i++)
                {
                    int row_index = SaleLogGrid.SelectedCells[i].RowIndex; //note if more than 1 row is highlighted, only the first row is considered.
                    bool same_row_index = false;
                    //assuming row index does not equal to the index of the sale
                    int selected_sale_index = Convert.ToInt32(SaleLogGrid.Rows[row_index].Cells[(int)SaleRecord.SaleColumnType.INDEX].Value);
                    //check if the row index has included or not, cos more than 1 cell can be selected in the same row
                    for (int j = 0; j < selected_sale_indices.Count; j++)
                    {
                        if ((int)selected_sale_indices[j] == selected_sale_index)
                        {
                            same_row_index = true;
                            break;
                        }
                    }
                    if (same_row_index == false)
                    {                        
                        selected_sale_indices.Add(selected_sale_index);
                        selected_salelist.add(salelist[selected_sale_index]);
                        selected_customerlist.add(customerlist[salelist[selected_sale_index].CustomerIndex]);
                        sb.Append("Selected sale Row: ");
                        sb.Append(selected_sale_index);
                        sb.Append(Environment.NewLine);
                    }
                }
                sb.Append("Total: " + selectedCellCount.ToString());
                OutputMsg4.Text = (sb.ToString() + "Selected Rows");

                PrintEngine printer = new PrintEngine(selected_salelist, selected_customerlist, PrintEngine.PrintCommandType.TOANDFROM);
                //update the firstpageflag
                writePrintAdressFlags(printer);
                //start printing
                do
                {
                    printer.Print();
                }
                while (printer.HasMorePages == true);
            }
            loadPrintAdressFlags();
             
        }

        private void PrintLabels_Click(object sender, EventArgs e)
        {
            //determine the row index of the selected cells    
            ArrayList selected_sale_indices = new ArrayList();    
            Int32 selectedCellCount = SaleLogGrid.GetCellCount(DataGridViewElementStates.Selected);
            if (selectedCellCount > 0)
            {
                SaleLogList selected_salelist = new SaleLogList();
                CustomerList selected_customerlist = new CustomerList();
                System.Text.StringBuilder sb = new System.Text.StringBuilder();
                for (int i = 0; i < selectedCellCount; i++)
                {
                    int row_index = SaleLogGrid.SelectedCells[i].RowIndex; //note if more than 1 row is highlighted, only the first row is considered.
                    bool same_row_index = false;
                    //assuming row index does not equal to the index of the sale
                    int selected_sale_index = Convert.ToInt32(SaleLogGrid.Rows[row_index].Cells[(int)SaleRecord.SaleColumnType.INDEX].Value);
                    //check if the row index has included or not, cos more than 1 cell can be selected in the same row
                    for (int j = 0; j < selected_sale_indices.Count; j++)
                    {
                        if ((int)selected_sale_indices[j] == selected_sale_index)
                        {
                            same_row_index = true;
                            break;
                        }
                    }
                    if (same_row_index == false)
                    {
                        selected_sale_indices.Add(selected_sale_index);
                        selected_salelist.add(salelist[selected_sale_index]);
                        selected_customerlist.add(customerlist[salelist[selected_sale_index].CustomerIndex]);
                        sb.Append("Selected sale Row: ");
                        sb.Append(selected_sale_index);
                        sb.Append(Environment.NewLine);
                    }
                }
                sb.Append("Total: " + selectedCellCount.ToString());
                OutputMsg4.Text = (sb.ToString() + "Selected Rows");

                PrintEngine printer = new PrintEngine(selected_salelist, selected_customerlist, PrintEngine.PrintCommandType.BEARINGLABEL);
                do
                {
                    printer.Print();
                }
                while (printer.HasMorePages == true);
            }

        }

        private void PrintPanel_Click(object sender, EventArgs e)
        {
            int qty = 24;
            PrintEngine printer = new PrintEngine("FRAGILE", qty, PrintEngine.PrintCommandType.LABEL);
            do
            {
                printer.Print();
            }
            while (printer.HasMorePages == true);
        }

        private void SearchTextBox_TextChanged(object sender, EventArgs e)
        {
            string SearchKeyWord = SearchTextBox.Text;
            switch (Tabtable1.SelectedIndex)
            {
                case ((int)TabIndexType.PRODUCT):
                    {
                        productlist.ShowSearchResults(ProductCatalogGrid, SearchKeyWord);
                        break;
                    }
                case ((int)TabIndexType.SALELOG):
                    {
                        //it can cause other issues if the sale grid only shows search results
                        //deselect all the rows
                        //SaleLogGrid.ClearSelection();
                        //not even select the first row (which it is by default
                        //SaleLogGrid.CurrentCell = null;

                        //clear all the sale list
                        SaleLogGrid.Rows.Clear();
                        int j = 0;
                        for (int i = 0; i < salelist.Count; i++)
                        {
                            Customer c = customerlist[salelist[i].CustomerIndex];
                            string content;
                            //check if string in each field contains substring
                            //if substring str2 cannot be found, str1.IndexOf(str2) returns -1
                            //add content to be search
                            content = c.Name + c.UserName + c.Email;
                            if (KeyWordsFound(SearchKeyWord, content))                
                            {//the key word is found, highlight it and terminate the forloop
                                //SaleLogGrid.FirstDisplayedScrollingRowIndex = i;
                                //SaleLogGrid.Rows[i].Selected = true;
                                //break;
                                //SaleLogGrid.Rows.Add(); //shoud be taken care off by the fill_to_row_i function
                                salelist[i].fill_to_row_i(SaleLogGrid, customerlist, j);
                                //fill_a_sale_to_row_i(salelist[i], j);
                                j++;
                            }
                        }
                        break;
                    }
                case ((int)TabIndexType.CUSTOMERS):
                    {
                        //clear all the customer list 
                        CustomerGrid.Rows.Clear();
                        int j = 0;
                        for (int i = 0; i < customerlist.Count; i++)
                        {
                            Customer c = customerlist[i];
                            string content;
                            //check if string in each field contains substring
                            //if substring str2 cannot be found, str1.IndexOf(str2) returns -1
                            //add content to be search
                            content = c.Name + c.UserName + c.Email;
                            if (KeyWordsFound(SearchKeyWord, content))
                            {//the key word is found, add it to the grid
                                //CustomerGrid.Rows.Add();//shoud be taken care off by the fill_to_row_i function
                                c.fill_to_row_i(CustomerGrid, j);
                                //fill_a_customer_to_row_i(c, j);
                                j++;                                
                            }
                        }
                        break;
                    }
                case ((int)TabIndexType.SALESUMMARY):
                    {
                        break;
                    }
                case ((int)TabIndexType.FINANCIALREPORT):
                    {
                        break;
                    }
                default:
                    break;                    
            }

            //if (Tabtable1.SelectedIndex == (int)TabIndexType.SALELOG)
            //{
            //    SaleLogGrid.Rows[2].Selected = true;
            //    OutputMsg3.AppendText("\nsale tab selected");

            //}
        }

        private void loadPrintAdressFlags()
        {
            PrintEngine printer = new PrintEngine();
            //in the print engine, this row is called column, a bit confusing i know.
            int Nrows = 3;
            bool[] firstpageflags = new bool[Nrows];
            firstpageflags = printer.get_firstpageflags();
            //reset all check boxes
            checkBoxAdd1.Checked = false;
            checkBoxAdd2.Checked = false;
            checkBoxAdd3.Checked = false;

            if (firstpageflags[0] == true)
            {
                checkBoxAdd1.Checked = true;
            }            
            if (firstpageflags[1] == true)
            {
                checkBoxAdd2.Checked = true;
            }            
            if (firstpageflags[2] == true)
            {
                checkBoxAdd3.Checked = true;
            }            
        }

        private void writePrintAdressFlags(PrintEngine pe)
        {
            //in the print engine, this row is called column, a bit confusing i know.
            int Nrows = 3;
            bool[] firstpageflags = new bool[Nrows];
            firstpageflags[0] = checkBoxAdd1.Checked;
            firstpageflags[1] = checkBoxAdd2.Checked;
            firstpageflags[2] = checkBoxAdd3.Checked;
            //if all false, set it to all true cos it means a new page anyway
            if (!firstpageflags[0] && !firstpageflags[1] && !firstpageflags[2])
            {
                firstpageflags[0] = true;
                firstpageflags[1] = true;
                firstpageflags[2] = true;
            }
            pe.FirstPageFlags = firstpageflags;
        }
        private bool KeyWordsFound(string keywords, string content)
        {
            return (content.IndexOf(keywords, StringComparison.OrdinalIgnoreCase) != -1);
        }
        private void AddCustomer_Click(object sender, EventArgs e)
        {
            CustomerEditForm AddCustomer = new CustomerEditForm();
            AddCustomer.Show();
            AddCustomer.FormClosed += new FormClosedEventHandler(AddCustomerForm_FormClosed);
        }
        private void AddCustomerForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            //come back to the mainform after entering a customer detail
            CustomerEditForm addcustomerform = (CustomerEditForm)sender;
            if (addcustomerform.OKpressed)
            {

                //add the new customer to the customer list
                customerlist.add(addcustomerform.customer);
                //when add an customer, it's index is the last one in the list, instead of -1
                customerlist[customerlist.Count - 1].Index = customerlist.Count - 1;

                //display it on the customer grid
                CustomerGrid.Rows.Add();
                customerlist[customerlist.Count - 1].fill_to_row_i(CustomerGrid, customerlist.Count - 1);
                //fill_a_customer_to_row_i(customerlist[customerlist.Count - 1], customerlist.Count - 1);
            }

        }

        private void CustomerGrid_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {           
            int selected_row_index = e.RowIndex;            
            if (selected_row_index >= 0)
            {
                //not necessarily equal to the row index, e.g. after the row are resorted
                int selected_customer_index = Convert.ToInt32(CustomerGrid.Rows[selected_row_index].Cells[(int) Customer.CustomerColumnType.INDEX].Value);
                CustomerEditForm cEditForm = new CustomerEditForm(customerlist[selected_customer_index],selected_row_index);
                cEditForm.Show();
                cEditForm.FormClosed += new FormClosedEventHandler(cEditForm_FormClosed);
            }
        }
        private void cEditForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            
            CustomerEditForm cEditForm = (CustomerEditForm)sender;

            //update the customer in the list
            customerlist[cEditForm.customer.Index] = cEditForm.customer;

            //update the customers grid
            cEditForm.customer.fill_to_row_i(CustomerGrid, cEditForm.selected_row_index);
            //fill_a_customer_to_row_i(cEditForm.customer,cEditForm.selected_row_index);
        }

        private void SaleLogGrid_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            int selected_row_index = e.RowIndex;
            if (selected_row_index >= 0)
            {
                //not necessarily equal to the row index, e.g. after the row are resorted
                int selected_sale_index = Convert.ToInt32(SaleLogGrid.Rows[selected_row_index].Cells[(int)SaleRecord.SaleColumnType.INDEX].Value);
                SaleEditForm_v2 sEditForm = new SaleEditForm_v2(salelist[selected_sale_index], selected_row_index,customerlist);
                sEditForm.Show();
                sEditForm.FormClosed += new FormClosedEventHandler(cEditForm_v2_FormClosed);
            }

        }

        private void cEditForm_v2_FormClosed(object sender, FormClosedEventArgs e)
        {

            SaleEditForm_v2 sEditForm = (SaleEditForm_v2)sender;

            //update the sale in the list
            salelist[sEditForm.sale.Index] = sEditForm.sale;

            //update the sale grid
            sEditForm.sale.fill_to_row_i(SaleLogGrid, customerlist, sEditForm.selected_row_index);
            //fill_a_sale_to_row_i(sEditForm.sale, sEditForm.selected_row_index);            
        }     

        private void SaleLogGrid_KeyPress(object sender, KeyPressEventArgs e)
        {            
            this.KeyPreview = false;
            char c = e.KeyChar;            
            if (SaleLogGrid.SelectedCells.Count>0)
            {
                if (SaleLogGrid.SelectedCells[0].ColumnIndex == (int)SaleRecord.SaleColumnType.PACKED)
                {                    
                    if (c != Convert.ToChar(Keys.Enter))
                    {
                        barcode_input += c;
                    }
                    else
                    {
                    }
                }
            }
        }

        private void SaleLogGrid_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter && barcode_input != null)
            {
                int selected_row_index = SaleLogGrid.SelectedCells[0].RowIndex;
                int sale_index = Convert.ToInt32(SaleLogGrid.Rows[selected_row_index].Cells[(int)SaleRecord.SaleColumnType.INDEX].Value);
                salelist[sale_index].trackingNumber = barcode_input;
                SaleLogGrid.Rows[selected_row_index].Cells[(int)SaleRecord.SaleColumnType.PACKED].Value = true;
                update_paid_and_packed(selected_row_index);
                OutputMsg4.AppendText("\n" + barcode_input);
                barcode_input = null;
                if (DebugModeOn)
                {
                    OutputMsg4.AppendText("\nSelected row ind: " + selected_row_index.ToString());
                    OutputMsg4.AppendText("\nSelected sale ind: " + sale_index.ToString());
                    OutputMsg4.AppendText("\nSale Tracking number: " + salelist[sale_index].trackingNumber);
                }
                // supress the enter key and call a button's click event
                //e.SuppressKeyPress = true;
            }
        }

        private void AddBuyin_Click(object sender, EventArgs e)
        {
            BuyinRecord newbuyin = new BuyinRecord();
            buyinlist.add(newbuyin);
            //assign the buyin record's index to the last index of the list
            int last_index = buyinlist.Count - 1;
            buyinlist[last_index].Index = last_index;
            BuyinGrid.Rows.Add();
            buyinlist[last_index].fill_to_last_row(BuyinGrid);
            //fill_a_buyin_to_row_i(buyinlist[last_index],last_index);
            //ProductCatalogGrid.Rows.Add();
            //fill_a_product_to_row_i(productlist[i], i);
            //BuyinForm AddForm = new BuyinForm(this);
            //AddForm.Show();
            //AddForm.FormClosed += new FormClosedEventHandler(BuyinForm_FormClosed);
        }
        private void BuyinForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            BuyinForm buyinform = (BuyinForm)sender;
            if (buyinform.OkPressed == true)
            {
                buyinlist[buyinform.selected_buyin_index] = buyinform.buyinrecord;
            }
        }
        public void focus_on_product_list()
        {
            Tabtable1.SelectedIndex = (int)TabIndexType.PRODUCT;
        }

        private void TestButton3_Click(object sender, EventArgs e)
        {
            //this.Tabtable1.TabPages[(int)TabIndexType.PRODUCT].Select();
            Tabtable1.SelectedIndex = (int)TabIndexType.PRODUCT;
        }

        private void BuyinGrid_DoubleClick(object sender, EventArgs e)
        {

        }

        private void BuyinGrid_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            int selected_row_index = e.RowIndex;
            if (selected_row_index >= 0)
            {
                //selected_row_index is not necessarily the bearing index, e.g. after the rows are resorted
                int selected_buyin_index = Convert.ToInt32(BuyinGrid.Rows[selected_row_index].Cells[(int)BuyinRecord.GridColumnType.INDEX].Value);
                BuyinForm AddForm = new BuyinForm(buyinlist[selected_buyin_index], selected_row_index, productlist);
                AddForm.Show();
                AddForm.FormClosed += new FormClosedEventHandler(BuyinForm_FormClosed);
            }
        }

        private void BuyinGrid_CellEnter(object sender, DataGridViewCellEventArgs e)
        {
            int sri = e.RowIndex;
            int sbi = Convert.ToInt32(BuyinGrid.Rows[sri].Cells[(int)BuyinRecord.GridColumnType.INDEX].Value);
            OutputMsg1.Text = buyinlist[sbi].totalPayable.ToString("0.00");
        }
    }
}
