using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using BrightIdeasSoftware;
using System.Reflection;
using System.Reflection.Emit;

namespace SMAT_CE
{
    public partial class DataErrorChecking : FormBase
    {

        iFile datachecker;

        string strErrorFile;//official_24-hr-PM25 020614_BrianT_Fail.csv";
        FileStream fsW;
        StreamWriter sw;
        FileStream fs;
        StreamReader sr;
        DataTable dt = new DataTable();
        //DataTable dtError = new DataTable();
        //Type type;
        string[] strLineArray;
        int iRow = 0;
        int iPage = 0;
        List<errorRecord> lstError = new List<errorRecord>();
        List<List<string>> lstUndo = new List<List<string>>();//List<List<"irow,icolumn,value">>

        int iID = -1, iType = -1, iLat = -1, iLong = -1, iDate = -1, iPM25 = -1, i98Percentile = -1, iStateName = -1, iCountyName = -1, iRank98 = -1, iCompletionCode = -1, iEPA = -1;

        public DataErrorChecking()
        {
            InitializeComponent();
            //txtFile.Text = @"D:\Project\SMAT\Code\SMAT_CE\Data\SampleData\Monitor_data\official_24-hr-PM25.NID2002thru2015_v2 -backup.csv";
        }

        private void DataErrorChecking_Load(object sender, EventArgs e)
        {
            cboAnalysis.Items.Add("Annual PM");
            cboAnalysis.Items.Add("Daily PM");
            cboAnalysis.Items.Add("Ozone");
            cboAnalysis.Items.Add("Visilibity");
            //btnContinueCheck.Enabled = false;
            //btnDelete.Enabled = false;
        }
        
        void ShowGroupsChecked(ObjectListView olv, CheckBox cb)
        {
            if (cb.Checked && olv.View == View.List)
            {
                cb.Checked = false;
                MessageBox.Show("ListView's cannot show groups when in List view.", "Object List View Demo", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else
            {
                olv.ShowGroups = cb.Checked;
                olv.BuildList();
            }
        }
        private void groupBox1_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.Clear(groupBox1.BackColor);
            e.Graphics.DrawString(groupBox1.Text, groupBox1.Font, Brushes.RoyalBlue, 10, 1);
            e.Graphics.DrawLine(Pens.RoyalBlue, 1, 7, 8, 7);
            e.Graphics.DrawLine(Pens.RoyalBlue, e.Graphics.MeasureString(groupBox1.Text, groupBox1.Font).Width + 8, 7, groupBox1.Width - 2, 7);
            e.Graphics.DrawLine(Pens.RoyalBlue, 1, 7, 1, groupBox1.Height - 2);
            e.Graphics.DrawLine(Pens.RoyalBlue, 1, groupBox1.Height - 2, groupBox1.Width - 2, groupBox1.Height - 2);
            e.Graphics.DrawLine(Pens.RoyalBlue, groupBox1.Width - 2, 7, groupBox1.Width - 2, groupBox1.Height - 2);
        }
        private void cboAnalysis_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                cboDatatype.Items.Clear();
                switch (cboAnalysis.Text)
                {
                    case "Annual PM":
                        cboDatatype.Items.Add("Species Monitor Data File");
                        cboDatatype.Items.Add("Unofficial Daily Average PM2.5 Data File");
                        cboDatatype.Items.Add("Official Quarterly Average FRM Data File");
                        break;
                    case "Daily PM":
                        cboDatatype.Items.Add("Species Monitor Data File");
                        cboDatatype.Items.Add("Unofficial Daily Average PM2.5 Data File");
                        cboDatatype.Items.Add("Official Daily Average FRM Data File");
                        break;
                    case "Ozone":
                        cboDatatype.Items.Add("Ozone Monitro Data File");
                        break;
                    case "Visilibity":
                        cboDatatype.Items.Add("IMPROVE Monitor Data - Old Algorithm");
                        cboDatatype.Items.Add("IMPROVE Monitor Data - New Algorithm");
                        break;
                }
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
            }
        }
        private void cbGroups_CheckedChanged(object sender, EventArgs e)
        {
            ShowGroupsChecked(this.olv, (CheckBox)sender);
        }

        private void tsbtnNextPage_Click(object sender, EventArgs e)
        {
            tsbtnBackPage.Enabled = true;
            iPage++;
            if (iPage.ToString() == tsLabelPages.Text.Substring(2) && lstError.Count % 50 != 0)
            {
                tsbtnNextPage.Enabled = false;
                olv.SetObjects(lstError.GetRange(50 * (iPage - 1), lstError.Count % 50));
            }
            else
                olv.SetObjects(lstError.GetRange(50 * (iPage - 1), 50));
            tstxtCurrentPage.Text = iPage.ToString();

            checkCurrentPage();
        }
        private void tsbtnBackPage_Click(object sender, EventArgs e)
        {
            tsbtnNextPage.Enabled = true; 
            iPage--;
            olv.SetObjects(lstError.GetRange(50 * (iPage-1), 50));
            tstxtCurrentPage.Text = iPage.ToString();
            if (iPage == 1) 
                tsbtnBackPage.Enabled = false;
            checkCurrentPage();
        }
        private void tsbtnLastPage_Click(object sender, EventArgs e)
        {
            tsbtnBackPage.Enabled = true;
            tsbtnNextPage.Enabled = false;

            iPage = Convert.ToInt16(tsLabelPages.Text.Substring(2));
            olv.SetObjects(lstError.GetRange(50 * (iPage - 1), lstError.Count % 50));
            tstxtCurrentPage.Text = iPage.ToString();
            checkCurrentPage();
        }
        private void tsbtnFirstPage_Click(object sender, EventArgs e)
        {
            tsbtnNextPage.Enabled = true;
            tsbtnBackPage.Enabled = false;
            iPage=1;
            olv.SetObjects(lstError.GetRange(50 * (iPage - 1), 50));
            tstxtCurrentPage.Text = iPage.ToString();
            checkCurrentPage();
        }
        
        private void btnReplace_Click(object sender, EventArgs e)
        {
            try
            {
                List<string> lstOldData = new List<string>();//it will be used for undo function                
                if (chkReplaceAllSelectedItems.Checked)
                {
                    foreach (var item in olv.SelectedObjects)
                    {
                        lstOldData.Add((item as errorRecord).iRow.ToString() + "," + cboColumn.Text + "," + (item as errorRecord).drInfo[cboColumn.Text]);
                        (item as errorRecord).drInfo[cboColumn.Text] = txtNewValue.Text;
                    }
                }
                else
                {
                    foreach (var item in olv.SelectedObjects)
                    {

                        lstOldData.Add((item as errorRecord).iRow.ToString() + "," + cboColumn.Text + "," + (item as errorRecord).drInfo[cboColumn.Text]);
                        if ((item as errorRecord).drInfo[cboColumn.Text].ToString() == txtOldValue.Text)
                            (item as errorRecord).drInfo[cboColumn.Text] = txtNewValue.Text;
                    }
                }

                lstUndo.Add(lstOldData);
                tsbtnUndo.Enabled = true;
                olv.RefreshSelectedObjects();
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
            }
        }
        private void btnSave_Click(object sender, EventArgs e)
        {
            try
            {
                SaveFileDialog savefile = new SaveFileDialog();
                savefile.Title = "Save files...";
                savefile.InitialDirectory = Path.GetDirectoryName(strErrorFile);
                savefile.Filter = "CSV files(*.csv)|*.csv";
                savefile.RestoreDirectory = true;
                if (savefile.ShowDialog() != DialogResult.OK)
                    return;
                string originFile = CommonClass.ResultFilePath + @"\~Temp.csv";//temp
                string newFile = savefile.FileName;
                File.Copy(originFile, newFile, true);

                fsW = new FileStream(newFile, System.IO.FileMode.Append, System.IO.FileAccess.Write);
                sw = new StreamWriter(fsW, Encoding.Default);
                
                //write new file
                string errorLine = "";
                int count = lstError.First().drInfo.ItemArray.Count();
                foreach (var item in lstError)
                {
                    if (item.errorMsg.Contains("Delete"))
                    {
                        continue;
                    }
                    errorLine = "";
                    for (int i = 1; i < count; i++)
                    {
                        errorLine += "," + item.drInfo[i].ToString();
                    }
                    errorLine = errorLine.Substring(1);                   
                    sw.WriteLine(errorLine);
                }
                sw.Close();
                fsW.Close();

                DialogResult rt = new DialogResult();
                rt = MessageBox.Show("Finish saving! Begin another checking?", "Tip", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
                if (rt == DialogResult.Yes)
                {
                    dt.Columns.Clear();
                    dt.Clear();
                    olv.Clear();
                    lstError.Clear();
                    cboColumn.Items.Clear();
                    iRow = 0;
                    txtReport.Text = "";
                }
                else
                {
                    this.Close();
                }

                FileAttributes fa = File.GetAttributes(newFile);
                File.SetAttributes(newFile, fa & (~FileAttributes.Hidden));
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.Message);
                CommonClass.LogError(ex);
            }
        }
        private void btnOpen_Click(object sender, EventArgs e)
        {
            try
            {
                OpenFileDialog openfile = new OpenFileDialog();
                //openfile.InitialDirectory = Application.StartupPath;
                openfile.RestoreDirectory = true;
                openfile.Title = LanguageOld.Translate("Select file...");
                openfile.Filter = LanguageOld.Translate("CSV Files(*.csv)|*.csv");
                if (openfile.ShowDialog() == DialogResult.OK)
                {
                    txtFile.Text = openfile.FileName;
                }
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
            }
        }
        private void tsbtnUndo_Click(object sender, EventArgs e)
        {
            Undo();
            if(lstUndo.Count==0)
            {
                tsbtnUndo.Enabled=false;
            }
        }
        private void btnContinueCheck_Click(object sender, EventArgs e)
        {
            try
            {
                //if ((sender as Button).Text == "Next")
                //{
                //    string strLine = "";
                //    for (int i = 0; i < dt.Columns.Count; i++)
                //    {
                //        strLineArray[i] = dgv.Rows[dt.Rows.Count - 1].Cells[i].Value.ToString().Trim();
                //        dt.Rows[dt.Rows.Count - 1][i] = strLineArray[i];
                //        strLine += strLineArray[i] + ",";
                //    }
                //    if (strLineArray[iDate].Trim().Length < 6 || Convert.ToDouble(strLineArray[iPM25]) < 0)
                //    {
                //        dgv.DataSource = dt;
                //        dgv.Rows[dt.Rows.Count - 1].DefaultCellStyle.BackColor = Color.Yellow;
                //        return;
                //    }

                //    sw.WriteLine(strLine.Substring(0, strLine.Length - 1));
                //    dgv.Rows[dt.Rows.Count - 1].DefaultCellStyle.BackColor = Color.White;

                //}
                //else if ((sender as Button).Text == "Delete")
                //{
                //    dt.Rows.RemoveAt(dt.Rows.Count - 1);
                //    dgv.DataSource = dt;
                //}

                //bool isOK = continueCheck();
                //if (!isOK) return;
                //MessageBox.Show("OK");
                //SaveFileDialog saveFile = new SaveFileDialog();
                //saveFile.Filter = "CSV(*.csv)|*.csv";
                //saveFile.InitialDirectory = CommonClass.ResultFilePath + @"\Result\";
                //saveFile.Title = Language.Translate("Save data...");
                //if (saveFile.ShowDialog() == DialogResult.Cancel)
                //{ return; }
                //string fileName = saveFile.FileName;
                //File.Copy(@"D:\软件项目\SMAT\SMAT_CE\Code\SMAT_CE\bin\Debug\Data\SampleData\Tmp.csv", fileName, true);

                ////btnContinueCheck.Enabled = false;
                ////btnDelete.Enabled = false;
                //dgv.DataSource = null;
            }
            catch
            { }
        }
        private void btnCheck_Click(object sender, EventArgs e)
        {
            try
            {

                if ((sender as Button).Text == "Next")
                {
                    //bool isOK = checkCurrentPage();
                    //if (!isOK) return;

                    //foreach (DataRow dr in dt.Rows)//改正之后的dt
                    //{
                    //    string str = "";
                    //    for (int i = 1; i < dt.Columns.Count - 1; i++)
                    //    {
                    //        str += dr[i] + ",";
                    //    }
                    //    str += dr[dt.Columns.Count - 1];
                    //    sw.WriteLine(str);
                    //}                    
                    //dt.Clear();
                    ////dtError.Clear();
                    //isOK = continueCheck();
                    //if (!isOK) return;
                }
                else if ((sender as Button).Text == "Check")
                {
                    if (lstError.Count != 0)
                    {
                        DialogResult rt = new DialogResult();
                        rt = MessageBox.Show("Give up the current checking?", "Tip", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
                        if (rt == DialogResult.No)
                        {
                            return;
                        }
                    }
                    dt.Columns.Clear();
                    dt.Clear();
                    olv.Clear();
                    lstError.Clear();
                    iRow = 0;
                    cboColumn.Items.Clear();

                    if (cboDatatype.Text == "")
                    {
                        MessageBox.Show("Please select data type!");
                        return;
                    }
                    if (txtFile.Text == "")
                    {
                        MessageBox.Show("Please select a data file!");
                        return;
                    }

                    WaitShow("Waiting...");

                    if (File.Exists(CommonClass.ResultFilePath + @"\~Temp.csv"))
                    {
                        File.Delete(CommonClass.ResultFilePath + @"\~Temp.csv");
                    }
                    fsW = new FileStream(CommonClass.ResultFilePath + @"\~Temp.csv", System.IO.FileMode.Create, System.IO.FileAccess.Write);
                    File.SetAttributes(CommonClass.ResultFilePath + @"\~Temp.csv", FileAttributes.Hidden);
                    sw = new StreamWriter(fsW, Encoding.Default);

                    strErrorFile = txtFile.Text;
                    fs = new FileStream(strErrorFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                    sr = new StreamReader(fs, System.Text.Encoding.UTF8);

                    #region Datatype
                    switch (cboDatatype.Text)
                    {
                        case "Official Daily Average FRM Data File": datachecker = new Official_Daily_Average_FRM_Data_File(); break;
                        case "Species Monitor Data File": datachecker = new Species_Monitor_Data_File(); break;
                        case "Unofficial Daily Average PM2.5 Data File": datachecker = new Unofficial_Daily_Average_PM25_Data_File(); break;
                        case "Official Quarterly Average FRM Data File": datachecker = new Official_Quarterly_Average_FRM_Data_File(); break;
                        case "Ozone Monitro Data File": datachecker = new Ozone_Monitor_Data_File(); break;
                        case "IMPROVE Monitor Data - Old Algorithm": datachecker = new IMPROVE_Monitor_Data_Old_Algorithm(); break;
                        case "IMPROVE Monitor Data - New Algorithm": datachecker = new IMPROVE_Monitor_Data_New_Algorithm(); break;
                    }

                    #endregion

                    DateTime start = DateTime.Now;

                    string strLine = sr.ReadLine();

                    iRow++;
                    sw.WriteLine(strLine);


                    #region CheckHeader

                    strLine = sr.ReadLine();
                    iRow++;
                    datachecker.GetHeader(strLine);
                    string ro = datachecker.checkColumnHeader(strLine);
                    if (ro != "")
                    {
                        txtReport.Text = string.Format("Report:\r\nChecking File: {0}\r\n", Path.GetFileName(strErrorFile));
                        txtReport.Text += ro;
                        olv.EmptyListMsg = "";
                        WaitClose();
                        sw.Close();
                        fsW.Close();
                        sr.Close();
                        fs.Close();
                        GC.Collect();
                        return;
                    }
                    sw.WriteLine(strLine);

                    #endregion

                    BrightIdeasSoftware.OLVColumn olvCol = new BrightIdeasSoftware.OLVColumn("Row", "iRow");
                    olvCol.Width = 80;
                    olvCol.IsEditable = false;
                    olv.Columns.Add(olvCol);
                    olvCol = new BrightIdeasSoftware.OLVColumn("Error column", "errorMsg");
                    olvCol.Width = 100;
                    olvCol.IsEditable = false;
                    olv.Columns.Add(olvCol);

                    #region test_动态创建类
                    //Type t = ClassHelper.BuildType("MyClass");
                    //List<ClassHelper.CustPropertyInfo> lcpi = new List<ClassHelper.CustPropertyInfo>();
                    //ClassHelper.CustPropertyInfo cpi;

                    //dt.Columns.Add("Row");
                    ////dtError.Columns.Add("Row");
                    //cpi = new ClassHelper.CustPropertyInfo("System.String", "iRow");
                    //lcpi.Add(cpi);
                    //cpi = new ClassHelper.CustPropertyInfo("System.String", "errorMsg");
                    //lcpi.Add(cpi);
                    //for (int j = 0; j < strLineArray.Count(); j++)
                    //{
                    //    string s = strLineArray[j].Trim();
                    //    //dgv.Columns.Add(strLineArray[j], strLineArray[j]);
                    //    dt.Columns.Add(s);
                    //    //dtError.Columns.Add(s);
                    //    cboColumn.Items.Add(s);
                    //    olvCol = new BrightIdeasSoftware.OLVColumn(s, s);
                    //    olvCol.Width = 80;
                    //    olv.Columns.Add(olvCol);

                    //    cpi = new ClassHelper.CustPropertyInfo("System.String", s);
                    //    lcpi.Add(cpi);

                    //}

                    //t = ClassHelper.AddProperty(t, lcpi);
                    //type = t;
                    #endregion

                    #region test_datarow
                    dt.Columns.Add("Row");
                    //dtError.Columns.Add("Row");
                    strLineArray = strLine.ToLower().Split(',');
                    for (int j = 0; j < strLineArray.Count(); j++)
                    {
                        string s = strLineArray[j].Trim();
                        //dgv.Columns.Add(strLineArray[j], strLineArray[j]);
                        dt.Columns.Add(s);
                        //dtError.Columns.Add(s);
                        cboColumn.Items.Add(s);
                        olvCol = new BrightIdeasSoftware.OLVColumn(s, "drInfo[" + strLineArray[j].Trim() + "]");
                        olvCol.Width = 80;
                        olv.Columns.Add(olvCol);
                    }
                    #endregion

                    //sw.WriteLine(strLine);

                    int iRow2 = iRow;
                    List<int> lstRepeatedLines = new List<int>();
                    while(sr.Peek()>0)
                    {
                        iRow2++;
                        strLine = sr.ReadLine();

                        string errorMessage = "";
                        int i=-1;
                        errorMessage = datachecker.checkRepeatedLines(strLine, iRow2, out i);

                        if(errorMessage!=""&&i!=-1)
                        {
                            //if (!lstRepeatedLines.Contains(i))
                            //    lstRepeatedLines.Add(i);
                            lstRepeatedLines.Add(iRow2);
                        }
                    }
                    sr.Close();
                    fs.Close();
                    GC.Collect();

                    fs = new FileStream(strErrorFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                    sr = new StreamReader(fs, System.Text.Encoding.UTF8);
                    iRow2 = 0;
                    while(iRow2!=iRow)
                    {
                        iRow2++;
                        sr.ReadLine();
                    }


                    #region CheckData  一次性检查所有的
                    txtReport.Text = string.Format("Report:\r\nChecking File: {0}\r\n", Path.GetFileName(strErrorFile));
                    //int iCount = 0;
                    while (sr.Peek() > 0)// && iCount < 1000)
                    {
                        iRow++;
                        strLine = sr.ReadLine();
                        string errorColumn = "";
                        if (lstRepeatedLines.Contains(iRow))
                        {
                            errorColumn = ",Repeated line";
                        }
                        //DataRow dr = dt.NewRow();
                        //dr[0] = iRow;
                        //strLineArray = strLine.Split(',');
                        //for (int j = 0; j < strLineArray.Count(); j++)
                        //{
                        //    dr[j + 1] = strLineArray[j];
                        //}
                        else
                        { errorColumn = datachecker.checkData(strLine); }
                        if (errorColumn != "")
                        {
                            DataRow dr = dt.NewRow();
                            //object[] o = new object[dt.Columns.Count];
                            //o[0] = iRow;

                            strLineArray = strLine.Split(',');
                            for (int j = 0; j < strLineArray.Count(); j++)
                            {
                                //o[j + 1] = strLineArray[j];
                                dr[j + 1] = strLineArray[j];
                            }

                            //dr.ItemArray = o;
                            errorRecord erRecord = new errorRecord();
                            erRecord.iRow = iRow;
                            //erRecord.drInfo = o;
                            erRecord.drInfo = dr;
                            //txtReport.Text += "Error occur in row " + iRow + ": invalid ";
                            erRecord.errorMsg = errorColumn.Substring(1);
                            //foreach (var item in errorColumn.Substring(1).Split(','))
                            //{
                            //    txtReport.Text += "\"" + item + "\"";
                            //}
                            lstError.Add(erRecord);
                            //txtReport.Text += "\r\n";
                        }
                        else
                        {
                            sw.WriteLine(strLine);
                            //olv.EmptyListMsg = "";
                        }
                        ////if (dt.Rows.Count > 4)
                        ////    dt.Rows.RemoveAt(0);
                        ////dt.Rows.Add(dr);
                        ////dgv.DataSource = dt;
                        //double d = 0;
                        //if (strLineArray[iDate].Trim().Length < 6 || !double.TryParse(strLineArray[iPM25], out d) || Convert.ToDouble(strLineArray[iPM25]) < 0)
                        //{
                        //    errorRecord erRecord = new errorRecord();
                        //    erRecord.iRow = iRow.ToString();
                        //    erRecord.drInfo = dr;
                        //    txtReport.Text += "Error occur in row " + iRow + ": invalid ";

                        //    if (strLineArray[iDate].Trim().Length < 6)
                        //    {
                        //        erRecord.errorMsg = "Date";
                        //        txtReport.Text += "\"Date\" ";
                        //    }
                        //    if (!double.TryParse(strLineArray[iPM25], out d) || Convert.ToDouble(strLineArray[iPM25]) < 0)
                        //    {
                        //        erRecord.errorMsg += "PM25";
                        //        txtReport.Text += "\"PM25\"";
                        //    }
                        //    //dtError.ImportRow(dr);
                        //    //dgv.DataSource = dt;
                        //    //dgv.Rows[dt.Rows.Count - 1].DefaultCellStyle.BackColor = Color.Yellow;
                        //    //btnContinueCheck.Enabled = true;
                        //    //btnDelete.Enabled = true;
                        //    //lblReport.Text = "Error occur in row" + iRow + " – DATE is invalid.";
                        //    //return false;
                        //    lstError.Add(erRecord);

                        //    txtReport.Text += "\r\n";
                        //    //object o = ClassHelper.CreateInstance(type);
                        //    //ClassHelper.SetPropertyValue(o, "iRow", dr[0]);
                        //    //ClassHelper.SetPropertyValue(o, "errorMsg", erRecord.errorMsg);
                        //    //for (int i = 1; i < dt.Columns.Count; i++)
                        //    //{
                        //    //    ClassHelper.SetPropertyValue(o, dt.Columns[i].ColumnName, dr[i]);
                        //    //}
                        //    //lst.Add(o);
                        //}
                        //sw.WriteLine(strLine);
                        //iCount++;                        
                    }


                    if (lstError.Count != 0)
                    {
                        //dgv.DataSource = dtError;
                        if (lstError.Count <= 50)
                        {
                            olv.SetObjects(lstError);
                            tsLabelPages.Text = "/ 1";
                            tsbtnNextPage.Enabled = false;
                            tsbtnBackPage.Enabled = false;
                            tsbtnFirstPage.Enabled = false;
                            tsbtnLastPage.Enabled = false;
                        }
                        else
                        {
                            tsbtnNextPage.Enabled = true;
                            tsbtnBackPage.Enabled = true;
                            tsbtnFirstPage.Enabled = true;
                            tsbtnLastPage.Enabled = true;
                            olv.SetObjects(lstError.GetRange(0, 50));
                            tsLabelPages.Text = "/ " + Math.Ceiling(lstError.Count / 50.0).ToString();
                        }
                        //tsLabelPages.Text = string.Format(tsLabelPages.Text, Math.Ceiling(lstError.Count / 50.0).ToString());
                        tstxtCurrentPage.Text = "1";
                        iPage = 1;
                    }
                    else
                    {
                        olv.EmptyListMsg = "The selected data file is avaliable!";
                        txtReport.Text += "\"Data Error Checking Finished!\"";
                    }

                    DateTime end = DateTime.Now;
                    //double timecost = end.Subtract(start).TotalSeconds;
                    #endregion

                    checkCurrentPage();

                    WaitClose();
                    sw.Close();
                    fsW.Close();
                    sr.Close();
                    fs.Close();
                    GC.Collect();

                    //btnCheck.Text = "Next";
                    //bool isOK = continueCheck();
                    //if (!isOK) return;
                    //MessageBox.Show("OK");
                    //btnContinueCheck.Enabled = false;
                    //btnDelete.Enabled = false;
                    //dgv.DataSource = null;
                }

            }
            catch
            {
                WaitClose();
                sw.Close();
                fsW.Close();
                sr.Close();
                fs.Close();
                GC.Collect();
            }
        }
        private void tsbtnCheckCurrentPage_Click(object sender, EventArgs e)
        {
            checkCurrentPage();
        }
        private void tsbtnDelete_Click(object sender, EventArgs e)
        {
            if (olv.SelectedItems != null)
            {
                List<string> lst = new List<string>();
                foreach (var item in olv.SelectedObjects)
                {
                    if (!(item as errorRecord).errorMsg.Contains("Delete"))
                    {
                        lst.Add((item as errorRecord).iRow.ToString() + ",Delete," + (item as errorRecord).errorMsg);
                        (item as errorRecord).errorMsg = "Delete," + (item as errorRecord).errorMsg;
                    }
                }
                //foreach (ListViewItem lvi in olv.SelectedItems)
                //{
                    
                //    //lvi.ForeColor = Color.Red;
                //    lvi.BackColor = Color.FromArgb(255, 199, 206);
                //    for (int i = 0; i < olv.Columns.Count; i++)
                //    {
                //        lvi.SubItems[i].BackColor = lvi.BackColor;
                //    }
                //}
                if (lst.Count != 0)
                { lstUndo.Add(lst); }
                tsbtnUndo.Enabled = true;
            }
            olv.RefreshSelectedObjects();
            olv.SelectedObjects = null;
        }

        //private void dgv_CellEnter(object sender, DataGridViewCellEventArgs e)
        //{
        //    if (dgv.CurrentCell.ColumnIndex == 0)
        //    {
        //        dgv.CurrentCell.ReadOnly = true;
        //    }
        //}
        private void Undo()
        {
            try
            {
                foreach (var LastChangedData in lstUndo.Last())
                {
                    string[] data = LastChangedData.Split(',');
                    int irow = Convert.ToInt16(data[0]);
                    string columntext = data[1];
                    string value = data[2];

                    foreach (var item in lstError)
                    {
                        if (item.iRow == irow)
                        {
                            if (columntext=="Delete")
                            {
                                item.errorMsg = value;
                            }
                            else
                            {
                                item.drInfo[columntext] = value;
                            }
                            olv.RefreshObject(item);
                        }
                    }
                }
                lstUndo.Remove(lstUndo.Last());
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
            }
        }
        private void olv_FormatCell(object sender, FormatCellEventArgs e)
        {
            if (e.ColumnIndex == 1)
            {
                if (e.CellValue.ToString() == "OK") e.SubItem.ForeColor = Color.Green;
                else if (e.CellValue.ToString().Contains("Delete"))
                {
                    e.SubItem.ForeColor = Color.FromArgb(156, 0, 6);
                    //e.SubItem.BackColor = Color.FromArgb(255, 199, 206);
                    olv.Items[e.RowIndex].BackColor = Color.FromArgb(255, 199, 206);
                    for (int i = 0; i < olv.Columns.Count; i++)
                    {
                        olv.Items[e.RowIndex].SubItems[i].BackColor = Color.FromArgb(255, 199, 206);
                    }
                }
                else
                {
                    e.SubItem.ForeColor = Color.FromArgb(156, 0, 6);
                }
            }
        }
        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (chkReplaceAllSelectedItems.Checked)
                txtOldValue.Enabled = false;
            else
                txtOldValue.Enabled = true;
        }
        private void olv_CellEditFinishing(object sender, CellEditEventArgs e)
        {
            if ((olv.SelectedObject as errorRecord).drInfo[e.Column.Text].ToString() != e.NewValue.ToString())
            {
                List<string> lstOldData = new List<string>();
                lstOldData.Add((olv.SelectedObject as errorRecord).iRow.ToString() + "," + e.Column.Text + "," + (olv.SelectedObject as errorRecord).drInfo[e.Column.Text]);
                lstUndo.Add(lstOldData);
                tsbtnUndo.Enabled = true;

                (olv.SelectedObject as errorRecord).drInfo[e.Column.Text] = e.NewValue;
            }
        }
        
        bool checkCurrentPage()
        {
            try
            {

                txtReport.Text = string.Format("Report:\r\nChecking File: {0}\r\n", Path.GetFileName(strErrorFile));
                if (olv.Items.Count == 0)
                {
                    txtReport.Text += "\"Data Error Checking Finished!\"";
                    return true;
                }

                bool isOK = true;


                for (int i = 0; i < olv.Items.Count; i++)
                {
                    string error = "";
                    string data = "";
                    for (int j = 2; j < olv.Items[i].SubItems.Count; j++)
                    {
                        data += "," + olv.Items[i].SubItems[j].Text;
                    }
                    error = datachecker.checkData(data.Substring(1));
                    if ((olv.Objects as List<errorRecord>)[i].errorMsg.Contains("Repeated line"))
                    {
                        error = ",Repeated line";
                    }

                    if (error != "")
                    {
                        isOK = false;

                        if ((olv.Objects as List<errorRecord>)[i].errorMsg.Contains("Delete"))
                        {
                            (olv.Objects as List<errorRecord>)[i].errorMsg = "Delete," + error.Substring(1);
                            olv.Items[i].SubItems[1].Text = "Delete," + error.Substring(1);
                        }
                        else
                        {
                            (olv.Objects as List<errorRecord>)[i].errorMsg = error.Substring(1);
                            olv.Items[i].SubItems[1].Text = error.Substring(1);
                        }
                        olv.Items[i].SubItems[1].ForeColor = Color.FromArgb(156, 0, 6);

                        txtReport.Text += "Error occur in row " + (olv.Objects as List<errorRecord>)[i].iRow + ": invalid ";
                        //add the error tip for COMPLETION_CODE ,by devin,20190719
                        Dictionary<string, string> DicErrorTip = new Dictionary<string, string>() { { "COMPLETION_CODE", "it should be a number" } };
                        string errorTip = DicErrorTip.ContainsKey(olv.Items[i].SubItems[1].Text) ? ", " + DicErrorTip[olv.Items[i].SubItems[1].Text] : "";

                        foreach (var item in error.Substring(1).Split(','))
                        {
                            txtReport.Text += "\"" + item + "\" " + errorTip;
                        }
                        txtReport.Text += "\r\n";
                    }
                    else
                    {
                        if ((olv.Objects as List<errorRecord>)[i].errorMsg.Contains("Delete"))
                        {
                            (olv.Objects as List<errorRecord>)[i].errorMsg = "Delete,OK";
                            olv.Items[i].SubItems[1].Text = "Delete,OK";
                        }
                        else
                        {
                            (olv.Objects as List<errorRecord>)[i].errorMsg = "OK";
                            olv.Items[i].SubItems[1].Text = "OK";
                        }
                        olv.Items[i].SubItems[1].ForeColor = Color.Green;
                    }

                    //if (dgv.Rows[i].Cells[iDate].Value.ToString().Trim().Length < 8 || !double.TryParse(strLineArray[iPM25], out d) || Convert.ToDouble(dgv.Rows[i].Cells[iPM25].Value.ToString().Trim()) < 0)
                    //{
                    //    isOK = false;
                    //}

                }
                if (isOK == true)
                {
                    txtReport.Text += "\"Data Error Checking Finished!\"";
                }
                return isOK;
            }
            catch
            {
                return false;
            }
        }
        //bool continueCheck()
        //{
        //    try
        //    {
        //        List<errorRecord> lstError = new List<errorRecord>();
        //        List<object> lst = new List<object>();
        //        txtReport.Text = "Report:\r\n";
        //        string strLine = "";
        //        int iCount = 0;
        //        while (sr.Peek() > 0 && iCount < 1000)
        //        {
        //            strLine = sr.ReadLine();
        //            strLineArray = strLine.Split(new char[] { ',' });
        //            DataRow dr = dt.NewRow();
        //            dr[0] = iRow;
        //            for (int j = 0; j < strLineArray.Count(); j++)
        //            {
        //                dr[j + 1] = strLineArray[j];
        //            }
        //            //if (dt.Rows.Count > 4)
        //            //    dt.Rows.RemoveAt(0);
        //            dt.Rows.Add(dr);
        //            //dgv.DataSource = dt;
        //            iRow++;
        //            double d = 0;
        //            if (strLineArray[iDate].Trim().Length < 6 || !double.TryParse(strLineArray[iPM25], out d) || Convert.ToDouble(strLineArray[iPM25]) < 0)
        //            {
        //                errorRecord erRecord = new errorRecord();
        //                erRecord.iRow = iRow;
        //                erRecord.drInfo = dr;
        //                txtReport.Text += "Error occur in row " + iRow + ": invalid ";

        //                if (strLineArray[iDate].Trim().Length < 6)
        //                {
        //                    erRecord.errorMsg = "Date";
        //                    txtReport.Text += "\"Date\" ";
        //                }
        //                if (!double.TryParse(strLineArray[iPM25], out d) || Convert.ToDouble(strLineArray[iPM25]) < 0)
        //                {
        //                    erRecord.errorMsg += "PM25";
        //                    txtReport.Text += "\"PM25\"";
        //                }
        //                //dtError.ImportRow(dr);
        //                //dgv.DataSource = dt;
        //                //dgv.Rows[dt.Rows.Count - 1].DefaultCellStyle.BackColor = Color.Yellow;
        //                //btnContinueCheck.Enabled = true;
        //                //btnDelete.Enabled = true;
        //                //lblReport.Text = "Error occur in row" + iRow + " – DATE is invalid.";
        //                //return false;
        //                lstError.Add(erRecord);

        //                txtReport.Text += "\r\n";
        //                //object o = ClassHelper.CreateInstance(type);
        //                //ClassHelper.SetPropertyValue(o, "iRow", dr[0]);
        //                //ClassHelper.SetPropertyValue(o, "errorMsg", erRecord.errorMsg);
        //                //for (int i = 1; i < dt.Columns.Count; i++)
        //                //{
        //                //    ClassHelper.SetPropertyValue(o, dt.Columns[i].ColumnName, dr[i]);
        //                //}
        //                //lst.Add(o);
        //            }
        //            //sw.WriteLine(strLine);
        //            iCount++;
        //        }


        //        //if (lstError.Count == 0)
        //        if (lstError.Count == 0)
        //        {
        //            foreach (DataRow dr in dt.Rows)
        //            {
        //                string s = "";
        //                for (int i = 0; i < dt.Columns.Count - 1; i++)
        //                {
        //                    s += dr[i] + ",";
        //                }
        //                s += dr[dt.Columns.Count - 1];
        //                sw.WriteLine(s);
        //            }
        //            dt.Clear();
        //            //dtError.Clear();
        //            if (sr.Peek() > 0)
        //                return continueCheck();
        //        }
        //        else
        //        {
        //            //dgv.DataSource = dtError;

        //            olv.SetObjects(lstError);

        //            #region test_用创建的那个类填objectlistview
        //            //List<OLVListItem> lstItem = new List<OLVListItem>();
        //            //foreach (DataRow row in dtError.Rows)
        //            //{
        //            //    object o = ClassHelper.CreateInstance(type);
        //            //    //string[] subitems = new string[dtError.Columns.Count];

        //            //    //object[] o = row.ItemArray;
        //            //    for (int i = 0; i < dtError.Columns.Count; i++)
        //            //    {
        //            //        //subitems[i] = o[i].ToString();
        //            //        ClassHelper.SetPropertyValue(o, dtError.Columns[i].ColumnName, row[i]);
        //            //    }
        //            //    lst.Add(o);
        //            //    //OLVListItem item = new OLVListItem(subitems);
        //            //    //lstItem.Add(item);
        //            //    //olv.Items.Add(item);
        //            //}
        //            //olv.BeginUpdate();
        //            //olv.SetObjects(lst);
        //            //olv.EndUpdate();
        //            #endregion
        //            return false;
        //        }

        //        return true;
        //    }
        //    catch
        //    {
        //        return false;
        //    }
        //}


        #region 等待窗口
        TipGIF waitMess = new TipGIF();//等待窗体
        bool sFlog = true;
        //--显示等待窗体 
        private void ShowWaitMess()
        {
            try
            {
                if (!waitMess.IsDisposed)
                {
                    waitMess.ShowDialog();
                }
            }
            catch (System.Threading.ThreadAbortException Err)
            {
                MessageBox.Show(Err.Message);
            }
        }

        //--新开辟一个线程调用 
        public void WaitShow(string msg)
        {
            try
            {
                if (sFlog == true)
                {
                    sFlog = false;
                    waitMess.Msg = msg;
                    waitMess.Title = Language.Localization.GetValue("Tip");
                    //ShowWaitMess();
                    System.Threading.Thread upgradeThread = null;
                    upgradeThread = new System.Threading.Thread(new System.Threading.ThreadStart(ShowWaitMess));
                    upgradeThread.Start();
                    //upgradeThread.IsBackground = true;
                }
            }
            catch (System.Threading.ThreadAbortException Err)
            {
                MessageBox.Show(Err.Message);
            }
        }
        private delegate void CloseFormDelegate();
        private delegate void ChangeDelegate(string msg);
        //--关闭等待窗体 
        public void WaitClose()
        {
            //同步到主线程上
            if (waitMess.InvokeRequired)
                waitMess.Invoke(new CloseFormDelegate(DoCloseJob));
            else
                DoCloseJob();
        }

        public void WaitChangeMsg(string msg)
        {
            try
            {
                if (waitMess.InvokeRequired)
                    waitMess.Invoke(new ChangeDelegate(DoChange), msg);
            }
            catch (System.Threading.ThreadAbortException Err)
            {
                MessageBox.Show(Err.Message);
            }
        }
        private void DoChange(string msg)
        {
            try
            {
                if (!waitMess.IsDisposed)
                {
                    if (waitMess.Created)
                    {
                        //sFlog = true;
                        waitMess.Msg = msg;
                        waitMess.Title = Language.Localization.GetValue("Tip");
                    }
                }
            }
            catch (System.Threading.ThreadAbortException Err)
            {
                MessageBox.Show(Err.Message);
            }
        }
        private void DoCloseJob()
        {
            try
            {
                if (!waitMess.IsDisposed)
                {
                    if (waitMess.Created)
                    {
                        sFlog = true;
                        waitMess.Close();
                    }
                }
            }
            catch (System.Threading.ThreadAbortException Err)
            {
                MessageBox.Show(Err.Message);
            }
        }
        #endregion 等待窗口


        private void olv_KeyDown(object sender, KeyEventArgs e)
        {
            if(e.KeyCode==Keys.Delete&&olv.SelectedItems.Count!=0)
            {
                tsbtnDelete_Click(null, null);
            }
        }
    }



    public interface iFile
    {
        /// <summary>
        /// check column headers,
        /// returns error columns or nothing
        /// </summary>
        /// <param name="header">header line</param>
        /// <returns>error columns or nothing</returns>
        string checkColumnHeader(string header);

        /// <summary>
        /// check data,
        /// returns error columns or nothing
        /// </summary>
        /// <param name="data">data line</param>
        /// <returns>error columns or nothing</returns>
        string checkData(string data);

        string checkRepeatedLines(string data, int row,out int firstRow);

        void GetHeader(string data);

        void Clear();
    }
    class CheckingFunction
    {
        /// <summary>
        /// check double data Positive
        /// </summary>
        /// <param name="strLineArray">data line</param>
        /// <param name="ids">Id Array</param>
        /// <returns>error ids</returns>
        public List<int> CheckDoubleDataPositive(string[] strLineArray, int[] ids)
        {
            try
            {
                double d = 0;
                List<int> errorid = new List<int>();
                foreach (int id in ids)
                {
                    if (strLineArray[id] == "" || id < 0)
                    {
                        continue;
                    }
                    if (!double.TryParse(strLineArray[id], out d))
                    {
                        errorid.Add(id);
                        continue;
                    }
                    if (d < 0 && d != -9 && d != -7)
                    {
                        errorid.Add(id);
                        continue;
                    }
                }
                return errorid;
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return null;
            }

        }

        /// <summary>
        /// check double data
        /// </summary>
        /// <param name="strLineArray">data line</param>
        /// <param name="ids">Id Array</param>
        /// <returns>error ids</returns>
        public List<int> CheckDoubleData(string[] strLineArray, int[] ids)
        {
            try
            {
                double d = 0;
                List<int> errorid = new List<int>();
                foreach (int id in ids)
                {
                    if (strLineArray[id] == "" || id < 0)
                    {
                        continue;
                    }
                    if (!double.TryParse(strLineArray[id], out d))
                    {
                        errorid.Add(id);
                        continue;
                    }
                    //if (d < 0 && d != -9 && d != -7)
                    //{
                    //    errorid.Add(id);
                    //    continue;
                    //}
                }
                return errorid;
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return null;
            }

        }

        /// <summary>
        /// check int data
        /// </summary>
        /// <param name="strLineArray"></param>
        /// <param name="ids"></param>
        /// <returns></returns>
        public List<int> CheckIntData(string[] strLineArray, int[] ids)
        {
            try
            {
                int d = 0;
                List<int> errorid = new List<int>();
                foreach (int id in ids)
                {
                    if (strLineArray[id] == "" || id < 0)
                    {
                        continue;
                    }
                    if (!int.TryParse(strLineArray[id], out d))
                    {
                        errorid.Add(id);
                        continue;
                    }
                    //if (d < 0)
                    //{
                    //    errorid.Add(id);
                    //    continue;
                    //}
                }
                return errorid;
            }
            catch (Exception ex)
            {
                CommonClass.LogError(ex);
                return null;
            }

        }
    }

    class Official_Daily_Average_FRM_Data_File :CheckingFunction, iFile
    {
        #region ColumnHeaders

        string[] columnheader = new string[] { "_id", "_type", "lat", "long", "date", "pm25", "98_percentile", "epa_flag", "completion_code", "_state_name", "_county_name", "rank98" };
        int iID = -1, iType = -1, iLat = -1, iLong = -1, iDate = -1, iPM25 = -1, i98Percentile = -1, iStateName = -1, iCountyName = -1, iRank98 = -1, iCompletionCode = -1, iEPA = -1;
        string[] dataheader;
        #endregion
        Dictionary<string, int> dicID = new Dictionary<string, int>();
        public string checkRepeatedLines(string dataline, int iRow, out int i)
        {
            i = -1;
            string[] strLineArray = dataline.Split(',');
            string errorMessage = "";
            if (dicID.ContainsKey(strLineArray[iID] + strLineArray[iDate]))
            {
                i = dicID[strLineArray[iID] + strLineArray[iDate]];
                errorMessage = "Repeated Lines";
            }
            else
            {
                dicID.Add(strLineArray[iID] + strLineArray[iDate], iRow);
            }


            return errorMessage;
        }

        public void GetHeader(string data)
        {
            string[] strArray = data.Split(',');
            dataheader = new string[strArray.Length];
            strArray.CopyTo(dataheader, 0);
        }
        public string checkColumnHeader(string header)
        {
            string errorMessage = "";
            string[] temp = header.Replace("\"","").ToLower().Split(',');
            for (int i = 0; i < temp.Length; i++)
            {
                switch (temp[i].Trim())
                {
                    case "_id":             iID = i;                break;
                    case "_type":           iType = i;              break;
                    case "lat":             iLat = i;               break;
                    case "long":            iLong = i;              break;
                    case "date":            iDate = i;              break;
                    case "pm25":            iPM25 = i;              break;
                    case "98_percentile":   i98Percentile = i;      break;
                    case "epa_flag":        iEPA = i;               break;
                    case "completion_code": iCompletionCode = i;    break;
                    case "_state_name":     iStateName = i;         break;
                    case "_county_name":    iCountyName = i;        break;
                    case "rank98":          iRank98 = i;            break;
                    //default:
                    //    errorMessage += "Invalid Column " + temp[i] + "\r\n ";
                    //    break;
                }
            }
            if (iID < 0 || iType < 0 || iLat < 0 || iLong < 0 || iDate < 0 || iPM25 < 0 || i98Percentile < 0 || iStateName < 0 || iCountyName < 0 || iRank98 < 0 || iCompletionCode < 0 || iEPA < 0)
            {
                errorMessage += "Missing Column \r\n ";
            }
            return errorMessage;
        }
        public string checkData(string data)
        {
            string errorMessage = "";
            string[] strLineArray = data.Split(',');
            double d = 0;
            DateTime date = DateTime.Now;

            if (!double.TryParse(strLineArray[iLat], out d))
            {
                errorMessage += ",LAT";
            }
            if (!double.TryParse(strLineArray[iLong], out d))
            {
                errorMessage += ",LONG";
            }
            if (strLineArray[iDate].Trim().Length < 6)//||!DateTime.TryParse(strLineArray[iDate],out date))
            {
                errorMessage += ",Date";
            }
            //if (!double.TryParse(strLineArray[iPM25], out d) || Convert.ToDouble(strLineArray[iPM25]) < 0)
            //{
            //    errorMessage += ",PM25";
            //}


            List<int> lstid = new List<int>();
            int[] iDoubleData = new int[] { iPM25 };
            lstid = CheckDoubleDataPositive(strLineArray, iDoubleData);

            int[] iIntData = new int[] { i98Percentile, iRank98, iCompletionCode, iEPA };
            lstid.AddRange(CheckIntData(strLineArray, iIntData));
            if (lstid.Count != 0)
            {
                foreach (int id in lstid)
                {
                    errorMessage += "," + dataheader[id];
                }
            }
            return errorMessage;
        }

        public void Clear()
        {
            dicID.Clear();
        }
    }

    class Official_Quarterly_Average_FRM_Data_File :CheckingFunction, iFile
    {
        #region ColumnHeaders

        string[] columnheader = new string[] { "_id", "_type", "lat", "long", "date", "pm25", "ndays", "_substitution_code", "completion_code", "_state_name", "_county_name" };
        int iID = -1, iType = -1, iLat = -1, iLong = -1, iDate = -1, iPM25 = -1, iNDays = -1, iStateName = -1, iCountyName = -1, iSubstitudionCode = -1, iCompletionCode = -1;
        string[] dataheader;
        Dictionary<string, int> dicID = new Dictionary<string, int>();

        #endregion
        public void GetHeader(string data)
        {
            string[] strArray = data.Split(',');
            dataheader = new string[strArray.Length];
            strArray.CopyTo(dataheader, 0);
        }
        public string checkColumnHeader(string header)
        {
            string errorMessage = "";
            string[] temp = header.Replace("\"", "").ToLower().Split(',');
            for (int i = 0; i < temp.Length; i++)
            {
                switch (temp[i].Trim())
                {
                    case "_id": iID = i; break;
                    case "_type": iType = i; break;
                    case "lat": iLat = i; break;
                    case "long": iLong = i; break;
                    case "date": iDate = i; break;
                    case "pm25": iPM25 = i; break;
                    case "ndays": iNDays = i; break;
                    case "completion_code": iCompletionCode = i; break;
                    case "_state_name": iStateName = i; break;
                    case "_county_name": iCountyName = i; break;
                    case "_substitution_code": iSubstitudionCode = i; break;
                    //default:
                    //    errorMessage += "Invalid Column " + temp[i] + "\r\n ";
                    //    break;
                }
            }
            if (iID < 0 || iType < 0 || iLat < 0 || iLong < 0 || iDate < 0 || iPM25 < 0 || iNDays < 0 || iStateName < 0 || iCountyName < 0 || iSubstitudionCode < 0 || iCompletionCode < 0 )
            {
                errorMessage += "Missing Column \r\n ";
            }
            return errorMessage;
        }
        public string checkData(string data)
        {
            string errorMessage = "";
            string[] strLineArray = data.Split(',');
            double d = 0;
            DateTime date = DateTime.Now;

            if (strLineArray[iDate].Trim().Length < 8)//|| !DateTime.TryParse(strLineArray[iDate], out date)
            {
                errorMessage += ",Date";
            }

            if (!double.TryParse(strLineArray[iLat],out d))
            {
                errorMessage += ",LAT";
            }
            if (!double.TryParse(strLineArray[iLong], out d))
            {
                errorMessage += ",LONG";
            }
            //add the validation of CompletionCode, by devin,20190719
            int cCode = 0;
            if (!int.TryParse(strLineArray[iCompletionCode], out cCode))
            {
                errorMessage += ",COMPLETION_CODE";
            }
            List<int> lstid = new List<int>();
            int[] iDoubleData = new int[] { iPM25 };
            lstid = CheckDoubleDataPositive(strLineArray, iDoubleData);
            int[] iIntData = new int[] { iNDays };
            lstid.AddRange(CheckIntData(strLineArray, iIntData));
            if (lstid.Count != 0)
            {
                foreach (int id in lstid)
                {
                    errorMessage += "," + dataheader[id];
                }
            }
            return errorMessage;
        }

        public string checkRepeatedLines(string dataline, int iRow, out int i)
        {
            i = -1;
            string[] strLineArray = dataline.Split(',');
            string errorMessage = "";
            if (dicID.ContainsKey(strLineArray[iID] + strLineArray[iDate]))
            {
                i = dicID[strLineArray[iID] + strLineArray[iDate]];
                errorMessage = "Repeated Lines";
            }
            else
            {
                dicID.Add(strLineArray[iID] + strLineArray[iDate], iRow);
            }


            return errorMessage;
        }

        public void Clear()
        {
            dicID.Clear();
        }
    }

    class Unofficial_Daily_Average_PM25_Data_File :CheckingFunction, iFile
    {
        #region ColumnHeaders

        string[] columnheader = new string[] { "_id", "_type", "lat", "long", "date", "pm25", "epa_flags", "user_flags"};
        int iID = -1, iType = -1, iLat = -1, iLong = -1, iDate = -1, iPM25 = -1, iEPAFlags = -1, iUserFlags = -1;
        string[] dataheader;
        #endregion
        Dictionary<string, int> dicID = new Dictionary<string, int>();
        public void GetHeader(string data)
        {
            string[] strArray = data.Split(',');
            dataheader = new string[strArray.Length];
            strArray.CopyTo(dataheader, 0);
        }
        public string checkColumnHeader(string header)
        {
            string errorMessage = "";
            string[] temp = header.Replace("\"", "").ToLower().Split(',');
            for (int i = 0; i < temp.Length; i++)
            {
                switch (temp[i].Trim())
                {
                    case "_id": iID = i; break;
                    case "_type": iType = i; break;
                    case "lat": iLat = i; break;
                    case "long": iLong = i; break;
                    case "date": iDate = i; break;
                    case "pm25": iPM25 = i; break;
                    case "epa_flag": iEPAFlags = i; break;
                    case "user_flag": iUserFlags = i; break;
                    //default:
                    //    errorMessage += "Invalid Column " + temp[i] + "\r\n ";
                    //    break;
                }
            }
            if (iID < 0 || iType < 0 || iLat < 0 || iLong < 0 || iDate < 0 || iPM25 < 0 || iEPAFlags < 0 || iUserFlags < 0)
            {
                errorMessage += "Missing Column \r\n ";
            }
            return errorMessage;
        }
        public string checkData(string data)
        {
            string errorMessage = "";
            string[] strLineArray = data.Split(',');
            double d = 0;
            DateTime date = DateTime.Now;

            if (!double.TryParse(strLineArray[iLat], out d))
            {
                errorMessage += ",LAT";
            }
            if (!double.TryParse(strLineArray[iLong], out d))
            {
                errorMessage += ",LONG";
            }
            if (strLineArray[iDate].Trim().Length < 6)// || !DateTime.TryParse(strLineArray[iDate], out date))
            {
                errorMessage += ",Date";
            }
            //if (!double.TryParse(strLineArray[iPM25], out d) || Convert.ToDouble(strLineArray[iPM25]) < 0)
            //{
            //    errorMessage += ",PM25";
            //}
            //if (!double.TryParse(strLineArray[iEPAFlags], out d))
            //{
            //    errorMessage += ",EPA_FLAG";
            //}
            List<int> lstid = new List<int>();
            int[] iDoubleData = new int[] { iPM25  };
            lstid = CheckDoubleDataPositive(strLineArray, iDoubleData);
            int[] iIntData = new int[] { iEPAFlags, iUserFlags };
            lstid.AddRange(CheckIntData(strLineArray, iIntData));
            if (lstid.Count != 0)
            {
                foreach (int id in lstid)
                {
                    errorMessage += "," + dataheader[id];
                }
            }

            return errorMessage;
        }

        public string checkRepeatedLines(string dataline, int iRow, out int i)
        {
            i = -1;
            string[] strLineArray = dataline.Split(',');
            string errorMessage = "";
            if (dicID.ContainsKey(strLineArray[iID] + strLineArray[iDate]))
            {
                i = dicID[strLineArray[iID] + strLineArray[iDate]];
                errorMessage = "Repeated Lines";
            }
            else
            {
                dicID.Add(strLineArray[iID] + strLineArray[iDate], iRow);
            }


            return errorMessage;
        }

        public void Clear()
        {
            dicID.Clear();
        }
    }

    class Species_Monitor_Data_File :CheckingFunction,iFile
    {
        #region ColumnHeaders

        string[] columnheader = new string[] { "_id", "_type", "lat", "long", "date", "so4", "no3r", "nh4", "ocb", "ec", "crustal", "salt", "don", "h2o_aim", "oc", "no3", "so4_3s", "crustal_alt", "frm_mass", "measured_fm", "rcfm", "al", "ca", "fe", "ti", "si", "epa_flags", "user_flags" };
        int iID = -1, iType = -1, iLat = -1, iLong = -1, iDate = -1, iSO4 = -1, iNO3R = -1, iNH4 = -1, iOCB = -1, iEC = -1, iCrustal = -1, iSalt = -1, iDON = -1, iH2O_AIM = -1, iOC = -1, iNO3 = -1, iSO43S = -1, iCrustalALT = -1, iFRMMAS = -1, iMeasuredFM = -1, iRCFM = -1, iAL = -1, iCA = -1, iFE = -1, iTI = -1, iSI = -1, iEPAFlags = -1, iUserFlags = -1;
        string[] dataheader;
        #endregion
        Dictionary<string, int> dicID = new Dictionary<string, int>();

        public void GetHeader(string data)
        {
            string[] strArray = data.Split(',');
            dataheader = new string[strArray.Length];
            strArray.CopyTo(dataheader, 0);
        }
        public string checkColumnHeader(string header)
        {
            string errorMessage = "";
            string[] temp = header.Replace("\"", "").ToLower().Split(',');
            for (int i = 0; i < temp.Length; i++)
            {
                switch (temp[i].Trim())
                {
                    case "_id": iID = i; break;
                    case "_type": iType = i; break;
                    case "lat": iLat = i; break;
                    case "long": iLong = i; break;
                    case "date": iDate = i; break;
                    case "so4": iSO4 = i; break;
                    case "no3r": iNO3R = i; break;
                    case "nh4": iNH4 = i; break;
                    case "ocb": iOCB = i; break;
                    case "ec": iEC = i; break;
                    case "crustal": iCrustal = i; break;
                    case "salt": iSalt = i; break;
                    case "don": iDON = i; break;
                    case "h2o_aim": iH2O_AIM = i; break;
                    case "oc": iOC = i; break;
                    case "no3": iNO3 = i; break;
                    case "so4_3s": iSO43S = i; break;
                    case "crustal_alt": iCrustalALT = i; break;
                    case "frm_mass": iFRMMAS = i; break;
                    case "measured_fm": iMeasuredFM = i; break;
                    case "rcfm": iRCFM = i; break;
                    case "al": iAL = i; break;
                    case "ca": iCA = i; break;
                    case "fe": iFE = i; break;
                    case "ti": iTI = i; break;
                    case "si": iSI = i; break;
                    case "epa_flag": iEPAFlags = i; break;
                    case "user_flag": iUserFlags = i; break;
                    //default:
                    //    errorMessage += "Invalid Column " + temp[i] + "\r\n ";
                    //    break;
                }
            }
            if (iID < 0 || iType < 0 || iLat < 0 || iLong < 0 || iDate < 0 || iSO4 < 0 || iNO3R < 0 || iNH4 < 0 || iOCB < 0 || iEC < 0 || iCrustal < 0 || iSalt < 0 || iDON < 0 || iH2O_AIM < 0 || iOC < 0 || iNO3 < 0 || iSO43S < 0 || iCrustal < 0 || iFRMMAS < 0 || iMeasuredFM < 0 || iRCFM < 0 || iAL < 0 || iCA < 0 || iFE < 0 || iTI < 0 || iSI < 0 || iEPAFlags < 0 || iUserFlags < 0)
            {
                errorMessage += "Missing Column \r\n ";
            }
            return errorMessage;
        }
        public string checkData(string data)
        {
            string errorMessage = "";
            string[] strLineArray = data.Split(',');
            double d = 0;
            DateTime date = DateTime.Now;

            if (!double.TryParse(strLineArray[iLat], out d))
            {
                errorMessage += ",LAT";
            }
            if (!double.TryParse(strLineArray[iLong], out d))
            {
                errorMessage += ",LONG";
            }
            if (strLineArray[iDate].Trim().Length < 6)//|| !DateTime.TryParse(strLineArray[iDate], out date))
            {
                errorMessage += ",Date";
            }

            List<int> lsterrorid = new List<int>();

            int[] iDoubleData = new int[] { iSO4, iNO3R, iNH4,  iEC, iCrustal, iSalt, iDON,  iOC, iNO3};
            //int[] iDoubleData = new int[] { iSO4, iNO3R, iNH4, iEC, iCrustal, iSalt, iDON, iH2O_AIM, iOC, iNO3, iSO43S, iCrustalALT, iFRMMAS, iMeasuredFM, iRCFM, iAL, iCA, iFE, iTI, iSI };
            lsterrorid = CheckDoubleDataPositive(strLineArray, iDoubleData);

            iDoubleData = new int[] { iOCB };
            lsterrorid.AddRange(CheckDoubleData(strLineArray, iDoubleData));

            int[] iIntData = new int[] { iEPAFlags, iUserFlags };
            lsterrorid.AddRange(CheckIntData(strLineArray, iIntData));
            if (lsterrorid.Count != 0)
            {
                foreach (int id in lsterrorid)
                {
                    errorMessage += "," + dataheader[id];
                }
            }



            //if (!double.TryParse(strLineArray[iPM25], out d) || Convert.ToDouble(strLineArray[iPM25]) < 0)
            //{
            //    errorMessage += ",PM25";
            ////}
            //if (!double.TryParse(strLineArray[iEPAFlags], out d))
            //{
            //    errorMessage += ",EPA_FLAG";
            //}
            return errorMessage;
        }

        public string checkRepeatedLines(string dataline, int iRow, out int i)
        {
            i = -1;
            string[] strLineArray = dataline.Split(',');
            string errorMessage = "";
            if (dicID.ContainsKey(strLineArray[iID] + strLineArray[iDate]))
            {
                i = dicID[strLineArray[iID] + strLineArray[iDate]];
                errorMessage = "Repeated Lines";
            }
            else
            {
                dicID.Add(strLineArray[iID] + strLineArray[iDate], iRow);
            }


            return errorMessage;
        }

        public void Clear()
        {
            dicID.Clear();
        }
    }

    class Ozone_Monitor_Data_File :CheckingFunction, iFile
    {
        #region ColumnHeaders

        string[] columnheader = new string[] { "_id", "_type", "lat", "long", "poc", "dvyear", "o3", "_state_name","_county_name" };
        int iID = -1, iType = -1, iLat = -1, iLong = -1, iPOC = -1, iDVYEAR = -1, iO3 = -1, iStateName = -1, iCountyName = -1;
        string[] dataheader;
        #endregion
        Dictionary<string, int> dicID = new Dictionary<string, int>();
        public string checkRepeatedLines(string dataline, int iRow, out int i)
        {
            i = -1;
            string[] strLineArray = dataline.Split(',');
            string errorMessage = "";
            if (dicID.ContainsKey(strLineArray[iID] + strLineArray[iDVYEAR]))
            {
                i = dicID[strLineArray[iID] + strLineArray[iDVYEAR]];
                errorMessage = "Repeated Lines";
            }
            else
            {
                dicID.Add(strLineArray[iID] + strLineArray[iDVYEAR], iRow);
            }


            return errorMessage;
        }
        public void GetHeader(string data)
        {
            string[] strArray = data.Split(',');
            dataheader = new string[strArray.Length];
            strArray.CopyTo(dataheader, 0);
        }
        public string checkColumnHeader(string header)
        {
            string errorMessage = "";
            string[] temp = header.Replace("\"", "").ToLower().Split(',');
            for (int i = 0; i < temp.Length; i++)
            {
                switch (temp[i].Trim())
                {
                    case "_id": iID = i; break;
                    case "_type": iType = i; break;
                    case "lat": iLat = i; break;
                    case "long": iLong = i; break;
                    case "poc": iPOC = i; break;
                    case "dvyear": iDVYEAR = i; break;
                    case "o3": iO3 = i; break;
                    case "_state_name": iStateName = i; break;
                    case "_county_name": iCountyName = i; break;
                    //default:
                    //    errorMessage += "Invalid Column " + temp[i] + "\r\n ";
                    //    break;
                }
            }
            if (iID < 0 || iType < 0 || iLat < 0 || iLong < 0 || iPOC < 0 || iDVYEAR < 0 || iO3 < 0 || iStateName < 0 || iCountyName < 0)
            {
                errorMessage += "Missing Column \r\n ";
            }
            return errorMessage;
        }
        public string checkData(string data)
        {
            string errorMessage = "";
            string[] strLineArray = data.Split(',');
            double d = 0;
            DateTime date = DateTime.Now;

            if (!double.TryParse(strLineArray[iLat], out d))
            {
                errorMessage += ",LAT";
            }
            if (!double.TryParse(strLineArray[iLong], out d))
            {
                errorMessage += ",LONG";
            }
            if (strLineArray[iDVYEAR].Trim().Length < 4)// !DateTime.TryParse(strLineArray[iDVYEAR], out date))
            {
                errorMessage += ",Date";
            }
            //if (!double.TryParse(strLineArray[iO3], out d) || d < 0)
            //{
            //    errorMessage += ",O3";
            //}
            //if (!double.TryParse(strLineArray[iPOC], out d) || d < 0)
            //{
            //    errorMessage += ",POC";
            //}
            List<int> lsterrorid = new List<int>();
            int[] iDoubleData = new int[] { iPOC, iO3 };
            lsterrorid = CheckDoubleDataPositive(strLineArray, iDoubleData);
            if (lsterrorid.Count != 0)
            {
                foreach (int id in lsterrorid)
                {
                    errorMessage += "," + dataheader[id];
                }
            }
            return errorMessage;
        }

        public void Clear()
        {
            dicID.Clear();
        }
    }

    class IMPROVE_Monitor_Data_Old_Algorithm :CheckingFunction, iFile
    {
        #region ColumnHeaders

        string[] columnheader = new string[] { "_id", "_type", "lat", "long", "date","frh", "pm25", "crustal", "amm_no3", "omc", "ec", "pm10", "cm", "amm_so4", "e_amm_so4", "e_amm_no3", "e_omc", "e_ec", "e_crustal", "e_cm", "tbext", "dv", "good_year", "group", "possible", "ndays", "complete_quarter", "sf", "so4f" };
        int iID = -1, iType = -1, iLat = -1, iLong = -1, iDate = -1,iFRH=-1, iPM25 = -1, iCrustal = -1, iAMM_NO3 = -1, iOMC = -1, iEC = -1, iPM10 = -1, iCM = -1, iAMM_SO4 = -1, iE_AMM_SO4 = -1, iE_AMM_NO3 = -1, iE_OMC = -1, iE_EC = -1, iE_Crustal = -1, iE_CM = -1, iTBEXT = -1, iDV = -1, iGOOD_YEAR = -1, iGROUP = -1, iPOSSIBLE = -1, iNDAYS = -1, iComplete = -1, iSF = -1, iSO4F = -1;
        string[] dataheader;
        #endregion
        Dictionary<string, int> dicID = new Dictionary<string, int>();

        public string checkRepeatedLines(string dataline, int iRow, out int i)
        {
            i = -1;
            string[] strLineArray = dataline.Split(',');
            string errorMessage = "";
            if (dicID.ContainsKey(strLineArray[iID] + strLineArray[iDate]))
            {
                i = dicID[strLineArray[iID] + strLineArray[iDate]];
                errorMessage = "Repeated Lines";
            }
            else
            {
                dicID.Add(strLineArray[iID] + strLineArray[iDate], iRow);
            }


            return errorMessage;
        }

        public void GetHeader(string data)
        {
            string[] strArray = data.Split(',');
            dataheader = new string[strArray.Length];
            strArray.CopyTo(dataheader, 0);
        }
        public string checkColumnHeader(string header)
        {
            string errorMessage = "";
            string[] temp = header.Replace("\"", "").ToLower().Split(',');
            for (int i = 0; i < temp.Length; i++)
            {
                switch (temp[i].Trim())
                {
                    case "_id": iID = i; break;
                    case "_type": iType = i; break;
                    case "lat": iLat = i; break;
                    case "long": iLong = i; break;
                    case "date": iDate = i; break;
                    case "frh": iFRH = i; break;
                    case "pm25": iPM25 = i; break;
                    case "crustal": iCrustal = i; break;
                    case "amm_no3": iAMM_NO3 = i; break;
                    case "omc": iOMC = i; break;
                    case "ec": iEC = i; break;
                    case "pm10": iPM10 = i; break;
                    case "cm": iCM = i; break;
                    case "amm_so4": iAMM_SO4 = i; break;
                    case "e_amm_so4": iE_AMM_SO4 = i; break;
                    case "e_amm_no3": iE_AMM_NO3 = i; break;
                    case "e_omc": iE_OMC = i; break;
                    case "e_ec": iE_EC = i; break;
                    case "e_crustal": iE_Crustal = i; break;
                    case "e_cm": iE_CM = i; break;
                    case "tbext": iTBEXT = i; break;
                    case "dv": iDV = i; break;
                    case "good_year": iGOOD_YEAR = i; break;
                    case "group": iGROUP = i; break;
                    case "possible_ndays": iPOSSIBLE = i; break;
                    case "ndays": iNDAYS = i; break;
                    case "complete_quarter": iComplete = i; break;
                    case "sf": iSF = i; break;
                    case "so4f": iSO4F = i; break;
                    //default:
                    //    errorMessage += "Invalid Column " + temp[i] + "\r\n ";
                    //    break;
                }
            }
            if (iID < 0 || iType < 0 || iLat < 0 || iLong < 0 || iDate < 0 || iFRH < 0 || iPM25 < 0 || iCrustal < 0 || iAMM_NO3 < 0 || iOMC < 0 || iEC < 0 || iPM10 < 0 || iCM < 0 || iAMM_SO4 < 0 || iE_AMM_SO4 < 0 || iE_AMM_NO3 < 0 || iE_OMC < 0 || iE_EC < 0 || iE_Crustal < 0 || iE_CM < 0 || iTBEXT < 0 || iDV < 0 || iGOOD_YEAR < 0 || iGROUP < 0 || iPOSSIBLE < 0 || iNDAYS < 0 || iComplete < 0 || iSF < 0 || iSO4F < 0)
            {
                errorMessage += "Missing Column \r\n ";
            }
            return errorMessage;
        }
        public string checkData(string data)
        {
            string errorMessage = "";
            string[] strLineArray = data.Split(',');
            double d = 0;
            DateTime date = DateTime.Now;

            if (!double.TryParse(strLineArray[iLat], out d))
            {
                errorMessage += ",LAT";
            }
            if (!double.TryParse(strLineArray[iLong], out d))
            {
                errorMessage += ",LONG";
            }
            if (strLineArray[iDate].Trim().Length < 6 )//|| !DateTime.TryParse(strLineArray[iDate], out date))
            {
                errorMessage += ",Date";
            }
            //if (!double.TryParse(strLineArray[iPM25], out d) || Convert.ToDouble(strLineArray[iPM25]) < 0)
            //{
            //    errorMessage += ",PM25";
            ////}
            //if (!double.TryParse(strLineArray[iEPAFlags], out d))
            //{
            //    errorMessage += ",EPA_FLAG";
            //}
            List<int> lsterrorid = new List<int>();
            int[] iDoubleData = new int[] { iFRH, iPM25, iCrustal, iAMM_NO3, iOMC, iEC, iPM10, iCM, iAMM_SO4, iE_AMM_SO4, iE_AMM_NO3, iE_OMC, iE_EC, iE_Crustal, iE_CM, iTBEXT };
            lsterrorid = CheckDoubleDataPositive(strLineArray, iDoubleData);

            int[] iIntData = new int[] { iGOOD_YEAR, iGROUP, iPOSSIBLE, iComplete, iNDAYS };
            lsterrorid.AddRange(CheckIntData(strLineArray, iIntData));
            if (lsterrorid.Count != 0)
            {
                foreach (int id in lsterrorid)
                {
                    errorMessage += "," + dataheader[id];
                }
            }

            return errorMessage;
        }

        public void Clear()
        {
            dicID.Clear();
        }
    }

    class IMPROVE_Monitor_Data_New_Algorithm : CheckingFunction, iFile
    {
        #region ColumnHeaders

        string[] columnheader = new string[] { "_id", "_type", "lat", "long", "date", "frh", "fsrh", "flrh", "fssrh", "ss_rayleigh", "sea_salt", "pm25", "crustal", "amm_no3", "omc", "ec", "pm10", "cm", "amm_so4", "large_omc", "small_omc", "large_amm_so4", "small_amm_so4", "large_amm_no3", "small_amm_no3", "e_amm_so4", "e_amm_no3", "e_omc", "e_ec","e_crustal","e_cm","e_sea_salt","tbext","dv","good_year","group","possible","ndays","complete_quarter","sf","so4f"};
        int iID = -1, iType = -1, iLat = -1, iLong = -1, iDate = -1, iFRH = -1, iFSRH = -1, iFLRH = -1, iFSSRH = -1, iSS_RAYLEIGH = -1, iSea_Salt = -1, iPM25 = -1, iCrustal = -1, iAMM_NO3 = -1, iOMC = -1, iEC = -1, iPM10 = -1, iCM = -1, iAMM_SO4 = -1, iLarge_OMC = -1, iSmall_OMC = -1, iLarge_AMM_SO4 = -1, iSmall_AMM_SO4 = -1, iLarge_AMM_NO3 = -1, iSmall_AMM_NO3 = -1, iE_AMM_SO4 = -1, iE_AMM_NO3 = -1, iE_OMC = -1, iE_EC = -1, iE_Crustal = -1, iE_CM = -1, iE_Sea_Salt = -1, iTBEXT = -1, iDV = -1, iGood_Year = -1, iPOSSIBLE = -1, iGROUP = -1, iNDAYS = -1, iComplete = -1, iSF = -1, iSO4F = -1;
        string[] dataheader;
        #endregion
        Dictionary<string, int> dicID = new Dictionary<string, int>();

        public string checkRepeatedLines(string dataline, int iRow, out int i)
        {
            i = -1;
            string[] strLineArray = dataline.Split(',');
            string errorMessage = "";
            if (dicID.ContainsKey(strLineArray[iID] + strLineArray[iDate]))
            {
                i = dicID[strLineArray[iID] + strLineArray[iDate]];
                errorMessage = "Repeated Lines";
            }
            else
            {
                dicID.Add(strLineArray[iID] + strLineArray[iDate], iRow);
            }


            return errorMessage;
        }

        public void GetHeader(string data)
        {
            string[] strArray = data.Split(',');
            dataheader = new string[strArray.Length];
            strArray.CopyTo(dataheader, 0);
        }
        public string checkColumnHeader(string header)
        {
            string errorMessage = "";
            string[] temp = header.Replace("\"", "").ToLower().Split(',');
            for (int i = 0; i < temp.Length; i++)
            {
                switch (temp[i].Trim())
                {
                    case "_id": iID = i; break;
                    case "_type": iType = i; break;
                    case "lat": iLat = i; break;
                    case "long": iLong = i; break;
                    case "date": iDate = i; break;
                    case "frh": iFRH = i; break;
                    case "fsrh": iFSRH = i; break;
                    case "flrh": iFLRH = i; break;
                    case "fssrh": iFSSRH = i; break;
                    case "ss_rayleigh": iSS_RAYLEIGH = i; break;
                    case "sea_salt": iSea_Salt = i; break;
                    case "pm25": iPM25 = i; break;
                    case "crustal": iCrustal = i; break;
                    case "amm_no3": iAMM_NO3 = i; break;
                    case "omc": iOMC = i; break;
                    case "ec": iEC = i; break;
                    case "pm10": iPM10 = i; break;
                    case "cm": iCM = i; break;
                    case "amm_so4": iAMM_SO4 = i; break;
                    case "large_omc": iLarge_OMC=i; break;
                    case "small_omc": iSmall_OMC = i; break;
                    case "large_amm_no3": iLarge_AMM_NO3 = i; break;
                    case "small_amm_no3": iSmall_AMM_NO3 = i; break;
                    case "large_amm_so4": iLarge_AMM_SO4 = i; break;
                    case "small_amm_so4": iSmall_AMM_SO4 = i; break;
                    case "e_amm_so4": iE_AMM_SO4 = i; break;
                    case "e_amm_no3": iE_AMM_NO3 = i; break;
                    case "e_omc": iE_OMC = i; break;
                    case "e_ec": iE_EC = i; break;
                    case "e_crustal": iE_Crustal = i; break;
                    case "e_cm": iE_CM = i; break;
                    case "e_sea_salt": iE_Sea_Salt = i; break;
                    case "tbext": iTBEXT = i; break;
                    case "dv": iDV = i; break;
                    case "good_year": iGood_Year = i; break;
                    case "group": iGROUP = i; break;
                    case "possible_ndays": iPOSSIBLE = i; break;
                    case "ndays": iNDAYS = i; break;
                    case "complete_quarter": iComplete = i; break;
                    case "sf": iSF = i; break;
                    case "so4f": iSO4F = i; break;
                    //default:
                    //    errorMessage += "Invalid Column " + temp[i] + "\r\n ";
                    //    break;
                }
            }
            if (iID < 0 || iType < 0 || iLat < 0 || iLong < 0 || iDate < 0 || iFRH < 0 || iFSRH < 0 || iFLRH < 0 || iFSSRH < 0 || iEC < 0 || iSS_RAYLEIGH < 0 || iSea_Salt < 0 || iPM25 < 0 || iCrustal < 0 || iAMM_NO3 < 0 || iOMC < 0 || iEC < 0 || iPM10 < 0 || iCM < 0 || iAMM_SO4 < 0 || iLarge_OMC < 0 || iSmall_OMC < 0 || iLarge_AMM_NO3 < 0 || iSmall_AMM_NO3 < 0 || iLarge_AMM_SO4 < 0 || iSmall_AMM_SO4 < 0 || iE_AMM_SO4 < 0 || iE_AMM_NO3 < 0 || iE_OMC < 0 || iE_EC < 0 || iE_Crustal < 0 || iE_CM < 0 || iE_Sea_Salt < 0 || iTBEXT < 0 || iDV < 0 || iGood_Year < 0 || iGROUP < 0 || iPOSSIBLE < 0 || iNDAYS < 0 || iComplete < 0 || iSF < 0 || iSO4F < 0)
            {
                errorMessage += "Missing Column \r\n ";
            }
            return errorMessage;
        }
        public string checkData(string data)
        {
            string errorMessage = "";
            string[] strLineArray = data.Split(',');
            double d = 0;
            DateTime date = DateTime.Now;

            if (!double.TryParse(strLineArray[iLat], out d))
            {
                errorMessage += ",LAT";
            }
            if (!double.TryParse(strLineArray[iLong], out d))
            {
                errorMessage += ",LONG";
            }
            if (strLineArray[iDate].Trim().Length < 6)// || !DateTime.TryParse(strLineArray[iDate], out date))
            {
                errorMessage += ",Date";
            }
            //if (!double.TryParse(strLineArray[iPM25], out d) || Convert.ToDouble(strLineArray[iPM25]) < 0)
            //{
            //    errorMessage += ",PM25";
            ////}
            //if (!double.TryParse(strLineArray[iEPAFlags], out d))
            //{
            //    errorMessage += ",EPA_FLAG";
            //}
            List<int> lsterrorid = new List<int>();
            int[] iDoubleData = new int[] { iFRH, iFSRH, iFLRH, iFSSRH, iSS_RAYLEIGH, iSea_Salt, iPM25, iCrustal, iAMM_NO3, iOMC, iEC, iPM10, iCM, iAMM_SO4, iLarge_OMC, iSmall_OMC, iLarge_AMM_SO4, iSmall_AMM_SO4, iLarge_AMM_NO3, iSmall_AMM_NO3, iE_AMM_SO4, iE_AMM_NO3, iE_OMC, iE_EC, iE_Crustal, iE_CM, iE_Sea_Salt, iTBEXT };
            lsterrorid = CheckDoubleDataPositive(strLineArray, iDoubleData);
            int[] iIntData = new int[] { iGood_Year, iGROUP, iPOSSIBLE, iComplete, iNDAYS };
            lsterrorid.AddRange(CheckIntData(strLineArray, iIntData));
            if (lsterrorid.Count != 0)
            {
                foreach (int id in lsterrorid)
                {
                    errorMessage += "," + dataheader[id];
                }
            }
            return errorMessage;
        }

        public void Clear()
        {
            dicID.Clear();
        }
    }
    
    public class errorRecord
    {
        public int iRow;
        public DataRow drInfo;
        public string errorMsg;
    }

    public class ClassHelper
    {
        /**/
        /// <summary>
        /// 根据类的类型型创建类实例。
        /// </summary>
        /// <param name="t">将要创建的类型。</param>
        /// <returns>返回创建的类实例。</returns>
        public static object CreateInstance(Type t)
        {
            return Activator.CreateInstance(t);
        }

        /**/
        /// <summary>
        /// 根据类的名称，属性列表创建型实例。
        /// </summary>
        /// <param name="className">将要创建的类的名称。</param>
        /// <param name="lcpi">将要创建的类的属性列表。</param>
        /// <returns>返回创建的类实例</returns>
        public static object CreateInstance(string className, List<CustPropertyInfo> lcpi)
        {
            Type t = BuildType(className);
            t = AddProperty(t, lcpi);
            return Activator.CreateInstance(t);
        }

        /**/
        /// <summary>
        /// 根据属性列表创建类的实例，默认类名为DefaultClass，由于生成的类不是强类型，所以类名可以忽略。
        /// </summary>
        /// <param name="lcpi">将要创建的类的属性列表</param>
        /// <returns>返回创建的类的实例。</returns>
        public static object CreateInstance(List<CustPropertyInfo> lcpi)
        {
            return CreateInstance("DefaultClass", lcpi);
        }

        /**/
        /// <summary>
        /// 根据类的实例设置类的属性。
        /// </summary>
        /// <param name="classInstance">将要设置的类的实例。</param>
        /// <param name="propertyName">将要设置属性名。</param>
        /// <param name="propertSetValue">将要设置属性值。</param>
        public static void SetPropertyValue(object classInstance, string propertyName, object propertSetValue)
        {
            classInstance.GetType().InvokeMember(propertyName, BindingFlags.SetProperty,
                                          null, classInstance, new object[] { Convert.ChangeType(propertSetValue, propertSetValue.GetType()) });
        }

        /**/
        /// <summary>
        /// 根据类的实例获取类的属性。
        /// </summary>
        /// <param name="classInstance">将要获取的类的实例</param>
        /// <param name="propertyName">将要设置的属性名。</param>
        /// <returns>返回获取的类的属性。</returns>
        public static object GetPropertyValue(object classInstance, string propertyName)
        {
            return classInstance.GetType().InvokeMember(propertyName, BindingFlags.GetProperty,
                                                          null, classInstance, new object[] { });
        }

        /**/
        /// <summary>
        /// 创建一个没有成员的类型的实例，类名为"DefaultClass"。
        /// </summary>
        /// <returns>返回创建的类型的实例。</returns>
        public static Type BuildType()
        {
            return BuildType("DefaultClass");
        }

        /**/
        /// <summary>
        /// 根据类名创建一个没有成员的类型的实例。
        /// </summary>
        /// <param name="className">将要创建的类型的实例的类名。</param>
        /// <returns>返回创建的类型的实例。</returns>
        public static Type BuildType(string className)
        {

            AppDomain myDomain = System.Threading.Thread.GetDomain();
            AssemblyName myAsmName = new AssemblyName();
            myAsmName.Name = "MyDynamicAssembly";

            //创建一个永久程序集，设置为AssemblyBuilderAccess.RunAndSave。
            AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(myAsmName,
                                                            AssemblyBuilderAccess.RunAndSave);

            //创建一个永久单模程序块。
            ModuleBuilder myModBuilder =
                myAsmBuilder.DefineDynamicModule(myAsmName.Name, myAsmName.Name + ".dll");
            //创建TypeBuilder。
            TypeBuilder myTypeBuilder = myModBuilder.DefineType(className,
                                                            TypeAttributes.Public);

            //创建类型。
            Type retval = myTypeBuilder.CreateType();

            //保存程序集，以便可以被Ildasm.exe解析，或被测试程序引用。
            myAsmBuilder.Save(myAsmName.Name + ".dll");
            return retval;
        }

        /**/
        /// <summary>
        /// 添加属性到类型的实例，注意：该操作会将其它成员清除掉，其功能有待完善。
        /// </summary>
        /// <param name="classType">指定类型的实例。</param>
        /// <param name="lcpi">表示属性的一个列表。</param>
        /// <returns>返回处理过的类型的实例。</returns>
        public static Type AddProperty(Type classType, List<CustPropertyInfo> lcpi)
        {
            //合并先前的属性，以便一起在下一步进行处理。
            MergeProperty(classType, lcpi);
            //把属性加入到Type。
            return AddPropertyToType(classType, lcpi);
        }

        /**/
        /// <summary>
        /// 添加属性到类型的实例，注意：该操作会将其它成员清除掉，其功能有待完善。
        /// </summary>
        /// <param name="classType">指定类型的实例。</param>
        /// <param name="cpi">表示一个属性。</param>
        /// <returns>返回处理过的类型的实例。</returns>
        public static Type AddProperty(Type classType, CustPropertyInfo cpi)
        {
            List<CustPropertyInfo> lcpi = new List<CustPropertyInfo>();
            lcpi.Add(cpi);
            //合并先前的属性，以便一起在下一步进行处理。
            MergeProperty(classType, lcpi);
            //把属性加入到Type。
            return AddPropertyToType(classType, lcpi);
        }

        /**/
        /// <summary>
        /// 从类型的实例中移除属性，注意：该操作会将其它成员清除掉，其功能有待完善。
        /// </summary>
        /// <param name="classType">指定类型的实例。</param>
        /// <param name="cpi">要移除的属性。</param>
        /// <returns>返回处理过的类型的实例。</returns>
        public static Type DeleteProperty(Type classType, string propertyName)
        {
            List<string> ls = new List<string>();
            ls.Add(propertyName);

            //合并先前的属性，以便一起在下一步进行处理。
            List<CustPropertyInfo> lcpi = SeparateProperty(classType, ls);
            //把属性加入到Type。
            return AddPropertyToType(classType, lcpi);
        }

        /**/
        /// <summary>
        /// 从类型的实例中移除属性，注意：该操作会将其它成员清除掉，其功能有待完善。
        /// </summary>
        /// <param name="classType">指定类型的实例。</param>
        /// <param name="lcpi">要移除的属性列表。</param>
        /// <returns>返回处理过的类型的实例。</returns>
        public static Type DeleteProperty(Type classType, List<string> ls)
        {
            //合并先前的属性，以便一起在下一步进行处理。
            List<CustPropertyInfo> lcpi = SeparateProperty(classType, ls);
            //把属性加入到Type。
            return AddPropertyToType(classType, lcpi);
        }

        /**/
        /// <summary>
        /// 把类型的实例t和lcpi参数里的属性进行合并。
        /// </summary>
        /// <param name="t">实例t</param>
        /// <param name="lcpi">里面包含属性列表的信息。</param>
        private static void MergeProperty(Type t, List<CustPropertyInfo> lcpi)
        {
            CustPropertyInfo cpi;
            foreach (PropertyInfo pi in t.GetProperties())
            {
                cpi = new CustPropertyInfo(pi.PropertyType.FullName, pi.Name);
                lcpi.Add(cpi);
            }
        }

        /**/
        /// <summary>
        /// 从类型的实例t的属性移除属性列表lcpi，返回的新属性列表在lcpi中。
        /// </summary>
        /// <param name="t">类型的实例t。</param>
        /// <param name="lcpi">要移除的属性列表。</param>
        private static List<CustPropertyInfo> SeparateProperty(Type t, List<string> ls)
        {
            List<CustPropertyInfo> ret = new List<CustPropertyInfo>();
            CustPropertyInfo cpi;
            foreach (PropertyInfo pi in t.GetProperties())
            {
                foreach (string s in ls)
                {
                    if (pi.Name != s)
                    {
                        cpi = new CustPropertyInfo(pi.PropertyType.FullName, pi.Name);
                        ret.Add(cpi);
                    }
                }
            }

            return ret;
        }

        /**/
        /// <summary>
        /// 把lcpi参数里的属性加入到myTypeBuilder中。注意：该操作会将其它成员清除掉，其功能有待完善。
        /// </summary>
        /// <param name="myTypeBuilder">类型构造器的实例。</param>
        /// <param name="lcpi">里面包含属性列表的信息。</param>
        private static void AddPropertyToTypeBuilder(TypeBuilder myTypeBuilder, List<CustPropertyInfo> lcpi)
        {
            FieldBuilder customerNameBldr;
            PropertyBuilder custNamePropBldr;
            MethodBuilder custNameGetPropMthdBldr;
            MethodBuilder custNameSetPropMthdBldr;
            MethodAttributes getSetAttr;
            ILGenerator custNameGetIL;
            ILGenerator custNameSetIL;

            // 属性Set和Get方法要一个专门的属性。这里设置为Public。
            getSetAttr =
                MethodAttributes.Public | MethodAttributes.SpecialName |
                    MethodAttributes.HideBySig;

            // 添加属性到myTypeBuilder。
            foreach (CustPropertyInfo cpi in lcpi)
            {
                //定义字段。
                customerNameBldr = myTypeBuilder.DefineField(cpi.FieldName,
                                                                 Type.GetType(cpi.Type),
                                                                 FieldAttributes.Private);

                //定义属性。
                //最后一个参数为null，因为属性没有参数。
                custNamePropBldr = myTypeBuilder.DefineProperty(cpi.PropertyName,
                                                                 System.Reflection.PropertyAttributes.HasDefault,
                                                                 Type.GetType(cpi.Type),
                                                                 null);


                //定义Get方法。
                custNameGetPropMthdBldr =
                    myTypeBuilder.DefineMethod(cpi.GetPropertyMethodName,
                                               getSetAttr,
                                               Type.GetType(cpi.Type),
                                               Type.EmptyTypes);

                custNameGetIL = custNameGetPropMthdBldr.GetILGenerator();

                custNameGetIL.Emit(OpCodes.Ldarg_0);
                custNameGetIL.Emit(OpCodes.Ldfld, customerNameBldr);
                custNameGetIL.Emit(OpCodes.Ret);

                //定义Set方法。
                custNameSetPropMthdBldr =
                    myTypeBuilder.DefineMethod(cpi.SetPropertyMethodName,
                                               getSetAttr,
                                               null,
                                               new Type[] { Type.GetType(cpi.Type) });

                custNameSetIL = custNameSetPropMthdBldr.GetILGenerator();

                custNameSetIL.Emit(OpCodes.Ldarg_0);
                custNameSetIL.Emit(OpCodes.Ldarg_1);
                custNameSetIL.Emit(OpCodes.Stfld, customerNameBldr);
                custNameSetIL.Emit(OpCodes.Ret);

                //把创建的两个方法(Get,Set)加入到PropertyBuilder中。
                custNamePropBldr.SetGetMethod(custNameGetPropMthdBldr);
                custNamePropBldr.SetSetMethod(custNameSetPropMthdBldr);
            }
        }

        /**/
        /// <summary>
        /// 把属性加入到类型的实例。
        /// </summary>
        /// <param name="classType">类型的实例。</param>
        /// <param name="lcpi">要加入的属性列表。</param>
        /// <returns>返回处理过的类型的实例。</returns>
        public static Type AddPropertyToType(Type classType, List<CustPropertyInfo> lcpi)
        {
            AppDomain myDomain = System.Threading.Thread.GetDomain();
            AssemblyName myAsmName = new AssemblyName();
            myAsmName.Name = "MyDynamicAssembly";

            //创建一个永久程序集，设置为AssemblyBuilderAccess.RunAndSave。
            AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(myAsmName,
                                                            AssemblyBuilderAccess.RunAndSave);

            //创建一个永久单模程序块。
            ModuleBuilder myModBuilder =
                myAsmBuilder.DefineDynamicModule(myAsmName.Name, myAsmName.Name + ".dll");
            //创建TypeBuilder。
            TypeBuilder myTypeBuilder = myModBuilder.DefineType(classType.FullName,
                                                            TypeAttributes.Public);

            //把lcpi中定义的属性加入到TypeBuilder。将清空其它的成员。其功能有待扩展，使其不影响其它成员。
            AddPropertyToTypeBuilder(myTypeBuilder, lcpi);

            //创建类型。
            Type retval = myTypeBuilder.CreateType();

            //保存程序集，以便可以被Ildasm.exe解析，或被测试程序引用。
            myAsmBuilder.Save(myAsmName.Name + ".dll");
            return retval;
        }

        /**/
        /// <summary>
        /// 自定义的属性信息类型。
        /// </summary>
        public class CustPropertyInfo
        {
            private string propertyName;
            private string type;

            /**/
            /// <summary>
            /// 空构造。
            /// </summary>
            public CustPropertyInfo() { }

            /**/
            /// <summary>
            /// 根据属性类型名称，属性名称构造实例。
            /// </summary>
            /// <param name="type">属性类型名称。</param>
            /// <param name="propertyName">属性名称。</param>
            public CustPropertyInfo(string type, string propertyName)
            {
                this.type = type;
                this.propertyName = propertyName;
            }

            /**/
            /// <summary>
            /// 获取或设置属性类型名称。
            /// </summary>
            public string Type
            {
                get { return type; }
                set { type = value; }
            }

            /**/
            /// <summary>
            /// 获取或设置属性名称。
            /// </summary>
            public string PropertyName
            {
                get { return propertyName; }
                set { propertyName = value; }
            }

            /**/
            /// <summary>
            /// 获取属性字段名称。
            /// </summary>
            public string FieldName
            {
                get { return propertyName.Substring(0, 1).ToLower() + propertyName.Substring(1); }
            }

            /**/
            /// <summary>
            /// 获取属性在IL中的Set方法名。
            /// </summary>
            public string SetPropertyMethodName
            {
                get { return "set_" + PropertyName; }
            }

            /**/
            /// <summary>
            ///  获取属性在IL中的Get方法名。
            /// </summary>
            public string GetPropertyMethodName
            {
                get { return "get_" + PropertyName; }
            }
        }
    }
}
