/*
Copyright 2010-2011 Grégory Soutadé
This file is part of KissCount.
KissCount 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.
KissCount 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 KissCount. If not, see .
*/
#include "KissCount.h"
std::vector KissCount::_importEngines;
KissCount::KissCount(const char* bdd_filename) : _user(NULL)
{
wxRect rect = wxDisplay().GetGeometry();
_wxUI = new wxUI(this, wxT("KissCount"), wxPoint(50, 50), wxSize(rect.width-rect.x, rect.height-rect.y));
_wxUI->SetLanguage(wxLocale::GetSystemLanguage());
_wxUI->Show(true);
_wxUI->Centre();
_wxUI->Disable();
try
{
_db = new Database(bdd_filename, this);
}
catch (std::string s)
{
_wxUI->Close(true);
throw s;
}
_wxUI->ChangeUser();
_wxUI->Enable();
}
KissCount::~KissCount()
{
delete _db;
delete _wxUI;
if (_user) delete _user;
}
std::list KissCount::GetUsers()
{
return _db->GetUsers();
}
bool KissCount::IsValidUser(const wxString& user, const wxString& password)
{
return _db->IsValidUser(user, password) ;
}
void KissCount::LoadUser(const wxString& user)
{
if (_user) delete _user;
_user = _db->LoadUser(user) ;
if (_user)
_wxUI->LoadUser();
}
void KissCount::LoadYear(int year, bool force)
{
if (!force && _user->_operations[year] != NULL) return;
if (_user->_operations[year] != NULL)
{
delete _user->_operations[year];
_user->_operations[year] = NULL;
}
_db->LoadYear(_user, year);
}
User* KissCount::GetUser()
{
return _user;
}
double KissCount::GetAccountAmount(const wxString& id, int month, int year)
{
return _db->GetAccountAmount(id, month, year);
}
double KissCount::CalcAccountAmount(const wxString& id, int month, int year, bool* had_values)
{
return _db->CalcAccountAmount(id, month, year, had_values);
}
void KissCount::UpdateOperation(Operation& op)
{
// Unlink
op.transfert = wxT("");
_user->LinkOrUnlinkOperation(op);
_db->UpdateOperation(_user, op);
// Link
_user->LinkOrUnlinkOperation(op);
}
wxString KissCount::AddOperation(Operation& op)
{
wxString ret = _db->AddOperation(_user, op);
if (op.transfert.Length())
_user->LinkOrUnlinkOperation(op);
return ret;
}
void KissCount::DeleteOperation(Operation& op)
{
if (op.transfert.Length())
{
op.transfert = wxT("");
_user->LinkOrUnlinkOperation(op);
}
_db->DeleteOperation(_user, op);
}
void KissCount::DeleteOperations(int month, int year)
{
_db->DeleteOperations(_user, month, year);
if (month != -1)
(*_user->_operations[year]).erase(month);
if (month == -1 || !_user->_operations[year]->size())
{
delete _user->_operations[year];
_user->_operations.erase(year);
}
}
double KissCount::MetaAmount(const wxString& id)
{
return _db->MetaAmount(id);
}
double KissCount::MetaPositiveAmount(const wxString& id)
{
return _db->MetaPositiveAmount(id);
}
void KissCount::SetAccountAmount(int month, int year, const wxString& accountId, double amount)
{
_db->SetAccountAmount(month, year, accountId, amount);
}
wxString KissCount::AddAccount(Account& ac)
{
wxDateTime curDate;
ac.id = _db->AddAccount(_user, ac);
_user->_accounts.push_back(ac);
curDate.SetToCurrent();
SetAccountAmount((int)curDate.GetMonth(), curDate.GetYear(), ac.id, 0.0);
return ac.id;
}
void KissCount::UpdateAccount(Account& ac)
{
std::vector::iterator it;
int i;
_db->UpdateAccount(ac);
for (i=0, it=_user->_accounts.begin(); it !=_user->_accounts.end(); it++, i++)
if (it->id == ac.id)
_user->_accounts[i] = ac;
if (ac._default)
std::sort(_user->_accounts.begin(), _user->_accounts.end(), sortAccounts);
}
void KissCount::DeleteAccount(Account& ac, const wxString& replacement)
{
std::vector::iterator it;
int i;
std::map >* >::iterator it2;
_db->DeleteAccount(_user, ac, replacement);
for (i=0, it=_user->_accounts.begin(); it !=_user->_accounts.end(); it++, i++)
if (it->id == ac.id)
{
_user->_accounts.erase(_user->_accounts.begin()+i);
break;
}
for (it2= _user->_operations.begin();
it2 != _user->_operations.end();
it2++)
LoadYear(it2->first, true);
}
void KissCount::AddSharedAccount(Account& ac, const wxString& granted)
{
_db->AddSharedAccount(ac, granted);
}
void KissCount::RemoveSharedAccount(Account& ac, const wxString& granted)
{
_db->RemoveSharedAccount(ac, granted);
}
std::map KissCount::getSharedAccountOwners(const wxString& account)
{
return _db->getSharedAccountOwners(account);
}
wxString KissCount::getSharedAccountOwner(const wxString& account)
{
return _db->getSharedAccountOwner(account);
}
wxString KissCount::AddCategory(Category& category)
{
wxString id;
id = _db->AddCategory(_user, category);
category.id = id;
_user->_categories.push_back(category);
_user->_categoriesFonts.push_back(ExtractFont(wxT("")));
return id;
}
void KissCount::UpdateCategory(Category& category)
{
_db->UpdateCategory(category);
for (int i=0; i<_user->GetCategoriesNumber();i++)
if (_user->_categories[i].id == category.id)
{
_user->_categories[i] = category;
_user->_categoriesFonts[i] = ExtractFont(category.font);
break;
}
}
void KissCount::DeleteCategory(Category& category, const wxString& replacement)
{
std::map >* >::iterator it;
_db->DeleteCategory(_user, category, replacement);
for (int i=0; i<_user->GetCategoriesNumber();i++)
if (_user->_categories[i].id == category.id)
{
_user->_categories.erase(_user->_categories.begin()+i);
_user->_categoriesFonts.erase(_user->_categoriesFonts.begin()+i);
break;
}
for (it= _user->_operations.begin();
it != _user->_operations.end();
it++)
LoadYear(it->first, true);
}
std::map > KissCount::GetAllOperations()
{
return _db->GetAllOperations(_user);
}
void KissCount::GenerateMonth(int monthFrom, int yearFrom, int monthTo, int yearTo)
{
std::vector::iterator it, it2;
std::map meta;
Operation op;
_db->GenerateMonth(_user, monthFrom, yearFrom, monthTo, yearTo);
if (!_user->_operations[yearTo])
_user->_operations[yearTo] = new std::map >();
if (monthFrom != -1 && yearFrom != -1)
{
LoadYear(yearFrom, false);
for(it = (*_user->_operations[yearFrom])[monthFrom].begin();
it != (*_user->_operations[yearFrom])[monthFrom].end();
it++)
{
if (!it->fix_cost) continue;
op = *it;
op.month = monthTo;
op.year = yearTo;
op.checked = false;
op.id = AddOperation(op);
op.childs.clear();
op._virtual = false;
if (op.meta)
meta[it->id] = op.id;
(*_user->_operations[yearTo])[monthTo].push_back(op);
}
// Re Generate parents
for(it = (*_user->_operations[yearTo])[monthTo].begin();
it != (*_user->_operations[yearTo])[monthTo].end();
it++)
{
if (it->parent.Length())
{
it->parent = meta[it->parent];
UpdateOperation(*it);
for(it2 = (*_user->_operations[yearTo])[monthTo].begin();
it2 != (*_user->_operations[yearTo])[monthTo].end();
it2++)
if (it2->id == it->parent)
{
it2->childs.push_back(it->id);
break;
}
}
}
}
_wxUI->GenerateMonth(monthTo, yearTo);
}
void KissCount::ChangePassword(const wxString& password)
{
_db->ChangePassword(_user, password);
}
bool KissCount::UserExists(const wxString& name)
{
return _db->UserExists(name);
}
void KissCount::ChangeName(const wxString& name)
{
_db->ChangeName(_user, name);
_user->_name = name;
}
// To enable translation during xgettext
wxString default_cats[] = {
_("Fix"), _("Groceries"), _("Hobbies"), _("Car"),
_("Unexpected"), _("Other")
};
void KissCount::NewUser(const wxString& name)
{
wxDateTime curDate;
Account ac = {
/*.id = */wxT(""),
/*.name = */_("Account 1"),
/*.number = */wxT(""),
/*.shared = */false,
/*.blocked = */false,
/*._default = */true,
/*.is_owner = */true};
Category cat ;
_db->NewUser(name);
if (_user) delete _user;
_user = _db->LoadUser(name) ;
curDate.SetToCurrent();
AddAccount(ac);
cat.parent = wxT("0") ; cat.name = wxT("Fix") ; cat.backcolor = OWN_YELLOW ; cat.forecolor = *wxBLACK; cat.fix_cost = true;
AddCategory(cat);
cat.parent = wxT("0") ; cat.name = wxT("Groceries") ; cat.backcolor = OWN_GREEN; cat.forecolor = *wxBLACK; cat.fix_cost = false;
AddCategory(cat);
cat.parent = wxT("0") ; cat.name = wxT("Hobbies") ; cat.backcolor = OWN_GREEN; cat.forecolor = *wxBLACK; cat.fix_cost = false;
AddCategory(cat);
cat.parent = wxT("0") ; cat.name = wxT("Car") ; cat.backcolor = OWN_GREEN; cat.forecolor = *wxBLACK; cat.fix_cost = false;
AddCategory(cat);
cat.parent = wxT("0") ; cat.name = wxT("Unexpected") ; cat.backcolor = OWN_GREEN; cat.forecolor = *wxBLACK; cat.fix_cost = false;
AddCategory(cat);
cat.parent = wxT("0") ; cat.name = wxT("Other") ; cat.backcolor = OWN_GREEN; cat.forecolor = *wxBLACK; cat.fix_cost = false;
AddCategory(cat);
SetOperationOrder(wxT("ASC"));
_db->GenerateMonth(_user, -1, -1, (int)curDate.GetMonth(), curDate.GetYear());
}
void KissCount::KillMe()
{
_wxUI->KillMe();
_db->KillMe(_user);
delete _user;
_user = NULL;
_wxUI->ChangeUser();
}
void KissCount::SetLanguage(wxLanguage language)
{
_user->_preferences[wxT("language")] = wxString::Format(wxT("%d"), language) ;
_db->UpdatePreference(_user, wxT("language"));
}
/*
ASC (default) or DESC
*/
void KissCount::SetOperationOrder(const wxString& order)
{
_user->_preferences[wxT("operation_order")] = order;
_db->UpdatePreference(_user, wxT("operation_order"));
}
const wxString& KissCount::GetOperationOrder()
{
return _user->_preferences[wxT("operation_order")] ;
}
std::vector* KissCount::Search(wxString* description, wxDateTime* dateFrom, wxDateTime* dateTo,
wxString* amountFrom, wxString* amountTo,
std::vector categories, int types, std::vector accounts)
{
return _db->Search(_user, description, dateFrom, dateTo, amountFrom, amountTo, categories, types, accounts, true);
}
bool KissCount::SearchPreviousOperation(Operation* res, Operation& op, int month, int year, bool limitToType)
{
std::vector* operations;
wxDateTime* date ;
//wxDateSpan threeMonths(0, 3); Not working :(
std::vector v;
int i;
month -= 3;
if (month < 0)
{
year -= 1;
month += 12;
}
date = new wxDateTime(0, (wxDateTime::Month)month, year);
if (limitToType)
operations = _db->Search(_user, &op.description, date, NULL, NULL, NULL, v, op.fix_cost ? FIX_OP : NON_FIX_OP, v, false);
else
operations = _db->Search(_user, &op.description, date, NULL, NULL, NULL, v, ALL_OP, v, false);
delete date;
if (!operations->size())
{
delete operations;
return false;
}
for(i=operations->size()-1; i>=0; i--)
if (!(*operations)[i].meta)
{
*res = (*operations)[i];
delete operations;
return true;
}
delete operations;
return false;
}
void KissCount::GetStats(int monthFrom, int yearFrom, int monthTo, int yearTo,
std::map > >* accountAmounts,
std::map* categories)
{
wxString monthF = wxString::Format(wxT("%d"), monthFrom);
wxString monthT = wxString::Format(wxT("%d"), monthTo);
wxString yearF = wxString::Format(wxT("%d"), yearFrom);
wxString yearT = wxString::Format(wxT("%d"), yearTo);
_db->GetStats(_user, monthF, yearF, monthT, yearT, accountAmounts, categories);
}
void KissCount::GetMonthStats(int month, int year, int nbDays,
std::map >* operations,
std::map* categories)
{
wxString monthS = wxString::Format(wxT("%d"), month);
wxString yearS = wxString::Format(wxT("%d"), year);
_db->GetMonthStats(_user, monthS, yearS, nbDays, operations, categories);
}
std::map* KissCount::GetNotChecked(int month, int year)
{
return _db->GetNotChecked(_user, month, year);
}
std::map* KissCount::GetVirtualAmount(int month, int year)
{
return _db->GetVirtualAmount(_user, month, year);
}
wxFont KissCount::ExtractFont(wxString strFont)
{
long int pos, pointSize, family, style, weight;
wxString faceName;
if (!strFont.Length())
{
DEFAULT_FONT(f);
return f;
}
pos = strFont.Find(wxT(";"));
if (pos != -1)
{
strFont.SubString(0, pos).ToLong(&pointSize);
strFont = strFont.SubString(pos+1, strFont.Length());
}
pos = strFont.Find(wxT(";"));
if (pos != -1)
{
strFont.SubString(0, pos).ToLong(&family);
strFont = strFont.SubString(pos+1, strFont.Length());
}
pos = strFont.Find(wxT(";"));
if (pos != -1)
{
strFont.SubString(0, pos).ToLong(&style);
strFont = strFont.SubString(pos+1, strFont.Length());
}
pos = strFont.Find(wxT(";"));
if (pos != -1)
{
strFont.SubString(0, pos).ToLong(&weight);
strFont = strFont.SubString(pos+1, strFont.Length());
}
faceName = strFont;
return wxFont(pointSize, family, style, weight, false, faceName) ;
}
wxString KissCount::CompactFont(const wxFont& font)
{
wxString res = wxString::Format(wxT("%d;%d;%d;%d;"), font.GetPointSize(), font.GetFamily(), font.GetStyle(), font.GetWeight());
res += font.GetFaceName();
return res;
}
void KissCount::UnRegisterImportEngine(ImportEngine* engine)
{
std::vector::iterator it;
for(it=_importEngines.begin(); it!=_importEngines.end(); it++)
if (*it == engine)
{
_importEngines.erase(it);
break;
}
}
void KissCount::RegisterImportEngine(ImportEngine* engine)
{
_importEngines.push_back(engine);
}
wxString KissCount::GetImportEngineExtensions()
{
wxString res;
std::vector::iterator it;
int i;
for(i=0; i<(int)_importEngines.size()-1; i++)
res = res + _importEngines[i]->GetFileExt() + wxT("|") ;
if (_importEngines.size())
res = res + _importEngines[i]->GetFileExt();
return res;
}
ImportEngine* KissCount::GetImportEngine(wxString path)
{
std::vector::iterator it;
for(it=_importEngines.begin(); it!=_importEngines.end(); it++)
if ((*it)->HandleFile(path, _user, _db, this))
return *it;
return NULL;
}
void KissCount::UpdateImportPattern()
{
_db->UpdateImportPattern(_user);
}