/// <summary>
 /// Konstruktor.
 /// </summary>
 /// <param name="leaveManagerParentForm">Obiekt rodzica.</param>
 /// <param name="connection">Połączenie z bazą danych. Powinno być otwarte.</param>
 /// <param name="employeeId">Numer id pracownika, którego dotyczy zgłoszenie urlopowe.</param>
 /// <param name="firstDay">Data rozpoczęcia urlopu.</param>
 /// <param name="lastDay">Data zakończenia urlopu.</param>
 public FormLeaveConsideration(LeaveManagerForm leaveManagerParentForm, SqlConnection connection, Leave consideredLeave )
 {
     InitializeComponent();
     this.connection = connection;
     this.consideredLeave = consideredLeave;
     this.leaveManagerParentForm = leaveManagerParentForm;
     labelFirstDayValue.Text = consideredLeave.FirstDay.ToString("d");
     labelLastDayValue.Text = consideredLeave.LastDay.ToString("d");
     try
     {
         //Zczytanie imienia, nazwiska oraz pozycji pracownika.
         Employee employee = this.GetEmployee(consideredLeave.EmployeeId);
         labelNameValue.Text = employee.Name;
         labelPositionValue.Text = employee.Position;
         DateTime tmp = consideredLeave.FirstDay;
         bool[] days = this.GetWorkingDaysOfWeek(employee.EmployeeId);
         while (tmp <= consideredLeave.LastDay)
         {
             if (days[((int)tmp.DayOfWeek + 6) % 7] && !IsHoliday(tmp))
                 dataGridView.Rows.Add(tmp, this.GetSimiliarWorkerCount(this.GetPositionID(employee.Position), employee.EmployeeId, tmp), this.GetNeededEmployeesNo(tmp));
             tmp = tmp.AddDays(1);
         }
     }
     catch (SqlException)
     {
         MessageBox.Show("SQL Error. This form will be close. Please try again later.");
         this.Close();
     }
     catch (InvalidOperationException)
     {
         MessageBox.Show("Invalid operation. This form will be close. Please try again later");
         this.Close();
     }
     catch (EmployeeIdException)
     {
         MessageBox.Show("EmployeeID not found in database. This form will be close. Please try again later");
         this.Close();
     }
     catch (Exception ex)
     {
         MessageBox.Show("Unknown exception has occured" + ex.Message);
         this.Close();
     }
 }
 /// <summary>
 /// Konstruktor przeznaczony do tworzenia instancji edytującej istniejący wpis
 /// urlopowy. Ustawia wartości w elementach zczytujących dane (np. textbox, combobox)
 /// zgodne z wartościami w edytowanym wpisie urlopowym.
 /// </summary>
 /// <param name="connection">Połączenie do bazy danych. Powinno być otwarte.</param>
 /// <param name="leaveDaysList">Dostępna liczba dni urlopowych (bez dni zaległych).</param>
 /// <param name="oldLeaveDaysList">Dostępna liczba zaległych dni urlopowych.</param>
 /// <param name="employeeId">Numer id pracownika, którego dotyczy zgłoszenie urlopowe.</param>
 /// <param name="editedLeave">Obiekt reprezentujący edytowany wpis urlopowy.</param>
 public FormLeaveApplication(SqlConnection connection, Leave editedLeave)
 {
     InitializeComponent();
     this.connection = connection;
     this.employeeId = editedLeave.EmployeeId;
     this.editMode = true;
     this.editedLeave = editedLeave;
     //Zczytanie listy typów urlopów i przypisanie do atrybutu klasy oraz do odpowiedniego
     //comboBox'a.
     try
     {
         comboBoxType.DataSource = leaveTypes = this.GetLeaveTypesList();
     }
     catch (SqlException)
     {
         MessageBox.Show("SQL Error. This form will be close. Please try again later.");
         this.Close();
     }
     catch (InvalidOperationException)
     {
         MessageBox.Show("Invalid operation. This form will be close. Please try again later");
         this.Close();
     }
     catch (Exception ex)
     {
         MessageBox.Show("Unknown exception has occured" + ex.Message);
         this.Close();
     }
     //Zaznaczenie w comboBox'ie zawierającym typy urlopów typu edytowanego zgłoszenia.
     comboBoxType.SelectedIndex = comboBoxType.FindStringExact(editedLeave.LeaveType);
     /* Ustawienie ograniczenia odnośnie możliwości wyboru dnia rozpoczęcia i zakończenia urlopu.
      * Jeżeli pierwszy dzień w zgłoszeniu już był (jest wcześniej niż teraz),
      * to najwcześniejszą możliwą datą jest ten właśnie dzień. W innym wypadku najwcześniejszą możliwą
      * datą jest dzisiaj.
      */
     if (editedLeave.FirstDay.CompareTo(DateTime.Now) <= 0)
     {
         dateTimePickerFirstDay.MinDate = editedLeave.FirstDay.Trim(TimeSpan.TicksPerDay);
         dateTimePickerLastDay.MinDate = editedLeave.FirstDay.Trim(TimeSpan.TicksPerDay);
     }
     else
     {
         dateTimePickerLastDay.MinDate = dateTimePickerFirstDay.MinDate = DateTime.Now.Trim(TimeSpan.TicksPerDay);
     }
     //Ograniczenie wyboru dnia rozpoczęcia i zakończenia. Najpóźniej na rok od dnia dzisiejszego.
     dateTimePickerFirstDay.MaxDate = DateTime.Now.Trim(TimeSpan.TicksPerDay).AddYears(1);
     dateTimePickerLastDay.MaxDate = DateTime.Now.Trim(TimeSpan.TicksPerDay).AddYears(1);
     /* Ustawienie wartości początkowej dla elementu wyboru dni rozpoczęcia i zakończenia
      * na dni rozpoczęcia i zakończenia w edytowanym zgłoszeniu.
      */
     dateTimePickerFirstDay.Value = editedLeave.FirstDay;
     dateTimePickerLastDay.Value = editedLeave.LastDay;
     /* Jeżli zgłoszenie urlopowe jest typu, który konsumuje dni urlopowe, to następuje
      * obliczenie i ustawienie wartości etykiety z liczbą zużywanych przez urlop dni.
      */
     if (leaveTypes[comboBoxType.SelectedIndex].ConsumesDays)
     {
         labelUsedDaysValue.Text = this.GetNumberOfWorkDays(dateTimePickerFirstDay.Value,
             dateTimePickerLastDay.Value, employeeId).ToString();
     }
     else
     {
         labelUsedDaysValue.Text = "0";
     }
     int oldLeaveDays = 0;
     int leaveDays = 0;
     this.GetDays(this.employeeId, ref leaveDays, ref oldLeaveDays);
     //Obliczenie i przypisanie do etykiety liczby dostępnych do zużycia dni.
     labelAvailableDaysValue.Text = (leaveDays + oldLeaveDays).ToString();
     labelNormalValue.Text = leaveDays.ToString();
     labelOldValue.Text = oldLeaveDays.ToString();
     textBoxRemarks.Text = editedLeave.Remarks;
     //Zczytanie listy statusów.
     List<String> statusList = this.GetStatusTypes();
     //Jeżeli status bieżącego urlopu nie jest approved, to usuwana jest możliwość wyboru tego statusu.
     if (!editedLeave.LeaveStatus.Equals("Approved"))
     {
         statusList.Remove("Approved");
     }
     comboBoxStatus.DataSource = statusList;
     comboBoxStatus.SelectedIndex = comboBoxStatus.FindStringExact(editedLeave.LeaveStatus);
 }
        //todo łądnie ogarnąć try i catche.
        /// <summary>
        /// Metoda obsługi zdarzenia wciśnięcia guzika ok.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonOk_Click(object sender, EventArgs e)
        {
            int numberOfUsedDays = this.GetNumberOfWorkDays(dateTimePickerFirstDay.Value, dateTimePickerLastDay.Value, employeeId);
            int leaveDays = 0;
            int oldLeaveDays = 0;
            int yearDays = 0;

            //Zczytanie aktualnych wartości dostępnych dni urlopowych.
            try
            {
                this.GetDays(employeeId, ref leaveDays, ref oldLeaveDays, ref yearDays);
            }
            catch (SqlException)
            {
                MessageBox.Show("SQL error. Please try connection to database or try again later");
                return;
            }
            catch (InvalidOperationException)
            {
                MessageBox.Show("Invalid operation. Please try again later.");
                return;
            }
            catch (Exception ex)
            {
                MessageBox.Show("Unknown exception has occured" + ex.Message);
                return;
            }
            //Uaktualnienie warotości etykiet.
            labelAvailableDaysValue.Text = (leaveDays + oldLeaveDays).ToString();
            labelNormalValue.Text = leaveDays.ToString();
            labelOldValue.Text = oldLeaveDays.ToString();
            //Sprawdzenie, czy nowe zgłoszenie nie wykorzystuje więcej dni, niż pracownik ma ich dostępnych.
            if (numberOfUsedDays <= oldLeaveDays + leaveDays)
            {
                //Sprawdzenie, czy zgłoszenie urlopowe wykorzystuje jakiekolwiek dni.
                if (numberOfUsedDays != 0)
                {
                    /* Sprawdzenie, czy zgłoszenie nie koliduje z już istniejącym.
                     * Jeżeli jest to nowe zgłoszenie (!editMode), to należy po prostu sprawdzić, czy
                     * któryś z dni zgłoszenia nie jest już wykorzystany w innym zgłoszeniu.
                     * Jeżeli jest to zgłoszenie edytowane, to należy sprawdzić, czy któryś z dni zgłoszenia
                     * nie jest już wykorzystany w innym zgłoszeniu, ale należy pominąć sprawdzanie wpisu
                     * edytowanego.
                     * Jeżeli zgłoszenie jest zgłoszeniem chorobowego, to może kolidować z innymi zgłoszeniami.
                     */
                    if ((!editMode && !this.IsDateFromPeriodUsed(dateTimePickerFirstDay.Value, dateTimePickerLastDay.Value, employeeId))
                        || (editMode && !this.IsDateFromPeriodUsed(dateTimePickerFirstDay.Value, dateTimePickerLastDay.Value, employeeId, editedLeave.FirstDay))
                        || comboBoxType.SelectedItem.ToString().Equals("Sick"))
                    {
                        string choosenStatus;
                        if (comboBoxStatus.SelectedItem != null)
                            choosenStatus = comboBoxStatus.SelectedItem.ToString();
                        else
                            choosenStatus = "Pending validation";
                        //Stworzenie nowego obiektu urlopu.
                        Leave leave = new Leave(employeeId, comboBoxType.SelectedItem.ToString(),
                            choosenStatus, dateTimePickerFirstDay.Value, dateTimePickerLastDay.Value, textBoxRemarks.Text);
                        if (editMode)
                        {
                            try
                            {
                                leave.Id = editedLeave.Id;
                                this.EditLeave(leave);
                                this.Close();
                            }
                            catch (SqlException)
                            {
                                MessageBox.Show("SQL error. Please try connection to database or try again later");
                            }
                            catch (InvalidOperationException)
                            {
                                MessageBox.Show("Invalid operation. Please try again later.");
                            }
                            catch (IsolationLevelException)
                            {
                                MessageBox.Show("Isolation level error. Please try again later or contact administrator");
                            }
                            catch (ArgumentException)
                            {
                                MessageBox.Show("Wrong argument\n");
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show("Unknown exception has occured" + ex.Message);
                            }
                        }
                        else
                        {
                            //Jeżeli wybrano zgłoszenie chorobowe.
                            if (comboBoxType.SelectedItem.ToString().Equals("Sick"))
                            {
                                try
                                {
                                    //Dodanie urlopu.
                                    this.AddSickLeave(leave);
                                    this.Close();
                                }
                                catch (SqlException)
                                {
                                    MessageBox.Show("SQL error. Please try connection to database or try again later");
                                }
                                catch (InvalidOperationException)
                                {
                                    MessageBox.Show("Invalid operation. Please try again later.");
                                }
                                catch (IsolationLevelException)
                                {
                                    MessageBox.Show("Isolation level error. Please try again later or contact administrator");
                                }
                                catch (ArgumentOutOfRangeException)
                                {
                                    MessageBox.Show("Wrong argument\n");
                                }
                                catch (Exception ex)
                                {
                                    MessageBox.Show("Unknown exception has occured" + ex.Message);
                                }
                            }
                            else
                            {
                                try
                                {
                                    this.AddLeave(leave);
                                    this.Close();
                                }
                                catch (OverflowException)
                                {
                                    MessageBox.Show("You don't have enough extraordinary days left.");
                                }
                                catch (SqlException)
                                {
                                    MessageBox.Show("SQL error. Please try connection to database or try again later");
                                }
                                catch (InvalidOperationException)
                                {
                                    MessageBox.Show("Invalid operation. Please try again later.");
                                }
                                catch (IsolationLevelException)
                                {
                                    MessageBox.Show("Isolation level error. Please try again later or contact administrator");
                                }
                                catch (ArgumentOutOfRangeException)
                                {
                                    MessageBox.Show("Wrong argument\n");
                                }
                                catch (Exception ex)
                                {
                                    MessageBox.Show("Unknown exception has occured" + ex.Message);
                                }
                            }
                        }
                    }
                    else
                    {
                        MessageBox.Show("At least one day from selected period is already used for leave.");
                    }
                }
                else
                {
                    MessageBox.Show("No work days selected.");
                }
            }
        }
 /// <summary>
 /// Metoda dodawania zgłoszenia urlopowego.
 /// Rozszerza formularz zgłoszenia urlopowego.
 /// </summary>
 /// <param name="form">Formularz wywołujący metodę.</param>
 /// <param name="leave">Obiekt reprezentujący nowy wpis urlopowy.</param>
 /// <exception cref="SqlException">An exception occurred while executing the command against a locked row.</exception>
 /// <exception cref="InvalidOperationException">The current state of the connection is closed.</exception>
 /// <exception cref="IsolationLevelException">Wyjątek występuje, gdy poziom izolacji uruchomionej w 
 /// formularzu transakcji jest zbyt niski do zapewnienia poprawnego wykonania poleceń metody.</exception>
 /// <exception cref="ArgumentException">Występuje w przypadku próby odjęcia większej liczby dni, niż pracownik posiada.</exception>
 public static void AddLeave(this FormLeaveApplication form, Leave leave)
 {
     AddLeave((LeaveManagerForm)form, leave);
 }
 /// <summary>
 /// Metoda pobierająca wpis urlopowy.
 /// </summary>
 /// <param name="form">Formularz potrzebujący metody.</param>
 /// <param name="id">Numer id pobieranego urlopu.</param>
 /// <returns>Obiekt reprezentujący dany urlop.</returns>
 /// <exception cref="SqlException">An exception occurred while executing the command against a locked row.</exception>
 /// <exception cref="InvalidOperationException">The current state of the connection is closed.</exception>
 private static Leave GetLeave(LeaveManagerForm form, int leaveId)
 {
     SqlCommand command = new SqlCommand("SELECT L.Employee_ID, LT.Name AS 'Type', " +
         "LS.Name AS 'Status', L.First_day, L.Last_day, " +
         "L.Remarks, L.Used_days FROM Leave L, Leave_type LT, Status_type LS WHERE Leave_ID = @Leave_ID",
         form.Connection);
     if (form.TransactionOn)
         command.Transaction = form.Transaction;
     command.Parameters.Add("@Leave_ID", SqlDbType.Int).Value = leaveId;
     SqlDataReader reader = command.ExecuteReader();
     reader.Read();
     Leave result = new Leave(leaveId, (int)reader["Employee_ID"], reader["Type"].ToString(), reader["Status"].ToString(),
         (DateTime)reader["First_day"], (DateTime)reader["Last_day"], reader["Remarks"].ToString(), (int)reader["Used_days"]);
     reader.Close();
     return result;
 }
        /// <summary>
        /// Metoda edytująca wpis urlopowy.
        /// </summary>
        /// <param name="form">Formularz potrzebujący metody.</param>
        /// <param name="leave">Obiekt urlopu wpisany w miejsce starego wpisu.</param>
        /// <param name="editedLeaveId">Numer id edytowanego wpisu urlopowego.</param>
        /// <exception cref="SqlException">An exception occurred while executing the command against a locked row.</exception>
        /// <exception cref="InvalidOperationException">The current state of the connection is closed.</exception>
        /// <exception cref="IsolationLevelException">Wyjątek występuje, gdy poziom izolacji uruchomionej w 
        /// formularzu transakcji jest zbyt niski do zapewnienia poprawnego wykonania poleceń metody.</exception>
        /// <exception cref="ArgumentException">Występuje w przypadku próby wzięcia pracownikowi większej liczby dni, niż posiada.</exception> 
        private static void EditLeave(LeaveManagerForm form, Leave leave)
        {
            /* Dla poprawnego działania tej metody konieczne jest aby posiadała ona transakcję
            * o odpowiednim poziomie izolacji.
            */

            //Zmienna przechowująca stan transakcji przed uruchomieniem metody.
            bool isFormTransactionOn = form.TransactionOn;
            //Jeżeli formularz posiada uruchomioną transakcję.
            if (form.TransactionOn)
            {
                //Sprawdzenie, czy poziom izolacji istniejącej transakcji jest wystarczający.
                if (form.Transaction.IsolationLevel != IsolationLevel.RepeatableRead &&
                    form.Transaction.IsolationLevel != IsolationLevel.Serializable)
                {
                    throw new IsolationLevelException();
                }
            }
            else//Jeżeli formularz nie posiada uruchomionej transakcji.
                //Uruchomienie nowej transakcji na potrzeby tej metody z odpowiednim poziomem izolacji.
                form.BeginTransaction(IsolationLevel.RepeatableRead);

            try
            {
                //Zczytanie podmienianego urlopu.
                Leave oldLeave = GetLeave(form, leave.Id);
                //Jeżeli wpisywany urlop konsumuje dni urlopowe.
                if (ConsumesDays(form, leave.LeaveType))
                {
                    leave.UsedDays = GetNumberOfWorkDays(form, leave.FirstDay, leave.LastDay, leave.EmployeeId);
                    //Obliczenie różnicy o którą trzeba zmienić liczbę dni urlopowych pracownika.
                    int difference = oldLeave.UsedDays - leave.UsedDays;
                    AddLeaveDays(form, leave.EmployeeId, difference);
                }
                else//Nowy urlop nie konsumuje dni.
                {
                    leave.UsedDays = 0;
                    //Jeżeli stary urlop konsumuje dni.
                    if (ConsumesDays(form, oldLeave.LeaveType))
                        //Dodajemy pracownikowi tyle dni, ile stary urlop konsumował.
                        AddLeaveDays(form, leave.EmployeeId, oldLeave.UsedDays);
                }
                //Polecenie sql aktualizujące wszystkie dane w starym wpisie.
                SqlCommand commandUpdate = new SqlCommand("UPDATE Leave SET LT_ID = (SELECT LT_ID FROM Leave_type WHERE Name = @Leave_type_name), LS_ID = " +
                   "(SELECT ST_ID FROM Status_type WHERE Name = @Status_name), " +
                   "First_day = @First_day, Last_day = @Last_day, Remarks = @Remarks, Used_days = @Used_days " +
                   "WHERE Leave_ID = @OldLeave_ID", form.Connection, form.Transaction);
                commandUpdate.Parameters.Add("@OldLeave_ID", SqlDbType.Int).Value = leave.Id;
                //Jeżeli wpisywany urlop jest chorobowym, to niezależnie od ustawionego stanu jest ustawiony stan zatwierdzony.
                if (leave.LeaveStatus.Equals("Sick"))
                {
                    commandUpdate.Parameters.Add("@Status_name", SqlDbType.VarChar).Value = "Approved";
                }
                else
                {
                    if (leave.LeaveStatus.Equals("Extraordinary"))
                    {
                    }
                    else
                    {
                        commandUpdate.Parameters.Add("@Status_name", SqlDbType.VarChar).Value = leave.LeaveStatus;
                    }
                }
                commandUpdate.Parameters.Add("@Employee_ID", SqlDbType.Int).Value = leave.EmployeeId;
                commandUpdate.Parameters.Add("@Leave_type_name", SqlDbType.VarChar).Value = leave.LeaveType;
                commandUpdate.Parameters.Add("@First_day", SqlDbType.Date).Value = leave.FirstDay;
                commandUpdate.Parameters.Add("@Last_day", SqlDbType.Date).Value = leave.LastDay;
                commandUpdate.Parameters.Add("@Remarks", SqlDbType.VarChar).Value = leave.Remarks;
                commandUpdate.Parameters.Add("@Used_days", SqlDbType.Int).Value = leave.UsedDays;
                commandUpdate.ExecuteNonQuery();
            }
            catch (Exception e)
            {
                //Jeżeli transakcja formularza była uruchomiona tylko na potrzeby tej metody, to ją cofamy.
                if (!isFormTransactionOn)
                    form.RollbackTransaction();
                //Wyrzucamy wyjątek do dalszej obsługi.
                throw e;
            }
            //Jeżeli operacja powiodła się, a transakcja była uruchomiona tylko na potrzeby tej metody to ją zatwierdzamy.
            if (!isFormTransactionOn)
                form.CommitTransaction();
        }
        /// <summary>
        /// Dodanie chorobowego.
        /// </summary>
        /// <param name="form">Formularz potrzebujący metody.</param>
        /// <param name="leave">Obiekt reprezentujący dodawany urlop.</param>
        /// <exception cref="SqlException">An exception occurred while executing the command against a locked row.</exception>
        /// <exception cref="InvalidOperationException">The current state of the connection is closed.</exception>
        /// <exception cref="IsolationLevelException">Wyjątek występuje, gdy poziom izolacji uruchomionej w 
        /// formularzu transakcji jest zbyt niski do zapewnienia poprawnego wykonania poleceń metody.</exception>
        private static void AddSickLeave(LeaveManagerForm form, Leave leave)
        {
            /* Dla poprawnego działania tej metody konieczne jest aby posiadała ona transakcję
               * o odpowiednim poziomie izolacji.
               */

            //Zmienna przechowująca stan transakcji przed uruchomieniem metody.
            bool isFormTransactionOn = form.TransactionOn;
            //Jeżeli formularz posiada uruchomioną transakcję.
            if (form.TransactionOn)
            {
                //Sprawdzenie, czy poziom izolacji istniejącej transakcji jest wystarczający.
                if (form.Transaction.IsolationLevel != IsolationLevel.RepeatableRead &&
                    form.Transaction.IsolationLevel != IsolationLevel.Serializable)
                {
                    throw new IsolationLevelException();
                }
            }
            else//Jeżeli formularz nie posiada uruchomionej transakcji.
                //Uruchomienie nowej transakcji na potrzeby tej metody z odpowiednim poziomem izolacji.
                form.BeginTransaction(IsolationLevel.RepeatableRead);

            try
            {
                //Zczytanie urlopów pracownika, któremu dodajemy chorobowe.
                /// Kolumny tabeli: "Leave Id", "Status", "First day", "Last day", "Type",
                /// "Remarks", "No. used days"
                DataTable dataLeaves = GetLeaves(form, leave.EmployeeId);

                /* Zmienna w której będzie przechowywana liczba dni do zwrócenia pracownikowi.
                 * Powiększa się w przypadku, gdy chorobowe zachodzi na jakiś urlop.
                 */
                int returnedLeaveDays = 0;
                int returnedDemandedDays = 0;
                //Dla każdego istniejącego w bazie urlopu.
                foreach (DataRow row in dataLeaves.Rows)
                {
                    //Pierwszy dzień sprawdzanego urlopu jest później lub ten sam, co pierwszy dzień chorobowego
                    if ((((DateTime)row.ItemArray.GetValue(2)).CompareTo(leave.FirstDay) >= 0)
                        //i jest wcześniej lub taki sam jak ostatni dzień chorobowego.
                    && (((DateTime)row.ItemArray.GetValue(2)).CompareTo(leave.LastDay) <= 0))
                    {//Czyli w praktyce: Zaczyna się w trakcie chorobowego -> jest anulowany.
                        //Jeżeli zachodzący wpis to chorobowe.
                        if (row.ItemArray.GetValue(4).ToString().Equals("Sick"))
                            throw new EntryExistsException();
                        //Polecenie sql zmieniające stan zachodzącego urlopu na anulowany.
                        SqlCommand commandUpdateLeave = new SqlCommand("UPDATE Leave SET " +
                           "LS_ID = (SELECT ST_ID FROM Status_type WHERE Name = @Status_name), Used_days = @Used_days " +
                           "WHERE Leave_ID = @Leave_ID", form.Connection, form.Transaction);
                        commandUpdateLeave.Parameters.Add("@Status_name", SqlDbType.VarChar).Value = "Canceled";
                        commandUpdateLeave.Parameters.Add("@Leave_ID", SqlDbType.Int).Value = (int)row.ItemArray.GetValue(0);
                        commandUpdateLeave.Parameters.Add("@Used_days", SqlDbType.Int).Value = 0;
                        commandUpdateLeave.ExecuteNonQuery();
                        //Dodanie do liczby dni do zwrócenia pracownikowi dni anulowanego urlopu.
                        returnedLeaveDays += (int)row.ItemArray.GetValue(6);
                        if (row.ItemArray.GetValue(4).ToString().Equals("Extraordinary"))
                        {
                            returnedDemandedDays += (int)row.ItemArray.GetValue(6);
                        }
                        continue;
                    }

                    if ((leave.FirstDay.CompareTo((DateTime)row.ItemArray.GetValue(2)) >= 0)//Sick first day later than leave first day
                    && (leave.FirstDay.CompareTo((DateTime)row.ItemArray.GetValue(3)) <= 0))//and earlier than leave last day.
                    {//Czyli w praktyce: Kończy się w trakcie chorobowego -> jest 'przycinany' do ostatniego dnia przed chorobowym.
                        SqlCommand commandUpdateLeave = new SqlCommand("UPDATE Leave SET " +
                            "Last_day = @Last_day, Used_days = @Used_days WHERE Leave_ID = @Leave_ID", form.Connection, form.Transaction);
                        commandUpdateLeave.Parameters.Add("@Last_day", SqlDbType.Date).Value = leave.FirstDay.AddDays(-1);
                        commandUpdateLeave.Parameters.Add("@Leave_ID", SqlDbType.Int).Value = (int)row.ItemArray.GetValue(0);
                        //Nowa liczba użytych dni to liczba użytych dni pomiędzy pierwszym dniem zmienianego urlopu i pierwszym-1 dniem chorobowego.
                        commandUpdateLeave.Parameters.Add("@Used_days", SqlDbType.Int).Value =
                            GetNumberOfWorkDays(form, (DateTime)row.ItemArray.GetValue(2), leave.FirstDay.AddDays(-1), leave.EmployeeId);
                        commandUpdateLeave.ExecuteNonQuery();
                        int tmpReturnedDays = GetNumberOfWorkDays(form, leave.FirstDay.AddDays(-1), (DateTime)row.ItemArray.GetValue(1), leave.EmployeeId);
                        //Dodanie do liczby dni do zwrócenia pracownikowi liczby dni za okres od początku chorobowego do końca urlopu.
                        returnedLeaveDays += GetNumberOfWorkDays(form, leave.FirstDay.AddDays(-1), (DateTime)row.ItemArray.GetValue(1), leave.EmployeeId);
                        //Jeżeli urlop był na żądanie.
                        if (row.ItemArray.GetValue(4).ToString().Equals("Extraordinary"))
                        {
                            returnedDemandedDays += tmpReturnedDays;
                        }
                        continue;
                    }
                }
                //Zwrócenie pracownikowi dni.
                AddLeaveDays(form, leave.EmployeeId, returnedLeaveDays);
                AddDemandDays(form, leave.EmployeeId, -returnedDemandedDays);
                //Dodanie urlopu.
                AddLeave(form, leave);
            }
            catch (Exception e)
            {
                //Jeżeli transakcja formularza była uruchomiona tylko na potrzeby tej metody, to ją cofamy.
                if (!isFormTransactionOn)
                    form.RollbackTransaction();
                //Wyrzucamy wyjątek do dalszej obsługi.
                throw e;
            }
            //Jeżeli operacja powiodła się, a transakcja była uruchomiona tylko na potrzeby tej metody to ją zatwierdzamy.
            if (!isFormTransactionOn)
                form.CommitTransaction();
        }
        /// <summary>
        /// Metoda dodawania zgłoszenia urlopowego.
        /// </summary>
        /// <param name="form">Formularz potrzebujący metody.</param>
        /// <param name="leave">Obiekt reprezentujący nowy wpis urlopowy.</param>
        /// <exception cref="SqlException">An exception occurred while executing the command against a locked row.</exception>
        /// <exception cref="InvalidOperationException">The current state of the connection is closed.</exception>
        /// <exception cref="IsolationLevelException">Wyjątek występuje, gdy poziom izolacji uruchomionej w 
        /// formularzu transakcji jest zbyt niski do zapewnienia poprawnego wykonania poleceń metody.</exception>
        /// <exception cref="ArgumentException">Występuje w przypadku próby odjęcia większej liczby dni, niż pracownik posiada.</exception>
        private static void AddLeave(LeaveManagerForm form, Leave leave)
        {
            /* Dla poprawnego działania tej metody konieczne jest aby posiadała ona transakcję
               * o odpowiednim poziomie izolacji.
               */

            //Zmienna przechowująca stan transakcji przed uruchomieniem metody.
            bool isFormTransactionOn = form.TransactionOn;
            //Jeżeli formularz posiada uruchomioną transakcję.
            if (form.TransactionOn)
            {
                //Sprawdzenie, czy poziom izolacji istniejącej transakcji jest wystarczający.
                if (form.Transaction.IsolationLevel != IsolationLevel.RepeatableRead &&
                    form.Transaction.IsolationLevel != IsolationLevel.Serializable)
                {
                    throw new IsolationLevelException();
                }
            }
            else//Jeżeli formularz nie posiada uruchomionej transakcji.
                //Uruchomienie nowej transakcji na potrzeby tej metody z odpowiednim poziomem izolacji.
                form.BeginTransaction(IsolationLevel.RepeatableRead);

            try
            {
                //Liczba zużytych przez urlop dni.
                int usedDays;
                //Jeżeli urlop konsumuje dni.
                if (ConsumesDays(form, leave.LeaveType))
                {
                    usedDays = GetNumberOfWorkDays(form, leave.FirstDay, leave.LastDay, leave.EmployeeId);
                    //Odejmujemy pracownikowi dni za dany urlop.
                    AddLeaveDays(form, leave.EmployeeId, -usedDays);
                }
                else
                {
                    usedDays = 0;
                }
                //Polecenie sql Zczytujące największy nr id + 1
                SqlCommand commandGetNewId = new SqlCommand("(SELECT MAX(Leave_ID) + 1 FROM Leave)", form.Connection, form.Transaction);
                int newLeaveId;
                try
                {
                    newLeaveId = (int)commandGetNewId.ExecuteScalar();
                }
                catch
                {
                    //Jeżeli nie udało się zczytać id, to możliwe, że żaden wpis w bazie nie istnieje. Wtedy przypisujemy id = 0
                    newLeaveId = 0;
                }

                //Polecenie sql dodające nowy wpis urlopowy.
                SqlCommand commandInsertLeave = new SqlCommand("INSERT INTO Leave VALUES (@Leave_ID, @Employee_ID, " +
                     "(SELECT LT_ID FROM Leave_type WHERE Name = @Leave_type_name), (SELECT ST_ID FROM Status_type WHERE Name = @Status_name), " +
                     "@First_day, @Last_day, @Remarks, @Used_days)", form.Connection, form.Transaction);
                //Jeżeli wpis to chorobowe, to automatycznie otrzymuje stan zatwierdzony.
                if (leave.LeaveType.Equals("Sick"))
                {
                    commandInsertLeave.Parameters.Add("@Status_name", SqlDbType.VarChar).Value = "Approved";
                }
                else
                {
                    //Jeżeli jest to urlop na żądanie, to automatycznie otrzymuje stan zatwierdzony.
                    if (leave.LeaveType.Equals("Extraordinary"))
                    {
                        commandInsertLeave.Parameters.Add("@Status_name", SqlDbType.VarChar).Value = "Approved";
                        //Zaktualizowanie stanu liczby dostępnych dni na żądanie.
                        AddDemandDays(form, leave.EmployeeId, usedDays);
                    }
                    else
                    {
                        commandInsertLeave.Parameters.Add("@Status_name", SqlDbType.VarChar).Value = leave.LeaveStatus;
                    }
                }
                commandInsertLeave.Parameters.Add("@Leave_ID", SqlDbType.Int).Value = newLeaveId;
                commandInsertLeave.Parameters.Add("@Employee_ID", SqlDbType.Int).Value = leave.EmployeeId;
                commandInsertLeave.Parameters.Add("@Leave_type_name", SqlDbType.VarChar).Value = leave.LeaveType;
                commandInsertLeave.Parameters.Add("@First_day", SqlDbType.Date).Value = leave.FirstDay;
                commandInsertLeave.Parameters.Add("@Last_day", SqlDbType.Date).Value = leave.LastDay;
                commandInsertLeave.Parameters.Add("@Remarks", SqlDbType.VarChar).Value = leave.Remarks;
                commandInsertLeave.Parameters.Add("@Used_days", SqlDbType.Int).Value = usedDays;
                commandInsertLeave.ExecuteNonQuery();
            }
            catch (Exception e)
            {
                //Jeżeli transakcja formularza była uruchomiona tylko na potrzeby tej metody, to ją cofamy.
                if (!isFormTransactionOn)
                    form.RollbackTransaction();
                //Wyrzucamy wyjątek do dalszej obsługi.
                throw e;
            }
            //Jeżeli operacja powiodła się, a transakcja była uruchomiona tylko na potrzeby tej metody to ją zatwierdzamy.
            if (!isFormTransactionOn)
                form.CommitTransaction();
        }