public int[] content;                  // number in each cat, high/med/low

            public static MaterialsFound Find(string fdname, List <MaterialsFound> list)
            {
                MaterialsFound mat = list.Find(x => x.matnamefd2.Equals(fdname, StringComparison.InvariantCultureIgnoreCase));

                if (mat == null)
                {
                    mat                   = new MaterialsFound();
                    mat.matnamefd2        = fdname;
                    mat.friendlyname      = MaterialCommodityData.GetByFDName(fdname)?.Name ?? fdname;
                    mat.prospectedamounts = new List <double>();
                    mat.content           = new int[3];
                    list.Add(mat);
                }

                return(mat);
            }
        private void buttonExtExcel_Click(object sender, EventArgs e)
        {
            Forms.ExportForm frm = new Forms.ExportForm();
            frm.Init(new string[] { "All" }, disablestartendtime: true);

            if (frm.ShowDialog(FindForm()) == DialogResult.OK)
            {
                BaseUtils.CSVWriteGrid grd = new BaseUtils.CSVWriteGrid();
                grd.SetCSVDelimiter(frm.Comma);

                var found = ReadHistory(out int prospectorsused, out int collectorsused, out int asteroidscracked, out int prospected, out int[] content);

                grd.GetPreHeader += delegate(int r)
                {
                    if (r == 0)
                    {
                        return new Object[] { "Limpets left ", limpetsleftdisplay, "Prospectors Fired", prospectorsused, "Collectors Deployed", collectorsused }
                    }
                    ;
                    else if (r == 1)
                    {
                        return(new object[0]);
                    }
                    else
                    {
                        return(null);
                    }
                };

                grd.GetSetsPad = delegate(int s, int r)
                {
                    return(r < 2 ? new object[0] : null);
                };

                {
                    grd.GetSetsHeader.Add(delegate(int s, int r)
                    {
                        if (r == 0)
                        {
                            return new object[] { "", "Ref.", "Coll.", "Pros", "Ratio%", "Avg%", "Min%", "Max%", "M.Load", "High Ct", "Med Ct", "Low Ct", "Discv" }
                        }
                        ;
                        else
                        {
                            return(null);
                        }
                    });

                    grd.GetSetsData.Add(delegate(int s, int r)
                    {
                        if (r == 0)
                        {
                            return(new object[] { "", "", "", prospected.ToString("N0"), "", "", "", "", "",
                                                  content[0].ToString("N0"),
                                                  content[1].ToString("N0"),
                                                  content[2].ToString("N0") });
                        }
                        else if (r <= found.Count)
                        {
                            MaterialsFound f = found[r - 1];
                            return(new object[] { f.friendlyname, f.amountrefined, f.amountcollected - f.amountdiscarded,
                                                  f.prospectednoasteroids > 0 ? f.prospectednoasteroids.ToString("N0") : "",
                                                  f.prospectednoasteroids > 0 ? (100.0 * (double)f.prospectednoasteroids / prospected).ToString("N1") : "",
                                                  f.prospectednoasteroids > 0 ? f.prospectedamounts.Average().ToString("N1") : "",
                                                  f.prospectednoasteroids > 0 ? f.prospectedamounts.Min().ToString("N1") : "",
                                                  f.prospectednoasteroids > 0 ? f.prospectedamounts.Max().ToString("N1") : "",
                                                  f.motherloadasteroids > 0 ? f.motherloadasteroids.ToString("N0") : "",
                                                  f.prospectednoasteroids > 0 ? f.content[0].ToString("N0") :"",
                                                  f.prospectednoasteroids > 0 ? f.content[1].ToString("N0") : "",
                                                  f.prospectednoasteroids > 0 ? f.content[2].ToString("N0") : "",
                                                  f.discovered ? "*" : "" });
                        }
                        else
                        {
                            return(null);
                        }
                    });
                }

                var prosmat = found.Where(x => x.prospectednoasteroids > 0).ToList();

                {
                    grd.GetSetsHeader.Add(delegate(int s, int r)
                    {
                        if (r == 0)
                        {
                            Object[] ret = new object[prosmat.Count + 1];
                            ret[0]       = "CDFb";

                            for (int i = 0; i < prosmat.Count; i++)
                            {
                                ret[i + 1] = prosmat[i].friendlyname;
                            }

                            return(ret);
                        }
                        else
                        {
                            return(null);
                        }
                    });

                    grd.GetSetsData.Add(delegate(int s, int r)
                    {
                        if (r < CFDbMax)
                        {
                            Object[] ret = new object[prosmat.Count + 1];
                            int percent  = r;
                            ret[0]       = percent.ToString("N0") + "%";
                            for (int m = 0; m < prosmat.Count; m++)
                            {
                                if (prosmat[m].prospectednoasteroids > 0)
                                {
                                    ret[m + 1] = ((double)prosmat[m].prospectedamounts.Count(x => x >= percent) / prosmat[m].prospectednoasteroids * 100.0).ToString("N1");
                                }
                                else
                                {
                                    ret[m + 1] = "";
                                }
                            }

                            return(ret);
                        }
                        else
                        {
                            return(null);
                        }
                    });
                }

                {
                    const int precol = 4;

                    grd.GetSetsHeader.Add(delegate(int s, int r)
                    {
                        if (r == 0)
                        {
                            Object[] ret = new object[found.Count + precol];
                            ret[0]       = "Event";
                            ret[1]       = "Time";
                            ret[2]       = "Content";
                            ret[3]       = "Motherload";

                            for (int i = 0; i < prosmat.Count; i++)
                            {
                                ret[i + precol] = prosmat[i].friendlyname;
                            }

                            return(ret);
                        }
                        else
                        {
                            return(null);
                        }
                    });

                    var proslist = curlist.Where(x => x.EntryType == JournalTypeEnum.ProspectedAsteroid).ToList();

                    grd.GetSetsData.Add(delegate(int s, int r)
                    {
                        if (r < proslist.Count)
                        {
                            var jp = proslist[r].journalEntry as JournalProspectedAsteroid;

                            Object[] ret = new object[prosmat.Count + precol];
                            ret[0]       = (r + 1).ToString("N0");
                            ret[1]       = jp.EventTimeUTC.ToStringZulu();
                            ret[2]       = jp.Content.ToString();
                            ret[3]       = MaterialCommodityData.GetByFDName(jp.MotherlodeMaterial)?.Name ?? jp.MotherlodeMaterial;

                            for (int m = 0; m < prosmat.Count; m++)
                            {
                                int mi = Array.FindIndex(jp.Materials, x => x.Name == prosmat[m].matnamefd2);
                                if (mi >= 0)
                                {
                                    ret[m + precol] = jp.Materials[mi].Proportion.ToString("N2");
                                }
                                else
                                {
                                    ret[m + precol] = "";
                                }
                            }
                            return(ret);
                        }
                        else
                        {
                            return(null);
                        }
                    });
                }

                grd.WriteGrid(frm.Path, frm.AutoOpen, FindForm());
            }
        }
        private List <MaterialsFound> ReadHistory(out int prospectorsused, out int collectorsused, out int asteroidscracked, out int prospected, out int[] content)
        {
            prospectorsused  = 0;
            collectorsused   = 0;
            asteroidscracked = 0;
            prospected       = 0;
            content          = new int[3];
            var found = new List <MaterialsFound>();

            foreach (var e in curlist)
            {
                //System.Diagnostics.Debug.WriteLine("{0} {1} {2}", e.Indexno, e.EventTimeUTC, e.EventSummary);

                switch (e.EntryType)
                {
                case JournalTypeEnum.AsteroidCracked:
                    asteroidscracked++;
                    break;

                case JournalTypeEnum.ProspectedAsteroid:
                    prospected++;
                    var pa = e.journalEntry as JournalProspectedAsteroid;
                    if (pa.Materials != null)
                    {
                        foreach (var m in pa.Materials)
                        {
                            var matpa = MaterialsFound.Find(m.Name, found);
                            matpa.prospectednoasteroids++;
                            matpa.prospectedamounts.Add(m.Proportion);
                            matpa.content[0] += pa.Content == JournalProspectedAsteroid.AsteroidContent.High ? 1 : 0;
                            matpa.content[1] += pa.Content == JournalProspectedAsteroid.AsteroidContent.Medium ? 1 : 0;
                            matpa.content[2] += pa.Content == JournalProspectedAsteroid.AsteroidContent.Low ? 1 : 0;

                            //System.Diagnostics.Debug.WriteLine("Prospected {0} {1} {2}", m.Name, m.Proportion, pa.Content );
                        }

                        if (pa.MotherlodeMaterial.HasChars())
                        {
                            var matpa = MaterialsFound.Find(pa.MotherlodeMaterial, found);
                            matpa.motherloadasteroids++;
                        }
                    }

                    content[0] += pa.Content == JournalProspectedAsteroid.AsteroidContent.High ? 1 : 0;
                    content[1] += pa.Content == JournalProspectedAsteroid.AsteroidContent.Medium ? 1 : 0;
                    content[2] += pa.Content == JournalProspectedAsteroid.AsteroidContent.Low ? 1 : 0;

                    break;

                case JournalTypeEnum.LaunchDrone:
                    var ld = e.journalEntry as JournalLaunchDrone;
                    if (ld.Type == JournalLaunchDrone.DroneType.Collection)
                    {
                        collectorsused++;
                    }
                    else if (ld.Type == JournalLaunchDrone.DroneType.Prospector)
                    {
                        prospectorsused++;
                    }
                    break;

                case JournalTypeEnum.MiningRefined:
                    var mr    = e.journalEntry as JournalMiningRefined;
                    var matmr = MaterialsFound.Find(mr.Type, found);
                    matmr.amountrefined++;
                    break;

                case JournalTypeEnum.MaterialCollected:
                    var mc    = e.journalEntry as JournalMaterialCollected;
                    var matmc = MaterialsFound.Find(mc.Name, found);
                    matmc.amountcollected += mc.Count;
                    //System.Diagnostics.Debug.WriteLine("Collected {0} {1}", mc.Count, matmc.amountcollected);
                    break;

                case JournalTypeEnum.MaterialDiscarded:
                    var md    = e.journalEntry as JournalMaterialDiscarded;
                    var matmd = MaterialsFound.Find(md.Name, found);
                    matmd.amountdiscarded += md.Count;
                    break;

                case JournalTypeEnum.MaterialDiscovered:
                    var mdi   = e.journalEntry as JournalMaterialDiscovered;
                    var matdi = MaterialsFound.Find(mdi.Name, found);
                    matdi.discovered = true;
                    break;
                }
            }

            found.Sort(delegate(MaterialsFound left, MaterialsFound right)
            {
                if (left.amountrefined > 0 || right.amountrefined > 0)
                {
                    return(right.amountrefined.CompareTo(left.amountrefined));
                }
                else
                {
                    return(right.amountcollected.CompareTo(left.amountcollected));
                }
            });

            return(found);
        }