2021-02-03 01:05:58 -05:00
using System ;
using System.Collections.Generic ;
using System.ComponentModel ;
using System.Data ;
using System.Drawing ;
2021-02-06 02:00:37 -05:00
using System.IO ;
2021-02-03 01:05:58 -05:00
using System.Linq ;
using System.Text ;
using System.Threading.Tasks ;
using System.Windows.Forms ;
2021-02-06 02:00:37 -05:00
using CsvHelper ;
2021-02-03 12:10:30 -05:00
using GreatHomeChildcare.Models ;
2021-02-03 01:05:58 -05:00
2021-02-03 13:21:00 -05:00
//REF:
//https://stackoverflow.com/questions/9780800/what-event-is-raised-when-a-user-interacts-with-the-datetimepicker-control
2021-02-03 01:05:58 -05:00
namespace GreatHomeChildcare
{
public partial class frmReports : Form
{
2021-02-03 12:10:30 -05:00
//globals for cheap access.
SqliteDataAccess SqliteDataAccess = new SqliteDataAccess ( ) ;
2021-02-03 17:19:24 -05:00
List < Child > AllChildren = new List < Child > ( ) ;
2021-02-06 02:00:37 -05:00
const string UNIXEPOCH = "1970-01-01" ;
const string DATE_TO_STRING = "yyyy-MM-dd" ;
2021-02-03 12:10:30 -05:00
2021-02-03 01:05:58 -05:00
public frmReports ( )
{
InitializeComponent ( ) ;
}
2021-02-03 12:10:30 -05:00
private void frmReports_Load ( object sender , EventArgs e )
{
2021-02-06 02:00:37 -05:00
/ * The columns are there for us in the designer view .
* Realistically we won ' t need them as the dgv is
* programatically bound to a data source .
* /
dgvReports . Columns . Clear ( ) ;
2021-02-05 23:13:29 -05:00
//cannot select from a future date.
this . dtpFrom . MaxDate = DateTime . Now ;
//Ensure the To date is not before the From date.
this . dtpTo . MinDate = this . dtpFrom . Value ;
this . dtpTo . MaxDate = DateTime . Now ;
2021-02-03 12:10:30 -05:00
LoadFilterComboBox ( ) ;
2021-02-03 17:19:24 -05:00
RefreshReportDgv ( ) ;
2021-02-03 12:10:30 -05:00
}
private void LoadFilterComboBox ( )
{
Child everyoneSelection = new Child ( ) ;
/ * cheap hack since you can ' t add an item to
* a combobox that has existing databinding .
* /
everyoneSelection . id = 0 ;
everyoneSelection . DisplayName = "Everyone" ;
2021-02-03 17:19:24 -05:00
AllChildren = SqliteDataAccess . GetAllChildren ( ) ;
AllChildren . Insert ( 0 , everyoneSelection ) ;
2021-02-03 12:10:30 -05:00
2021-02-03 17:19:24 -05:00
cbChildPicker . DataSource = AllChildren ;
}
/ * Updates the on - screen display datagridview
* upon selecting a new child from the drop - down box .
* /
private void cbChildPicker_SelectionChangeCommitted ( object sender , EventArgs e )
{
RefreshReportDgv ( ) ;
2021-02-03 12:10:30 -05:00
}
2021-02-03 13:21:00 -05:00
//DTP shenanigans ref stackexchange
private void dtpFrom_ValueChanged ( object sender , EventArgs e )
{
//Update the to date, but not before the From date.
dtpTo . MinDate = dtpFrom . Value ;
}
private void dtpFrom_DropDown ( object sender , EventArgs e )
{
dtpFrom . ValueChanged - = dtpFrom_ValueChanged ;
}
private void dtpFrom_CloseUp ( object sender , EventArgs e )
{
dtpFrom . ValueChanged + = dtpFrom_ValueChanged ;
dtpFrom_ValueChanged ( sender , e ) ;
2021-02-06 02:00:37 -05:00
RefreshReportDgv ( ) ;
}
private void dtpTo_CloseUp ( object sender , EventArgs e )
{
RefreshReportDgv ( ) ;
2021-02-03 13:21:00 -05:00
}
2021-02-03 17:19:24 -05:00
//Refresh the datagrid view.
private void RefreshReportDgv ( )
{
2021-02-06 02:00:37 -05:00
dgvReports . DataSource = null ;
2021-02-03 17:19:24 -05:00
dgvReports . Rows . Clear ( ) ;
2021-02-05 01:16:12 -05:00
2021-02-03 17:19:24 -05:00
//First do the everyone case.
if ( cbChildPicker . Text = = "Everyone" )
{
2021-02-06 02:00:37 -05:00
List < ReportScreen > lstRs = new List < ReportScreen > ( ) ;
foreach ( DateTime day in EachDay ( dtpFrom . Value , dtpTo . Value ) )
2021-02-05 01:16:12 -05:00
{
2021-02-06 02:00:37 -05:00
//Double loop here is the only way I can think about it.
foreach ( Child child in AllChildren )
{
//Repeat of the code of an individual child.
ReportScreen rs = new ReportScreen ( ) ;
rs = ReportChildDay ( child , day ) ;
2021-02-05 01:16:12 -05:00
2021-02-06 02:00:37 -05:00
if ( rs ! = null )
{
//push older events to the bottom.
lstRs . Insert ( 0 , rs ) ;
}
} //foreach child
} //foreach day
//Load the datagrid.
dgvReports . DataSource = lstRs ;
} // end everyone
2021-02-03 17:19:24 -05:00
else //load an individual child
{
2021-02-05 01:16:12 -05:00
Child child = ( Child ) cbChildPicker . SelectedItem ;
2021-02-06 02:00:37 -05:00
List < ReportScreen > lstRs = new List < ReportScreen > ( ) ;
2021-02-05 01:16:12 -05:00
foreach ( DateTime day in EachDay ( dtpFrom . Value , dtpTo . Value ) )
{
2021-02-06 02:00:37 -05:00
ReportScreen rs = new ReportScreen ( ) ;
rs = ReportChildDay ( child , day ) ;
if ( rs ! = null )
{
//push older events to the bottom.
lstRs . Insert ( 0 , rs ) ;
}
2021-02-05 01:16:12 -05:00
}
2021-02-06 02:00:37 -05:00
//Load the datagrid.
dgvReports . DataSource = lstRs ;
} //end else individual child
}
/ * Gets sign / in out data for a single child given a single day .
* INPUT : child , day
* OUTPUT : reportscreen datatype class .
* /
private ReportScreen ReportChildDay ( Child child , DateTime day )
{
ReportScreen rs = new ReportScreen ( ) ;
AttendenceSingleInOutData in_data = new AttendenceSingleInOutData ( ) ;
AttendenceSingleInOutData out_data = new AttendenceSingleInOutData ( ) ;
in_data = SqliteDataAccess . GetAttendenceByStatusForChildByDay ( child , "in" , day . ToString ( DATE_TO_STRING ) ) ;
out_data = SqliteDataAccess . GetAttendenceByStatusForChildByDay ( child , "out" , day . ToString ( DATE_TO_STRING ) ) ;
if ( in_data = = null )
return null ;
rs . ChildName = $"{in_data.ChildLastName}, {in_data.ChildFirstName}" ;
rs . in_time = DateTime . Parse ( in_data . timestamp ) ;
rs . GuardianInName = $"{in_data.GuardianLastName}, {in_data.GuardianLastName}" ;
if ( out_data ! = null ) //Student's been checked out, display that data.
{
rs . out_time = DateTime . Parse ( out_data . timestamp ) ;
rs . GuardianOutName = $"{out_data.GuardianLastName}, {out_data.GuardianFirstName}" ;
}
else //Student has not been checked out yet.
{
rs . out_time = DateTime . Parse ( UNIXEPOCH ) ;
rs . GuardianOutName = String . Empty ;
}
if ( rs . out_time ! = DateTime . Parse ( UNIXEPOCH ) ) //check for null out_time.
{
TimeSpan duration = rs . out_time . Subtract ( rs . in_time ) ;
rs . Duration = duration . ToString ( ) ;
2021-02-03 17:19:24 -05:00
}
2021-02-06 02:00:37 -05:00
return rs ;
2021-02-03 17:19:24 -05:00
}
2021-02-05 01:16:12 -05:00
//https://stackoverflow.com/questions/1847580/how-do-i-loop-through-a-date-range
public IEnumerable < DateTime > EachDay ( DateTime from , DateTime thru )
{
for ( var day = from . Date ; day . Date < = thru . Date ; day = day . AddDays ( 1 ) )
yield return day ;
}
2021-02-06 02:00:37 -05:00
private void btnSavetoCSV_Click ( object sender , EventArgs e )
{
//If nothing's shown on screen, there's nothing to save.
if ( dgvReports . Rows . Count < 1 )
{
MessageBox . Show ( "There are no reports for that time frame. Choose another time frame and try again." , "Great Home Childcare" , MessageBoxButtons . OK , MessageBoxIcon . None ) ;
return ;
}
//Build the default filename
saveFileDialogReport . FileName = DateTime . Now . ToString ( "yy.MM.dd" ) + "-report.csv" ;
if ( saveFileDialogReport . ShowDialog ( ) = = DialogResult . OK
& & saveFileDialogReport . FileName ! = "" )
{
string filename = saveFileDialogReport . FileName ;
List < ReportData > lstReport = new List < ReportData > ( ) ;
lstReport = GenerateReport ( ) ;
//Now with that monkey business out of the way
//let's get on with actually saving the file.
TextWriter textWriter = new StreamWriter ( filename ) ;
CsvWriter csvWriter = new CsvWriter ( textWriter ) ;
csvWriter . WriteRecords ( lstReport ) ;
textWriter . Close ( ) ;
MessageBox . Show ( "Report Saved" , "Great Home Childcare" , MessageBoxButtons . OK , MessageBoxIcon . None ) ;
}
}
private List < ReportData > GenerateReport ( )
{
List < ReportData > lstReport = new List < ReportData > ( ) ;
//First do the everyone case.
if ( cbChildPicker . Text = = "Everyone" )
{
/ * This is basically the same code as ReportChildDay ,
* but the query we are executing is different along with the datatype .
* /
foreach ( DateTime day in EachDay ( dtpFrom . Value , dtpTo . Value ) )
{
List < ReportData > dayRd = new List < ReportData > ( ) ;
dayRd = SqliteDataAccess . GetReportData ( day . ToString ( DATE_TO_STRING ) , null ) ;
lstReport . AddRange ( dayRd ) ;
}
}
else //an individual child was selected.
{
Child child = ( Child ) cbChildPicker . SelectedItem ;
foreach ( DateTime day in EachDay ( dtpFrom . Value , dtpTo . Value ) )
{
List < ReportData > dayRd = new List < ReportData > ( ) ;
dayRd = SqliteDataAccess . GetReportData ( day . ToString ( DATE_TO_STRING ) , child ) ;
lstReport . AddRange ( dayRd ) ;
}
}
return lstReport ;
}
private void btnPrint_Click ( object sender , EventArgs e )
{
//If nothing's shown on screen, there's nothing to print.
if ( dgvReports . Rows . Count < 1 )
{
MessageBox . Show ( "There are no reports for that time frame. Choose another time frame and try again." , "Great Home Childcare" , MessageBoxButtons . OK , MessageBoxIcon . None ) ;
return ;
}
//TODO: figure out a way to actually implement printing. It's one of the toolbox things.
}
2021-02-03 01:05:58 -05:00
}
}