/**
    File        : BalanceAccount.cpp
    Description : Classes to balance an account
    Author      : Raymond Marsh
    Created     : 08/01/2009
    Copyright 2009, 2010 Raymond Marsh

    This program is distributed under the terms of the GNU General Public License.
    To view a copy of the license see the file 'copying.txt'

    This file is part of the Ace Personal Finance Assistant Suite.

    Ace Personal Finance Assistant is free software: you can redistribute it and/or modify it under
    the terms of the GNU General Public License as published by the Free Software Foundation, either
    version 3 of the License, or (at your option) any later version.

    Ace Personal Finance Assistant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
    without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along with Ace Personal Finance Assistant.
    If not, see <http://www.gnu.org/licenses/>.
**/

#include "BalanceAccount.h"

CBalanceDlg::CBalanceDlg(wxWindow* pParent, /*ace::CData* pData, */SBalanceInfo &BalanceInfo)
: wxDialog(pParent, wxID_ANY, _("Statement Information"), wxDefaultPosition, wxSize(325, 300), wxCAPTION),
  m_pParent(pParent), /*m_pData(pData), */m_pBalanceInfo(&BalanceInfo)
{
    wxPanel* pPanel = new wxPanel(this, wxID_ANY);
    wxBoxSizer* pVSizer = new wxBoxSizer(wxVERTICAL);
    wxGridSizer* pGSizer = new wxGridSizer(0, 2, 0, 0);
    wxStdDialogButtonSizer* pBtnSizer = new wxStdDialogButtonSizer();

    wxStaticText* pHeaderTxt = new wxStaticText(pPanel, wxID_ANY, _("Enter information from your statement") );

    pGSizer->Add(new wxStaticText(pPanel, wxID_ANY, _("Statement End Date") ),
                 3, wxALIGN_CENTER | wxALL | wxEXPAND, 5);
    pGSizer->Add(m_pEndDateCtrl = new wxDatePickerCtrl(pPanel,
                                                       idEndDateCtrl,
                                                       wxDateTime::Today(),
                                                       wxDefaultPosition,
                                                       wxDefaultSize,
                                                       wxDP_DROPDOWN,
                                                       wxDefaultValidator),
                 2, wxALIGN_CENTER | wxALL | wxEXPAND, 5);

    pGSizer->Add(new wxStaticText(pPanel, wxID_ANY, _("Statement End Balance") ),
                 3, wxALIGN_CENTER | wxALL | wxEXPAND, 5);
    pGSizer->Add(m_pEndBalanceCtrl = new wxTextCtrl(pPanel,
                                                    idEndBalanceCtrl,
                                                    _(""),
                                                    wxDefaultPosition,
                                                    wxDefaultSize,
                                                    0,
                                                    wxTextValidator(wxFILTER_NUMERIC,
                                                                    &BalanceInfo.EndBalance) ),
                 2, wxALIGN_CENTER | wxALL | wxEXPAND, 5);

    pGSizer->Add(m_pServiceChargeBtn = new wxCheckBox(pPanel,
                                                      idServiceChargeBtn,
                                                      _("Service Charge Amount"),
                                                      wxDefaultPosition,
                                                      wxDefaultSize),
                 3, wxALIGN_CENTER | wxALL | wxEXPAND, 5);
    pGSizer->Add(m_pServiceChargeCtrl = new wxTextCtrl(pPanel,
                                                       idServiceChargeCtrl,
                                                       _(""),
                                                       wxDefaultPosition,
                                                       wxDefaultSize,
                                                       0,
                                                       wxTextValidator(wxFILTER_NUMERIC,
                                                                       &BalanceInfo.ServiceCharge) ),
                 2, wxALIGN_CENTER | wxALL | wxEXPAND, 5);

    pGSizer->Add(m_pInterestPaidBtn = new wxCheckBox(pPanel,
                                                     idInterestPaidBtn,
                                                     _("Interest Paid Amount"),
                                                     wxDefaultPosition,
                                                     wxDefaultSize),
                 3, wxALIGN_CENTER | wxALL | wxEXPAND, 5);
    pGSizer->Add(m_pInterestPaidCtrl = new wxTextCtrl(pPanel,
                                                      idInterestPaidCtrl,
                                                      _(""),
                                                      wxDefaultPosition,
                                                      wxDefaultSize,
                                                      0,
                                                      wxTextValidator(wxFILTER_NUMERIC,
                                                                      &BalanceInfo.InterestPaid) ),
                 2, wxALIGN_CENTER | wxALL | wxEXPAND, 5);

    pBtnSizer->AddButton(new wxButton(pPanel, wxID_OK, _("Continue") ) );
    pBtnSizer->AddButton(new wxButton(pPanel, wxID_CANCEL, _("Cancel") ) );
    pBtnSizer->Realize();

    // put everything together
    pVSizer->Add(pHeaderTxt, 3, wxALIGN_CENTER | wxALL | wxEXPAND, 10);
    pVSizer->AddStretchSpacer(1);
    pVSizer->Add(pGSizer, 11, wxALIGN_CENTER | wxALL | wxEXPAND, 10);
    pVSizer->Add(new wxStaticLine(pPanel), 0, wxALIGN_CENTER | wxALL | wxEXPAND, 5);
    pVSizer->Add(pBtnSizer, 2, wxALIGN_CENTER | wxALL | wxEXPAND, 10);
    pPanel->SetSizer(pVSizer);

    wxBoxSizer* pHSizer = new wxBoxSizer(wxHORIZONTAL);
    pHSizer->Add(pPanel, 1, wxALIGN_CENTER | wxALL | wxEXPAND, 10);
    SetSizer(pHSizer);

    // the service charge and interest paid text boxes need to be initially disabled
    m_pServiceChargeCtrl->Disable();
    m_pInterestPaidCtrl->Disable();
    m_pServiceChargeBtn->SetValue(false);
    m_pInterestPaidBtn->SetValue(false);

    // connect event handlers
    Connect(wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED,
            wxCommandEventHandler(CBalanceDlg::OnContinue) );
    Connect(wxID_CANCEL, wxEVT_COMMAND_BUTTON_CLICKED,
            wxCommandEventHandler(CBalanceDlg::OnCancel) );
    Connect(idServiceChargeBtn, wxEVT_COMMAND_CHECKBOX_CLICKED,
            wxCommandEventHandler(CBalanceDlg::OnServiceChargeBtnSelected) );
    Connect(idInterestPaidBtn, wxEVT_COMMAND_CHECKBOX_CLICKED,
            wxCommandEventHandler(CBalanceDlg::OnInterestPaidBtnSelected) );


    (FindWindowById(idEndBalanceCtrl, this) )->SetFocus();
    Centre();
}

void CBalanceDlg::OnContinue(wxCommandEvent &event)
{
    // get the data from the controls
    if (Validate() && TransferDataFromWindow() )
    {
        // make sure dollar amount is an accepted value (x.xx)
        m_pBalanceInfo->EndBalance = (m_pEndBalanceCtrl->GetValue() );
        if (!(ace::g_pData->VerifyCorrectAmountFormat(m_pBalanceInfo->EndBalance) ) )
        {
            aceMSGBOX(this, ace::MB_INFO, _("You did not enter a correct dollar amount.\nFormat is x.xx"), NULL);
            return;
        }

        // get the date
        m_pBalanceInfo->EndDate = (m_pEndDateCtrl->GetValue() ).Format(_("%m/%d/%Y") );

        // if service charge is active, verify amount format, else make it 0.00
        if (m_pServiceChargeCtrl->IsEnabled() )
        {
            m_pBalanceInfo->ServiceCharge = (m_pServiceChargeCtrl->GetValue() );
            if (!(ace::g_pData->VerifyCorrectAmountFormat(m_pBalanceInfo->ServiceCharge) ) )
            {
                aceMSGBOX(this, ace::MB_INFO, _("You did not enter a correct dollar amount.\nFormat is x.xx"), NULL);
                return;
            }
            m_pBalanceInfo->IsServiceCharge = true;
        }
        else
        {
            m_pBalanceInfo->IsServiceCharge = false;
            m_pBalanceInfo->ServiceCharge = _("0.00");
        }
        // if interest paid is active, verify amount format, else make it 0.00
        if (m_pInterestPaidCtrl->IsEnabled() )
        {
            m_pBalanceInfo->InterestPaid = (m_pInterestPaidCtrl->GetValue() );
            if (!(ace::g_pData->VerifyCorrectAmountFormat(m_pBalanceInfo->InterestPaid) ) )
            {
                aceMSGBOX(this, ace::MB_INFO, _("You did not enter a correct dollar amount.\nFormat is x.xx"), NULL);
                return;
            }
            m_pBalanceInfo->IsInterestPaid = true;
        }
        else
        {
            m_pBalanceInfo->IsInterestPaid = false;
            m_pBalanceInfo->InterestPaid = _("0.00");
        }
    }
    EndModal(wxOK);
}

void CBalanceDlg::OnCancel(wxCommandEvent &event)
{
    EndModal(wxCANCEL);
}

void CBalanceDlg::OnServiceChargeBtnSelected(wxCommandEvent &event)
{
    const bool val = m_pServiceChargeBtn->GetValue();
    (val) ? m_pServiceChargeCtrl->Enable() : m_pServiceChargeCtrl->Disable();
}

void CBalanceDlg::OnInterestPaidBtnSelected(wxCommandEvent &event)
{
    const bool val = m_pInterestPaidBtn->GetValue();
    (val) ? m_pInterestPaidCtrl->Enable() : m_pInterestPaidCtrl->Disable();
}



///** class : CBalancePanel *************************************************///



CBalancePanel::CBalancePanel(wxWindow* pParent, CAccountBase* pAccount, SBalanceInfo& BalanceInfo)
: wxPanel(pParent, wxID_ANY), m_pParent(pParent), m_pAccount(pAccount),
  m_pBalanceInfo(&BalanceInfo), m_ClearedAmount(0.00f)
{
    // set up controls
    wxBoxSizer* pHSizer1 = new wxBoxSizer(wxHORIZONTAL);
    pHSizer1->AddStretchSpacer(1);
    pHSizer1->Add(new wxStaticText(this, wxID_ANY, _("Balance Account") ),
                  3, wxALIGN_CENTER | wxLEFT | wxRIGHT | wxEXPAND, 15);
    pHSizer1->AddStretchSpacer(1);

    wxBoxSizer* pHSizer2 = new wxBoxSizer(wxHORIZONTAL);
    pHSizer2->Add(new wxStaticText(this, wxID_ANY, _("Statement Date") ),
                  3, wxALIGN_CENTER | wxLEFT | wxRIGHT | wxEXPAND, 15);
    pHSizer2->AddStretchSpacer(1);
    pHSizer2->Add(new wxTextCtrl(this,
                                 idStatementDateCtrl,
                                 _(""),
                                 wxDefaultPosition,
                                 wxDefaultSize,
                                 wxTE_READONLY,
                                 wxTextValidator(wxFILTER_ASCII,
                                                 &BalanceInfo.EndDate) ),
                  2, wxALIGN_CENTER | wxLEFT | wxRIGHT | wxEXPAND, 15);

    wxBoxSizer* pHSizer3 = new wxBoxSizer(wxHORIZONTAL);
    pHSizer3->Add(new wxStaticText(this, wxID_ANY, _("Statement Balance") ),
                  3, wxALIGN_CENTER | wxLEFT | wxRIGHT | wxEXPAND, 15);
    pHSizer3->AddStretchSpacer(1);
    pHSizer3->Add(new wxTextCtrl(this,
                                 idStatementBalanceCtrl,
                                 _(""),
                                 wxDefaultPosition,
                                 wxDefaultSize,
                                 wxTE_READONLY | wxTE_RIGHT,
                                 wxTextValidator(wxFILTER_ASCII,
                                                 &BalanceInfo.EndBalance) ),
                  2, wxALIGN_CENTER | wxLEFT | wxRIGHT | wxEXPAND, 15);

    wxBoxSizer* pHSizer4 = new wxBoxSizer(wxHORIZONTAL);
    pHSizer4->Add(new wxStaticText(this, wxID_ANY, _("Transactions Cleared") ),
                  3, wxALIGN_CENTER | wxLEFT | wxRIGHT | wxEXPAND, 15);
    pHSizer4->Add(m_pClearedTransactionsCtrl = new wxTextCtrl(this,
                                                              idClearedTransactionsCtrl,
                                                              _(""),
                                                              wxDefaultPosition,
                                                              wxDefaultSize,
                                                              wxTE_READONLY | wxTE_RIGHT),
                  1, wxALIGN_CENTER | wxLEFT | wxRIGHT | wxEXPAND, 15);
    pHSizer4->Add(m_pClearedAmountCtrl = new wxTextCtrl(this,
                                                        idClearedAmountCtrl,
                                                        _(""),
                                                        wxDefaultPosition,
                                                        wxDefaultSize,
                                                        wxTE_READONLY | wxTE_RIGHT),
                  2, wxALIGN_CENTER | wxLEFT | wxRIGHT | wxEXPAND, 15);

    wxBoxSizer* pHSizer5 = new wxBoxSizer(wxHORIZONTAL);
    pHSizer5->Add(new wxStaticText(this, wxID_ANY, _("Difference") ),
                  3, wxALIGN_CENTER | wxLEFT | wxRIGHT | wxEXPAND, 15);
    pHSizer5->AddStretchSpacer(1);
    pHSizer5->Add(m_pDifferenceCtrl = new wxTextCtrl(this,
                                                     idDifferenceCtrl,
                                                     _(""),
                                                     wxDefaultPosition,
                                                     wxDefaultSize,
                                                     wxTE_READONLY | wxTE_RIGHT),
                  2, wxALIGN_CENTER | wxLEFT | wxRIGHT | wxEXPAND, 15);

    wxStdDialogButtonSizer* pBtnSizer = new wxStdDialogButtonSizer();
    pBtnSizer->AddButton(new wxButton(this, wxID_OK, _("Finish") ) );
    pBtnSizer->AddButton(new wxButton(this, wxID_CANCEL, _("Cancel") ) );
    pBtnSizer->Realize();

    wxBoxSizer* pVSizer = new wxBoxSizer(wxVERTICAL);
    pVSizer->Add(pHSizer1, 1, wxALIGN_CENTER | wxTOP | wxBOTTOM | wxEXPAND, 5);
    pVSizer->Add(pHSizer2, 1, wxALIGN_CENTER | wxTOP | wxBOTTOM | wxEXPAND, 5);
    pVSizer->Add(pHSizer3, 1, wxALIGN_CENTER | wxTOP | wxBOTTOM | wxEXPAND, 5);
    pVSizer->Add(pHSizer4, 1, wxALIGN_CENTER | wxTOP | wxBOTTOM | wxEXPAND, 5);
    pVSizer->Add(pHSizer5, 1, wxALIGN_CENTER | wxTOP | wxBOTTOM | wxEXPAND, 5);
    pVSizer->Add(new wxStaticLine(this), 0, wxALIGN_CENTER | wxTOP | wxBOTTOM | wxEXPAND, 5);
    pVSizer->Add(pBtnSizer, 1, wxALIGN_CENTER | wxTOP | wxBOTTOM | wxEXPAND, 5);

    SetSizer(pVSizer);

    // if there was a service charge entered then save that transaction
    if (BalanceInfo.IsServiceCharge)
    {
        double ServiceCharge = 0.00f;
        BalanceInfo.ServiceCharge.ToDouble(&ServiceCharge);
        STransaction Transaction =
        {
            m_pAccount->GetNextTransactionNumber(),
            0,
            m_pAccount->GetAccountName(),
            _(""),
            NULL,
            BalanceInfo.EndDate,
            TT_DEBIT,
            0,
            _("Service Charge"),
            ServiceCharge,
            _("Bank Charges"),
            _("Service Charge"),
            _(" "),
            TS_CLEARED,
            false,
            0.00f
        };
        m_pAccount->SaveTransaction(Transaction);
    }

    // if there was interest paid entered then save that transaction
    if (BalanceInfo.IsInterestPaid)
    {
        double InterestPaid = 0.00f;
        BalanceInfo.InterestPaid.ToDouble(&InterestPaid);
        STransaction Transaction =
        {
            m_pAccount->GetNextTransactionNumber(),
            0,
            m_pAccount->GetAccountName(),
            _(""),
            NULL,
            BalanceInfo.EndDate,
            TT_DEPOSIT,
            0,
            _("Interest Paid"),
            InterestPaid,
            _("Other Income"),
            _("Interest Paid"),
            _(" "),
            TS_CLEARED,
            true,
            0.00f
        };
        m_pAccount->SaveTransaction(Transaction);
    }

    // get the starting balance
    m_ClearedAmount = (m_pAccount->GetAccountInfo() ).LastStatementBalance;

    // get the number of cleared transactions and the cleared balance
    m_ClearedTransactions = 0;
    m_pAccount->ResetTransactionCounter();
    while (m_pAccount->HasMoreTransactions() )
    {
        STransaction Transaction = m_pAccount->GetNextTransaction();
        if (Transaction.Status == TS_CLEARED)
        {
            m_ClearedTransactions++;
            (Transaction.IsDeposit) ? m_ClearedAmount += Transaction.Amount : m_ClearedAmount -= Transaction.Amount;
        }
    }

    // get the statement and difference balance
    BalanceInfo.EndBalance.ToDouble(&m_StatementBalance);
    m_Difference =  m_ClearedAmount - m_StatementBalance;

    // move data to the controls
    TransferDataToWindow();
    m_pDifferenceCtrl->ChangeValue(wxString::Format(_("%1.2f"), m_Difference) );
    m_pClearedTransactionsCtrl->ChangeValue(wxString::Format(_("%u"), m_ClearedTransactions) );
    m_pClearedAmountCtrl->ChangeValue(wxString::Format(_("%1.2f"), m_ClearedAmount) );

    // connect event handlers
    Connect(wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED,
            wxCommandEventHandler(CBalancePanel::OnFinish) );
    Connect(wxID_CANCEL, wxEVT_COMMAND_BUTTON_CLICKED,
            wxCommandEventHandler(CBalancePanel::OnCancel) );
}

void CBalancePanel::UpdateBalancingStatus(const double Amount, const bool IsDeposit, const bool IsCleared, const bool IsEdit)
{
    if (IsCleared)
    {
        (IsDeposit) ? m_ClearedAmount += Amount : m_ClearedAmount -= Amount;
        if (!IsEdit) m_ClearedTransactions++;
    }
    else
    {
        wxASSERT_MSG(m_ClearedTransactions >= 0, _("Number of cleared transactions less than 0") );
        (IsDeposit) ? m_ClearedAmount -= Amount : m_ClearedAmount += Amount;
        if (!IsEdit) m_ClearedTransactions--;
    }
    m_Difference = m_ClearedAmount - m_StatementBalance;
    m_pDifferenceCtrl->ChangeValue(wxString::Format(_("%1.2f"), m_Difference) );
    m_pClearedTransactionsCtrl->ChangeValue(wxString::Format(_("%u"), m_ClearedTransactions) );
    m_pClearedAmountCtrl->ChangeValue(wxString::Format(_("%1.2f"), m_ClearedAmount) );
}

void CBalancePanel::OnFinish(wxCommandEvent &event)
{
    if (m_Difference > 0.01f || m_Difference < -0.01f)
    {
        wxString msg = (_("Your account is not balanced yet!\n") );
        msg += wxString::Format(_("You still have a difference of %1.2f\n"), m_Difference);
        msg += _("Do you want to continue?");
        if (aceMSGBOX(this, ace::MB_QUESTION, msg, NULL) == wxID_NO)
        {
            m_pAccount->StopBalancing();
        }
        return;
    }
    m_pAccount->BalancingAccountFinished(m_pBalanceInfo->EndDate);
    aceMSGBOX(this, ace::MB_INFO, _("Your account has been successfully balanced!"), NULL);
}

void CBalancePanel::OnCancel(wxCommandEvent &event)
{
    m_pAccount->StopBalancing();
}


