/*
  Copyright 2010-2012 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 
#include 
#include 
#include 
#include "User.hpp"
User::User(Database* db) : _db(db)
{
    _preferences["operation_order"] = "ASC" ;
    _preferences["account_limit_value"] = "200";
    _preferences["account_limit_color_r"] = "240";
    _preferences["account_limit_color_g"] = "195";
    _preferences["account_limit_color_b"] = "0";
}
User::~User()
{
    InvalidateOperations();
}
void User::InvalidateOperations()
{
    std::map >* >::iterator it;
    std::vector::iterator it2;
    int i;
    for (it = _operations.begin(); it != _operations.end(); it++)
    {
        if (_operations[it->first])
	{
            delete it->second;
	}
    }
    _operations.clear();
    std::sort(_accounts.begin(), _accounts.end(), Account());
    std::sort(_categories.begin(), _categories.end(), Category());
    for (i=0, it2=_categories.begin(); it2 !=_categories.end(); it2++, i++)
    {
	_categoriesFonts[i] = KissCount::ExtractFont(it2->font);
    }
}
Category User::GetCategory(int catId)
{
    Category cat;
    std::vector::iterator it = std::find(_categories.begin(), _categories.end(), catId);
    if (it !=_categories.end()) return *it;
    if (_db->LoadCategory(catId, "", cat))
	return cat;
    cat.id = 0;
    cat.parent = 0;
    cat.name = _("Unknown");
    cat.font = "";
    cat.backcolor = view::OWN_GREEN;
    cat.forecolor = Qt::black;
    return cat;
}
QString User::GetCategoryName(int catId)
{
    Category cat;
    std::vector::iterator it = std::find(_categories.begin(), _categories.end(), catId);
    if (it !=_categories.end()) return it->name;
    if (_db->LoadCategory(catId, "", cat))
	return cat.name;
    return _("Unknown") ;
}
int User::GetCategoryId(const QString& catName) /*throw (CategoryNotFound)*/
{
    std::vector::iterator it;
    Category cat;
    for (it=_categories.begin(); it !=_categories.end(); it++)
        if (_(it->name.toStdString().c_str()) == catName)
            return it->id;
    if ( _db->LoadCategory(0, catName, cat))
	return cat.id;
    throw CategoryNotFound();
}
const QFont User::GetCategoryFont(int catId)
{
    DEFAULT_FONT(f);
    Category cat;
    for (unsigned int i=0; i<_categories.size(); i++)
        if (_categories[i].id == catId)
            return _categoriesFonts[i];
    if (_db->LoadCategory(catId, "", cat))
	return KissCount::ExtractFont(cat.font);
    return f;
}
void User::AddCategory(const Category& cat)
{
    _categories.push_back(cat);
    _categoriesFonts.push_back(KissCount::ExtractFont(""));
}
void User::UpdateCategory(const Category& cat)
{
    std::vector::iterator it = std::find(_categories.begin(), _categories.end(), cat.id);
    if (it !=_categories.end())
    {
	*it = cat;
	_categoriesFonts[it-_categories.begin()] = KissCount::ExtractFont(cat.font);
    }
}
void User::DeleteCategory(const Category& cat)
{
    std::vector::iterator it = std::find(_categories.begin(), _categories.end(), cat.id);
    if (it !=_categories.end())
    {
	int pos = it - _categories.begin();
	_categories.erase(_categories.begin()+pos);
	_categoriesFonts.erase(_categoriesFonts.begin()+pos);
    }
}
Tag User::GetTag(int tagId)
{
    Tag tag;
    std::vector::iterator it = std::find(_tags.begin(), _tags.end(), tagId);
    if (it !=_tags.end()) return *it;
    if (_db->LoadTag(tagId, "", tag))
	return tag;
    tag.id = 0;
    tag.name = "";
    return tag;
}
QString User::GetTagName(int tagId)
{
    Tag tag;
    std::vector::iterator it = std::find(_tags.begin(), _tags.end(), tagId);
    if (it !=_tags.end()) return it->name;
    if (_db->LoadTag(tagId, "", tag))
	return tag.name;
    return _("Unknown") ;
}
int User::GetTagId(const QString& tagName) /*throw (TagNotFound)*/
{
    std::vector::iterator it;
    Tag tag;
    for (it=_tags.begin(); it !=_tags.end(); it++)
        if (_(it->name.toStdString().c_str()) == tagName)
            return it->id;
    if ( _db->LoadTag(0, tagName, tag))
	return tag.id;
    throw TagNotFound();
}
void User::AddTag(const Tag& tag)
{
    _tags.push_back(tag);
}
void User::UpdateTag(const Tag& tag)
{
    std::vector::iterator it = std::find(_tags.begin(), _tags.end(), tag.id);
    if (it !=_tags.end())
    {
	*it = tag;
    }
}
void User::DeleteTag(const Tag& tag)
{
    std::vector::iterator it = std::find(_tags.begin(), _tags.end(), tag.id);
    if (it !=_tags.end())
    {
	int pos = it - _tags.begin();
	_tags.erase(_tags.begin()+pos);
    }
}
Account User::GetAccount(int accountId) /*throw (AccountNotFound)*/
{
    std::vector::iterator it = std::find(_accounts.begin(), _accounts.end(), accountId);
    
    if (it != _accounts.end())
	return *it;
    
    throw AccountNotFound();
}
QString User::GetAccountName(int accountId)
{
    std::vector::iterator it = std::find(_accounts.begin(), _accounts.end(), accountId);
    if (it != _accounts.end()) return it->name;
    return _("Unknown") ;
}
int User::GetAccountId(const QString& accountName) /*throw (AccountNotFound)*/
{
    std::vector::iterator it;
    for (it=_accounts.begin(); it !=_accounts.end(); it++)
        if (it->name == accountName)
            return it->id;
    throw AccountNotFound();
}
int User::GetAccountIdFromAccountNumber(const QString& accountNumber) /*throw (AccountNotFound)*/
{
    std::vector::iterator it;
    for (it=_accounts.begin(); it !=_accounts.end(); it++)
        if (it->number == accountNumber)
            return it->id;
    throw AccountNotFound();
}
void User::AddAccount(Account& ac)
{
    _accounts.push_back(ac);
}
void User::UpdateAccount(Account& ac)
{
    std::vector::iterator it = std::find(_accounts.begin(), _accounts.end(), ac.id);
    if (it != _accounts.end())
	*it = ac;
}
void User::DeleteAccount(Account& ac)
{
    std::vector::iterator it = std::find(_accounts.begin(), _accounts.end(), ac.id);
    if (it != _accounts.end())
	_accounts.erase(it);
}
int User::GetCategoriesNumber()
{
    return _categories.size();
}
int User::GetTagsNumber()
{
    return _tags.size();
}
int User::GetAccountsNumber()
{
    return _accounts.size();
}
int User::GetOperationsNumber(int month, int year)
{
    return (*_operations[year])[month].size();
}
QString User::GetLanguage()
{
    return _preferences["language"];
    // long val;
    // if (!res.Length())
    //     return wxLANGUAGE_ENGLISH ;
  
    // res.ToLong(&val);
  
    // return (wxLanguage)val;
}
void User::SetLanguage(QString language)
{
    _preferences["language"] = language;
    _db->UpdatePreference(this, "language");
}
void User::SetAccountLimitValue(int limit)
{
    _preferences["account_limit_value"] = QString::number(limit);
    _db->UpdatePreference(this, "account_limit_value");
}
void User::SetAccountLimitColor(QColor& color)
{
    _preferences["account_limit_color_r"] = QString::number(color.red());
    _preferences["account_limit_color_g"] = QString::number(color.green());
    _preferences["account_limit_color_b"] = QString::number(color.blue());
    _db->UpdatePreference(this, "account_limit_color_r");
    _db->UpdatePreference(this, "account_limit_color_g");
    _db->UpdatePreference(this, "account_limit_color_b");
}
int User::GetAccountLimitValue(void)
{
    return _preferences["account_limit_value"].toInt();
}
QColor User::GetAccountLimitColor(void)
{
    int r = _preferences["account_limit_color_r"].toInt();
    int g = _preferences["account_limit_color_g"].toInt();
    int b = _preferences["account_limit_color_b"].toInt();
    return QColor(r,g,b);
}
void User::LinkOrUnlinkOperation(Operation& op)
{
    std::vector::iterator it;
    Account account, account2;
    if (!_operations[op.year])
	_db->LoadYear(this, op.year);
    if (!_operations[op.year])
	return;
    // Not Linked
    if (!op.transfert)
    {
        for (it = (*_operations[op.year])[op.month].begin(); it != (*_operations[op.year])[op.month].end(); it++)
	{
            if (it->id != op.id && it->transfert == op.id)
	    {
                it->transfert = 0;
		it->_virtual = false;
                return;
	    }
	}
    }
    // Linked
    else
    {
        for (it = (*_operations[op.year])[op.month].begin(); it != (*_operations[op.year])[op.month].end(); it++)
	{
            if (it->id != op.id && it->id == op.transfert)
	    {
		account = GetAccount(it->account);
		account2 = GetAccount(op.account);
                it->transfert = op.id;
		it->_virtual = account._virtual || account2._virtual;
		op._virtual = account._virtual || account2._virtual;
                return;
	    }
	}
        op.transfert = 0;
	op._virtual = false;
    }
}
bool User::Group(std::vector* ops, const Operation& op)
{
    std::vector::iterator it;
    std::vector::iterator it2;
    for (it = ops->begin(); it != ops->end(); it++)
    {
        if (it->id == op.parent)
	{
	    it2 = std::find(it->childs.begin(), it->childs.end(), op.id);
            if (it2 == it->childs.end())
		it->childs.push_back(op.id);
	    return true;
	}
    }
    return false ;
}
void User::Group(const Operation& op)
{
    std::vector::iterator it;
    if (!Group(&(*_operations[op.year])[op.month], op)
	&& _db->LoadOperation(this, op.parent))
    {
	it = std::find ((*_operations[op.year])[op.month].begin(), (*_operations[op.year])[op.month].end(), op.parent);
	if (it != (*_operations[op.year])[op.month].end())
	    it->childs.push_back(op.id);
    }
}
void User::UnGroup(const Operation& op)
{
    std::vector::iterator it;
    std::vector::iterator it2;
    for (it = (*_operations[op.year])[op.month].begin(); it != (*_operations[op.year])[op.month].end(); it++)
    {
        if (it->id == op.parent)
	{
	    for (it2 = it->childs.begin(); it2 != it->childs.end(); it2++)
		if (*it2 == op.id)
		{
		    it->childs.erase(it2);
		    return;
		}
	}
    }
}
void User::ResolveGroups(int year)
{
    unsigned int i;
    std::map >::iterator it;
    for (it = _operations[year]->begin(); it != _operations[year]->end(); it++)
    {
	for (i=0; isecond.size(); i++)
	    if (it->second[i].parent)
		Group(((*_operations[year])[it->first])[i]);
    }
}