//читает очередь партий из переданного листа Excel
        //в очередь qParties
        private void ReadParties(IXLWorksheet _inSheet)
        {
            qParties = new Queue <tParty>();
            //первая строка - легенда, данные со второй строки
            int iRow = 2;

            //читаем, пока не найдется пустая ячейка в столбце ID
            while (_inSheet.Cell(String.Format("A{0}", iRow)).Value.ToString() != "")
            {
                tParty Party = new tParty();

                Party._id = Int32.Parse(_inSheet.Cell(String.Format("A{0}", iRow)).Value.ToString());
                int iNomID = Int32.Parse(_inSheet.Cell(String.Format("B{0}", iRow)).Value.ToString());

                //вставим связанную с партией номенклатуру, найдя ее по ID
                //если номенклатура не найдена, считаем данные ошибочными и пропускаем
                int iNomIndex = FindNomenclatureByID(iNomID);
                if (iNomIndex != -1)
                {
                    Party._tnNomenclature = ((tNomenclature)arrNomenclatures[iNomIndex]);
                    qParties.Enqueue(Party);
                }
                ++iRow;
            }
        }
        private void btnCalc_Click(object sender, EventArgs e)
        {
            btnReadFiles.Enabled = false;
            arrSchedule          = new ArrayList();

            //для каждого элемента из очереди партий:
            while (qParties.Count > 0)
            {
                //извлекаем элемент-партию
                tParty Party = qParties.Dequeue();

                //сортируем массив оборудования по признаку возрастания текущей занятости
                IComparer myComparer = new tMachineToolComparerLoad();
                arrTools.Sort(myComparer);

                int i;
                for (i = 0; i < arrTools.Count; ++i)
                {
                    //находим наименее занятую машину, подходящую для обработки номенклатуры из партии
                    if (((tMachineTool)arrTools[i]).isSuitableForNomenclature(Party._tnNomenclature._id))
                    {
                        tWorkSchedule wsItem;
                        wsItem._Party     = Party;
                        wsItem._Tool      = (tMachineTool)arrTools[i];
                        wsItem._startTime = ((tMachineTool)arrTools[i]).GetCurrentLoad();
                        //партию назначаем как самой машине (в ее личный список дел)
                        ((tMachineTool)arrTools[i]).AssignJob(Party);
                        //так и в общий план работ
                        arrSchedule.Add(wsItem);
                        break;
                    }
                }
                if (i == arrTools.Count)
                {
                    //не нашлось подходящего инструмента для обработки партии
                    MessageBox.Show(
                        String.Format("Внимание! Для партии №{0} ({1}) не нашлось подходящего инструмента, способного её обработать.", Party._id, Party._tnNomenclature._sName),
                        "Партия не обработана",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Warning
                        );
                }
            }

            //если удалось хоть одну партию вписать в план, то стартуем вывод результатов
            if (arrSchedule.Count > 0)
            {
                //предварительно сортируем машины по ID, так как перепутались в ходе назначения заданий
                IComparer myComparer = new tMachineToolComparerID();
                arrTools.Sort(myComparer);

                this.Height           = iMaxHeight;
                dataGridView1.Visible = true;
                ShowReport();
                PrintResult();
                btnExcel.Enabled = true;
            }
        }
        //записать партию в план обработки машины
        public int AssignJob(tParty Party)
        {
            int iTime = GetTimeByNomenclatureID(Party._tnNomenclature._id);

            if (iTime != -1)
            {
                iCurrentLoad += iTime;
                arrWorks.Add(Party);
                return(0);
            }
            return(-1);
        }
        private void PrintResult()
        {
            String strFilename = strOutFilename;// System.IO.Directory.GetCurrentDirectory() + "\\" + "out.xlsx";

            if (System.IO.File.Exists(strFilename))
            {
                try
                {
                    System.IO.File.Delete(strFilename);
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show("Внимание! Не удалось создать файл для записи результатов. Возможно, файл открыт в другой программе, или недостаточно прав для записи.", "Файл не создан", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                    //return;
                }
            }
            XLWorkbook xlBook  = new XLWorkbook();
            var        xlSheet = xlBook.Worksheets.Add("Расписание обработки партий");

            //вывод результатов (общая таблица планирования)
            xlSheet.Cells("A1").Value = "Номер партии";
            xlSheet.Cells("B1").Value = "Номенклатура";
            xlSheet.Cells("C1").Value = "Оборудование";
            xlSheet.Cells("D1").Value = "Начало этапа обработки";
            xlSheet.Cells("E1").Value = "Конец этапа обработки";
            for (int i = 0; i < arrSchedule.Count; ++i)
            {
                //в excel
                xlSheet.Cells(String.Format("A{0}", i + 2)).Value = ((tWorkSchedule)arrSchedule[i])._Party._id;
                xlSheet.Cells(String.Format("B{0}", i + 2)).Value = ((tWorkSchedule)arrSchedule[i])._Party._tnNomenclature._sName;
                xlSheet.Cells(String.Format("C{0}", i + 2)).Value = ((tWorkSchedule)arrSchedule[i])._Tool.GetName();
                xlSheet.Cells(String.Format("D{0}", i + 2)).Value = ((tWorkSchedule)arrSchedule[i])._startTime;
                xlSheet.Cells(String.Format("E{0}", i + 2)).Value = ((tWorkSchedule)arrSchedule[i])._startTime + ((tWorkSchedule)arrSchedule[i])._Tool.GetTimeByNomenclatureID(((tWorkSchedule)arrSchedule[i])._Party._tnNomenclature._id);
                //и на экран
                dataGridView1.Rows.Add(
                    ((tWorkSchedule)arrSchedule[i])._Party._id,
                    ((tWorkSchedule)arrSchedule[i])._Party._tnNomenclature._sName,
                    ((tWorkSchedule)arrSchedule[i])._Tool.GetName(),
                    ((tWorkSchedule)arrSchedule[i])._startTime,
                    ((tWorkSchedule)arrSchedule[i])._startTime + ((tWorkSchedule)arrSchedule[i])._Tool.GetTimeByNomenclatureID(((tWorkSchedule)arrSchedule[i])._Party._tnNomenclature._id)
                    );
            }
            xlSheet.Columns().AdjustToContents();

            //дополнительно в отдельные страницы впишем графики загрузки каждой машины
            for (int i = 0; i < arrTools.Count; ++i)
            {
                String strTabName = String.Format("Расписание \"{0}\"", ((tMachineTool)arrTools[i]).GetName());
                //в excel имя воркшита лимитировано по размеру в 31 символ
                //если перебрали - заменяем полное имя на счетчик цикла
                if (strTabName.Length > 31)
                {
                    //strTabName = strTabName.Substring(0, 31);
                    strTabName = i.ToString();
                }
                var xlSheet1 = xlBook.Worksheets.Add(strTabName);
                xlSheet1.Cells("A1").Value = "Номер партии";
                xlSheet1.Cells("B1").Value = "Номенклатура";
                xlSheet1.Cells("C1").Value = "Начало этапа обработки";
                xlSheet1.Cells("D1").Value = "Конец этапа обработки";
                int iTime = 0;
                for (int j = 0; j < ((tMachineTool)arrTools[i]).arrWorks.Count; ++j)
                {
                    tParty Party = (tParty)(((tMachineTool)arrTools[i]).arrWorks[j]);
                    xlSheet1.Cells(String.Format("A{0}", j + 2)).Value = Party._id;
                    xlSheet1.Cells(String.Format("B{0}", j + 2)).Value = Party._tnNomenclature._sName;
                    xlSheet1.Cells(String.Format("C{0}", j + 2)).Value = iTime;
                    xlSheet1.Cells(String.Format("D{0}", j + 2)).Value = (iTime += ((tMachineTool)arrTools[i]).GetTimeByNomenclatureID(Party._tnNomenclature._id));
                }
                xlSheet1.Columns().AdjustToContents();
            }

            try
            {
                xlBook.SaveAs(strFilename);
                //System.Diagnostics.Process.Start(strFilename, "");
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("Внимание! Не удалось создать файл для записи результатов. Возможно, файл открыт в другой программе, или недостаточно прав для записи.", "Файл не создан", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
            }

            btnReadFiles.Enabled = true;
            btnCalc.Enabled      = false;
        }