<commit_before>#include "Main.hpp"
using namespace std;

unsigned int Level::levelCounter = 0;
string Level::current = "NULL";
string Level::next = "NULL";
Level::Level(string name)
{
    init(name, true);
}
void Level::init(string name, bool full)
{
	if (name.empty() or (name == "NULL"))
    {
        current = "level9";
        levelCounter = 0;
        menus.push_back(new Menu(MAIN));
    }
    else {current = name;}
    stringstream ss;
    GLfloat x;
    GLfloat y = 0;
    fstream file(("levels/" + current + ".lvl").c_str(), fstream::in);
    string caption;
    if(!REPEAT_LEVEL) {levelCounter++;}
    if(!file.is_open()) {cerr << "Error with loading file: " << strerror(errno) << endl; QUIT = true; return;}
    textures.loadIMG("textures.png");
    getline(file, caption);
    next = caption;
    getline(file, caption);
    ss << "Pertotman, Level " << levelCounter << ": " << caption;
    caption = ss.str();
    SDL_WM_SetCaption(caption.c_str(), "Pertotman");
    for(unsigned int counter = 1; file.eof() == false; counter++)
    {
		x = 0;
		string line;
		file >> line;
		for(unsigned int i = 0; i < line.size(); i++)
		{
			switch (line[i])
			{
				case 'w':
                case 'W':
                 walls.push_back(new Wall(x, y, textures));
                 break;
				case 'c':
                case 'C':
                 if(full){coffees.push_back(new Coffee(x, y, textures));}
                 spaces.push_back(new Space(x, y, textures));
                 break;
				case 'b':
                case 'B':
                 if(full){enemies.push_back(new Enemy(x, y, textures));}
                 spaces.push_back(new Space(x, y, textures));
                 break;
				case 'p':
                case 'P':
                 if(full){pacmans.push_back(new Pacman(x, y, textures));}
                 spaces.push_back(new Space(x, y, textures));
                 break;
				case 's':
                case 'S':
                 spaces.push_back(new Space(x, y, textures));
                 break;
				default:
                 cerr << "Error with loading level: Invalid character." << endl; QUIT = true; return;
                 break;
			}
			x += 32;
		}
		y += 32;
	}
	for (unsigned int i = 0; i < spaces.size(); i++)
	{
		spaces[i]->neighbours(this);
    }
	if (full and(pacmans.size() != 1)) {cerr << "Error with loading level: Too many pacman instances." << endl; QUIT = true; return;}
}
void Level::save() const
{
    size_t unit = sizeof(GLfloat);
    size_t sizeTemp;
    fstream file("savegame.sav", fstream::out | fstream::binary | fstream::trunc);
    if(!file.is_open()) {cerr << "Error with opening file: " << strerror(errno) << endl; QUIT = true; return;}
    file.write(reinterpret_cast<char*>(&unit), sizeof(size_t));
    sizeTemp = sizeof(int);
    file.write(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    file.write(reinterpret_cast<char*>(&levelCounter), sizeTemp);
    sizeTemp = current.size();
    file.write(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    file.write(current.c_str(), sizeTemp);
    sizeTemp = pacmans.size();
    file.write(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    for (unsigned int i = 0; i < pacmans.size(); i++)
        {
            file.write(reinterpret_cast<char*>(&pacmans[i]->x), unit);
            file.write(reinterpret_cast<char*>(&pacmans[i]->y), unit);
        }
    sizeTemp = coffees.size();
    for (unsigned int i = 0; i < coffees.size(); i++)
    {
        if(!coffees[i]->armed){sizeTemp--;}
    }
    file.write(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    for (unsigned int i = 0; i < coffees.size(); i++)
        {
            if(coffees[i]->armed)
            {
                file.write(reinterpret_cast<char*>(&coffees[i]->x), unit);
                file.write(reinterpret_cast<char*>(&coffees[i]->y), unit);
            }
        }
    sizeTemp = enemies.size();
    file.write(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    for (unsigned int i = 0; i < enemies.size(); i++)
        {
            file.write(reinterpret_cast<char*>(&enemies[i]->x), unit);
            file.write(reinterpret_cast<char*>(&enemies[i]->y), unit);
        }
}
void Level::load()
{
    size_t unit = sizeof(GLfloat);
    size_t sizeTemp;
    char lvlName[50];
    GLfloat xTemp, yTemp;
    fstream file("savegame.sav", fstream::in | fstream::binary);
    if(!file.is_open())
    {
        levelCounter = 0;
        init("level1", true);
        return;
    }
    file.read(reinterpret_cast<char*>(&unit), sizeof(size_t));
    file.read(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    file.read(reinterpret_cast<char*>(&levelCounter), sizeTemp);
    levelCounter--;
    file.read(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    file.read(lvlName, sizeTemp);
    lvlName[sizeTemp] = 0;
    init(lvlName, false);
    file.read(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    for (unsigned int i = 0; i < sizeTemp; i++)
        {
            file.read(reinterpret_cast<char*>(&xTemp), unit);
            file.read(reinterpret_cast<char*>(&yTemp), unit);
            pacmans.push_back(new Pacman(xTemp, yTemp, textures));
        }
    file.read(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    for (unsigned int i = 0; i < sizeTemp; i++)
        {
            file.read(reinterpret_cast<char*>(&xTemp), unit);
            file.read(reinterpret_cast<char*>(&yTemp), unit);
            coffees.push_back(new Coffee(xTemp, yTemp, textures));
        }
    file.read(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    for (unsigned int i = 0; i < sizeTemp; i++)
        {
            file.read(reinterpret_cast<char*>(&xTemp), unit);
            file.read(reinterpret_cast<char*>(&yTemp), unit);
            enemies.push_back(new Enemy(xTemp, yTemp, textures));
        }
    menus.push_back(new Menu(ESCAPE));
}
void Level::handle(SDL_Event inputEvent)
{
    if((inputEvent.type == SDL_KEYDOWN) and (inputEvent.key.keysym.sym == SDLK_ESCAPE))
    {
        if (PAUSE == 0)
        {
            PAUSE = -1;
        }
        else
        {
            PAUSE = 0;
        }
        if(menus.empty()) {menus.push_back(new Menu(ESCAPE));}
        else {menus.pop_back();}
    }
    else
    {
        if(menus.size() > 0)
        {
            if(!menus[menus.size() - 1]->handle(inputEvent)) {menus.pop_back();}
        }
        for (unsigned int i = 0; i < pacmans.size(); i++)
        {
            pacmans[i]->handle(inputEvent);
        }
    }
}
void Level::update()
{
    if(menus.empty())
    {
        for (unsigned int i = 0; i < spaces.size(); i++)
        {
            spaces[i]->update();
        }
        for (unsigned int i = 0; i < walls.size(); i++)
        {
            walls[i]->update();
        }
        for (unsigned int i = 0; i < coffees.size(); i++)
        {
            coffees[i]->update();
        }
        for (unsigned int i = 0; i < enemies.size(); i++)
        {
            enemies[i]->update();
        }
        for (unsigned int i = 0; i < pacmans.size(); i++)
        {
            pacmans[i]->update();
        }
    }
}
void Level::render() const
{
	glClear(GL_COLOR_BUFFER_BIT);
	bool bgrender = true;
	if(menus.size() > 0)
    {
        if(menus[0]->type == MAIN) {bgrender = false;}
    }
	if (bgrender)
    {
        for (unsigned int i = 0; i < spaces.size(); i++)
        {
            spaces[i]->render();
        }
        for (unsigned int i = 0; i < walls.size(); i++)
        {
            walls[i]->render();
        }
        for (unsigned int i = 0; i < coffees.size(); i++)
        {
            coffees[i]->render();
        }
        for (unsigned int i = 0; i < enemies.size(); i++)
        {
            enemies[i]->render();
        }
        for (unsigned int i = 0; i < pacmans.size(); i++)
        {
            pacmans[i]->render();
        }
    }
	if(menus.size() > 0) {menus[menus.size() - 1]->render();}
}
void Level::destroy()
{
    for (unsigned int i = 0; i < menus.size(); i++)
	{
		menus.erase(menus.begin() + i);
	}
    for (unsigned int i = 0; i < spaces.size(); i++)
	{
	    spaces.erase(spaces.begin() + i);
	}
	for (unsigned int i = 0; i < walls.size(); i++)
	{
	    walls.erase(walls.begin() + i);
	}
	for (unsigned int i = 0; i < coffees.size(); i++)
	{
	    coffees.erase(coffees.begin() + i);
	}
	for (unsigned int i = 0; i < enemies.size(); i++)
	{
	    enemies.erase(enemies.begin() + i);
	}
	for (unsigned int i = 0; i < pacmans.size(); i++)
	{
	    pacmans.erase(pacmans.begin() + i);
	}
	menus.clear();
	spaces.clear();
	walls.clear();
	coffees.clear();
    enemies.clear();
    pacmans.clear();
    Coffee::count = 0;
}
<commit_msg>Pathfinding for one enemy only<commit_after>#include "Main.hpp"
using namespace std;

unsigned int Level::levelCounter = 0;
string Level::current = "NULL";
string Level::next = "NULL";
Level::Level(string name)
{
    init(name, true);
}
void Level::init(string name, bool full)
{
	if (name.empty() or (name == "NULL"))
    {
        current = "level9";
        levelCounter = 0;
        menus.push_back(new Menu(MAIN));
    }
    else {current = name;}
    stringstream ss;
    GLfloat x;
    GLfloat y = 0;
    fstream file(("levels/" + current + ".lvl").c_str(), fstream::in);
    string caption;
    if(!REPEAT_LEVEL) {levelCounter++;}
    if(!file.is_open()) {cerr << "Error with loading file: " << strerror(errno) << endl; QUIT = true; return;}
    textures.loadIMG("textures.png");
    getline(file, caption);
    next = caption;
    getline(file, caption);
    ss << "Pertotman, Level " << levelCounter << ": " << caption;
    caption = ss.str();
    SDL_WM_SetCaption(caption.c_str(), "Pertotman");
    for(unsigned int counter = 1; file.eof() == false; counter++)
    {
		x = 0;
		string line;
		file >> line;
		for(unsigned int i = 0; i < line.size(); i++)
		{
			switch (line[i])
			{
				case 'w':
                case 'W':
                 walls.push_back(new Wall(x, y, textures));
                 break;
				case 'c':
                case 'C':
                 if(full){coffees.push_back(new Coffee(x, y, textures));}
                 spaces.push_back(new Space(x, y, textures));
                 break;
				case 'b':
                case 'B':
                 if(full){enemies.push_back(new Enemy(x, y, textures));}
                 spaces.push_back(new Space(x, y, textures));
                 break;
				case 'p':
                case 'P':
                 if(full){pacmans.push_back(new Pacman(x, y, textures));}
                 spaces.push_back(new Space(x, y, textures));
                 break;
				case 's':
                case 'S':
                 spaces.push_back(new Space(x, y, textures));
                 break;
				default:
                 cerr << "Error with loading level: Invalid character." << endl; QUIT = true; return;
                 break;
			}
			x += 32;
		}
		y += 32;
	}
	for (unsigned int i = 0; i < spaces.size(); i++)
	{
		spaces[i]->neighbours(this);
    }
	if (full and(pacmans.size() != 1)) {cerr << "Error with loading level: Too many pacman instances." << endl; QUIT = true; return;}
}
void Level::save() const
{
    size_t unit = sizeof(GLfloat);
    size_t sizeTemp;
    fstream file("savegame.sav", fstream::out | fstream::binary | fstream::trunc);
    if(!file.is_open()) {cerr << "Error with opening file: " << strerror(errno) << endl; QUIT = true; return;}
    file.write(reinterpret_cast<char*>(&unit), sizeof(size_t));
    sizeTemp = sizeof(int);
    file.write(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    file.write(reinterpret_cast<char*>(&levelCounter), sizeTemp);
    sizeTemp = current.size();
    file.write(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    file.write(current.c_str(), sizeTemp);
    sizeTemp = pacmans.size();
    file.write(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    for (unsigned int i = 0; i < pacmans.size(); i++)
        {
            file.write(reinterpret_cast<char*>(&pacmans[i]->x), unit);
            file.write(reinterpret_cast<char*>(&pacmans[i]->y), unit);
        }
    sizeTemp = coffees.size();
    for (unsigned int i = 0; i < coffees.size(); i++)
    {
        if(!coffees[i]->armed){sizeTemp--;}
    }
    file.write(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    for (unsigned int i = 0; i < coffees.size(); i++)
        {
            if(coffees[i]->armed)
            {
                file.write(reinterpret_cast<char*>(&coffees[i]->x), unit);
                file.write(reinterpret_cast<char*>(&coffees[i]->y), unit);
            }
        }
    sizeTemp = enemies.size();
    file.write(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    for (unsigned int i = 0; i < enemies.size(); i++)
        {
            file.write(reinterpret_cast<char*>(&enemies[i]->x), unit);
            file.write(reinterpret_cast<char*>(&enemies[i]->y), unit);
        }
}
void Level::load()
{
    size_t unit = sizeof(GLfloat);
    size_t sizeTemp;
    char lvlName[50];
    GLfloat xTemp, yTemp;
    fstream file("savegame.sav", fstream::in | fstream::binary);
    if(!file.is_open())
    {
        levelCounter = 0;
        init("level1", true);
        return;
    }
    file.read(reinterpret_cast<char*>(&unit), sizeof(size_t));
    file.read(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    file.read(reinterpret_cast<char*>(&levelCounter), sizeTemp);
    levelCounter--;
    file.read(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    file.read(lvlName, sizeTemp);
    lvlName[sizeTemp] = 0;
    init(lvlName, false);
    file.read(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    for (unsigned int i = 0; i < sizeTemp; i++)
        {
            file.read(reinterpret_cast<char*>(&xTemp), unit);
            file.read(reinterpret_cast<char*>(&yTemp), unit);
            pacmans.push_back(new Pacman(xTemp, yTemp, textures));
        }
    file.read(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    for (unsigned int i = 0; i < sizeTemp; i++)
        {
            file.read(reinterpret_cast<char*>(&xTemp), unit);
            file.read(reinterpret_cast<char*>(&yTemp), unit);
            coffees.push_back(new Coffee(xTemp, yTemp, textures));
        }
    file.read(reinterpret_cast<char*>(&sizeTemp), sizeof(size_t));
    for (unsigned int i = 0; i < sizeTemp; i++)
        {
            file.read(reinterpret_cast<char*>(&xTemp), unit);
            file.read(reinterpret_cast<char*>(&yTemp), unit);
            enemies.push_back(new Enemy(xTemp, yTemp, textures));
        }
    menus.push_back(new Menu(ESCAPE));
}
void Level::handle(SDL_Event inputEvent)
{
    if((inputEvent.type == SDL_KEYDOWN) and (inputEvent.key.keysym.sym == SDLK_ESCAPE))
    {
        if (PAUSE == 0)
        {
            PAUSE = -1;
        }
        else
        {
            PAUSE = 0;
        }
        if(menus.empty()) {menus.push_back(new Menu(ESCAPE));}
        else {menus.pop_back();}
    }
    else
    {
        if(menus.size() > 0)
        {
            if(!menus[menus.size() - 1]->handle(inputEvent)) {menus.pop_back();}
        }
        for (unsigned int i = 0; i < pacmans.size(); i++)
        {
            pacmans[i]->handle(inputEvent);
        }
    }
}
void Level::update()
{
    if(menus.empty())
    {
        for (unsigned int i = 0; i < spaces.size(); i++)
        {
            spaces[i]->update();
        }
        for (unsigned int i = 0; i < walls.size(); i++)
        {
            walls[i]->update();
        }
        for (unsigned int i = 0; i < coffees.size(); i++)
        {
            coffees[i]->update();
        }
        for (unsigned int i = 0; i < 1; i++)
        {
            enemies[i]->update();
        }
        for (unsigned int i = 0; i < pacmans.size(); i++)
        {
            pacmans[i]->update();
        }
    }
}
void Level::render() const
{
	glClear(GL_COLOR_BUFFER_BIT);
	bool bgrender = true;
	if(menus.size() > 0)
    {
        if(menus[0]->type == MAIN) {bgrender = false;}
    }
	if (bgrender)
    {
        for (unsigned int i = 0; i < spaces.size(); i++)
        {
            spaces[i]->render();
        }
        for (unsigned int i = 0; i < walls.size(); i++)
        {
            walls[i]->render();
        }
        for (unsigned int i = 0; i < coffees.size(); i++)
        {
            coffees[i]->render();
        }
        for (unsigned int i = 0; i < enemies.size(); i++)
        {
            enemies[i]->render();
        }
        for (unsigned int i = 0; i < pacmans.size(); i++)
        {
            pacmans[i]->render();
        }
    }
	if(menus.size() > 0) {menus[menus.size() - 1]->render();}
}
void Level::destroy()
{
    for (unsigned int i = 0; i < menus.size(); i++)
	{
		menus.erase(menus.begin() + i);
	}
    for (unsigned int i = 0; i < spaces.size(); i++)
	{
	    spaces.erase(spaces.begin() + i);
	}
	for (unsigned int i = 0; i < walls.size(); i++)
	{
	    walls.erase(walls.begin() + i);
	}
	for (unsigned int i = 0; i < coffees.size(); i++)
	{
	    coffees.erase(coffees.begin() + i);
	}
	for (unsigned int i = 0; i < enemies.size(); i++)
	{
	    enemies.erase(enemies.begin() + i);
	}
	for (unsigned int i = 0; i < pacmans.size(); i++)
	{
	    pacmans.erase(pacmans.begin() + i);
	}
	menus.clear();
	spaces.clear();
	walls.clear();
	coffees.clear();
    enemies.clear();
    pacmans.clear();
    Coffee::count = 0;
}
<|endoftext|>


<commit_before>/*
 * $Id$
 *
 * Copyright(C) 1998-2004 Satoshi Nakamura
 * All rights reserved.
 *
 */

#include <qmaccount.h>
#include <qmapplication.h>
#include <qmdocument.h>
#include <qmfolder.h>
#include <qmmacro.h>
#include <qmmessage.h>
#include <qmsecurity.h>

#include <qscrypto.h>

#include "messagecomposer.h"
#include "../model/addressbook.h"
#include "../ui/foldermodel.h"
#include "../ui/securitymodel.h"

using namespace qm;
using namespace qs;

/****************************************************************************
 *
 * MessageComposer
 *
 */

qm::MessageComposer::MessageComposer(bool bDraft,
									 Document* pDocument,
									 Profile* pProfile,
									 HWND hwnd,
									 FolderModel* pFolderModel,
									 SecurityModel* pSecurityModel) :
	bDraft_(bDraft),
	pDocument_(pDocument),
	pProfile_(pProfile),
	hwnd_(hwnd),
	pFolderModel_(pFolderModel),
	pSecurityModel_(pSecurityModel)
{
}

qm::MessageComposer::~MessageComposer()
{
}

bool qm::MessageComposer::compose(Account* pAccount,
								  SubAccount* pSubAccount,
								  Message* pMessage,
								  unsigned int nFlags) const
{
	assert(pAccount || pFolderModel_);
	assert((!pAccount && !pSubAccount) ||
		(pAccount && !pSubAccount) || (pAccount && pSubAccount));
	assert(pMessage);

	if (!pAccount) {
		assert(pFolderModel_);

		UnstructuredParser account;
		Part::Field f = pMessage->getField(L"X-QMAIL-Account", &account);
		if (f == Part::FIELD_EXIST) {
			pAccount = pDocument_->getAccount(account.getValue());
		}
		else {
			pAccount = pFolderModel_->getCurrentAccount();
			if (!pAccount) {
				Folder* pFolder = pFolderModel_->getCurrentFolder();
				if (pFolder)
					pAccount = pFolder->getAccount();
			}
		}
	}
	if (!pAccount)
		return false;
	if (!pSubAccount) {
		UnstructuredParser subaccount;
		Part::Field f = pMessage->getField(L"X-QMAIL-SubAccount", &subaccount);
		if (f == Part::FIELD_EXIST)
			pSubAccount = pAccount->getSubAccount(subaccount.getValue());
		else
			pSubAccount = pAccount->getCurrentSubAccount();
	}

	Folder* pFolder = pAccount->getFolderByFlag(
		bDraft_ ? Folder::FLAG_DRAFTBOX : Folder::FLAG_OUTBOX);
	if (!pFolder || pFolder->getType() != Folder::TYPE_NORMAL)
		return false;

	bool bResent = PartUtil(*pMessage).isResent();

	AddressParser from(pSubAccount->getSenderName(),
		pSubAccount->getSenderAddress());
	if (!pMessage->setField(bResent ? L"Resent-From" : L"From", from))
		return false;

	Time time(Time::getCurrentTime());
	DateParser date(time);
	if (!pMessage->setField(bResent ? L"Resent-Date" : L"Date", date))
		return false;

	if (pSubAccount->isAddMessageId()) {
		WCHAR wsz[256];
		swprintf(wsz, L"%u%04d%02d%02d%02d%02d%02d",
			::GetCurrentProcessId(), time.wYear, time.wMonth,
			time.wDay, time.wHour, time.wMinute, time.wSecond);

		wstring_ptr wstrMessageId(concat(wsz, pSubAccount->getSenderAddress()));

		MessageIdParser messageId(wstrMessageId.get());
		if (!pMessage->setField(bResent ? L"Resent-Message-Id" : L"Message-Id", messageId))
			return false;
	}

	const WCHAR* pwszMacro = 0;
	UnstructuredParser macro;
	Part::Field f = pMessage->getField(L"X-QMAIL-Macro", &macro);
	if (f == Part::FIELD_EXIST)
		pwszMacro = macro.getValue();
	pMessage->removeField(L"X-QMAIL-Macro");

	wstring_ptr wstrVersion(Application::getApplication().getVersion(true));
	UnstructuredParser mailer(wstrVersion.get(), L"utf-8");
	if (!pMessage->replaceField(L"X-Mailer", mailer))
		return false;

	if (!pMessage->sortHeader())
		return false;

	const Security* pSecurity = pDocument_->getSecurity();
	const SMIMEUtility* pSMIMEUtility = pSecurity->getSMIMEUtility();
	if (pSMIMEUtility && nFlags != 0) {
		const Certificate* pSelfCertificate = 0;
		if (pProfile_->getInt(L"Security", L"EncryptForSelf", 0))
			pSelfCertificate = pSubAccount->getCertificate();
		SMIMECallbackImpl callback(pSecurity,
			pDocument_->getAddressBook(), pSelfCertificate);

		if (nFlags & FLAG_SIGN) {
			// TODO
			// Read from profile whether make multipart/signed or not
			bool bMultipart = false;
			Certificate* pCertificate = pSubAccount->getCertificate();
			PrivateKey* pPrivateKey = pSubAccount->getPrivateKey();
			if (pCertificate && pPrivateKey) {
				xstring_ptr strMessage(pSMIMEUtility->sign(pMessage,
					bMultipart, pPrivateKey, pCertificate));
				if (!strMessage.get())
					return false;
				if (!pMessage->create(strMessage.get(), -1, Message::FLAG_NONE))
					return false;
			}
		}
		if (nFlags & FLAG_ENCRYPT) {
			std::auto_ptr<Cipher> pCipher(Cipher::getInstance(L"des3"));
			xstring_ptr strMessage(pSMIMEUtility->encrypt(
				pMessage, pCipher.get(), &callback));
			if (!strMessage.get())
				return false;
			if (!pMessage->create(strMessage.get(), -1, Message::FLAG_NONE))
				return false;
		}
	}

	if (!pAccount->appendMessage(static_cast<NormalFolder*>(pFolder), *pMessage,
		MessageHolder::FLAG_SEEN | (bDraft_ ? MessageHolder::FLAG_DRAFT : 0)))
		return false;
	if (!pFolder->saveMessageHolders())
		return false;

	if (pwszMacro) {
		MacroParser parser(MacroParser::TYPE_MESSAGE);
		std::auto_ptr<Macro> pMacro(parser.parse(pwszMacro));
		if (!pMacro.get())
			return false;

		MacroContext context(0, 0, MessageHolderList(), pAccount, pDocument_,
			hwnd_, pProfile_, false, pSecurityModel_->isDecryptVerify(), 0, 0);
		MacroValuePtr pValue(pMacro->value(&context));
	}

	return true;
}

/****************************************************************************
 *
 * AddressBook::SMIMECallbackImpl
 *
 */

qm::SMIMECallbackImpl::SMIMECallbackImpl(const Security* pSecurity,
										 AddressBook* pAddressBook,
										 const Certificate* pSelfCertificate) :
	pSecurity_(pSecurity),
	pAddressBook_(pAddressBook),
	pSelfCertificate_(pSelfCertificate)
{
}

qm::SMIMECallbackImpl::~SMIMECallbackImpl()
{
}

std::auto_ptr<Certificate> qm::SMIMECallbackImpl::getCertificate(const WCHAR* pwszAddress)
{
	assert(pwszAddress);

	const AddressBookEntry* pEntry = pAddressBook_->getEntry(pwszAddress);
	if (!pEntry)
		return 0;

	const AddressBookEntry::AddressList& l = pEntry->getAddresses();
	for (AddressBookEntry::AddressList::const_iterator itA = l.begin(); itA != l.end(); ++itA) {
		const AddressBookAddress* pAddress = *itA;
		if (_wcsicmp(pAddress->getAddress(), pwszAddress) == 0)
			return pSecurity_->getCertificate(pAddress->getCertificate());
	}
	return 0;
}

const Certificate* qm::SMIMECallbackImpl::getSelfCertificate()
{
	return pSelfCertificate_;
}
<commit_msg>Add Global/XMailerWithOSVersion. <BTS:540><commit_after>/*
 * $Id$
 *
 * Copyright(C) 1998-2004 Satoshi Nakamura
 * All rights reserved.
 *
 */

#include <qmaccount.h>
#include <qmapplication.h>
#include <qmdocument.h>
#include <qmfolder.h>
#include <qmmacro.h>
#include <qmmessage.h>
#include <qmsecurity.h>

#include <qscrypto.h>

#include "messagecomposer.h"
#include "../model/addressbook.h"
#include "../ui/foldermodel.h"
#include "../ui/securitymodel.h"

using namespace qm;
using namespace qs;

/****************************************************************************
 *
 * MessageComposer
 *
 */

qm::MessageComposer::MessageComposer(bool bDraft,
									 Document* pDocument,
									 Profile* pProfile,
									 HWND hwnd,
									 FolderModel* pFolderModel,
									 SecurityModel* pSecurityModel) :
	bDraft_(bDraft),
	pDocument_(pDocument),
	pProfile_(pProfile),
	hwnd_(hwnd),
	pFolderModel_(pFolderModel),
	pSecurityModel_(pSecurityModel)
{
}

qm::MessageComposer::~MessageComposer()
{
}

bool qm::MessageComposer::compose(Account* pAccount,
								  SubAccount* pSubAccount,
								  Message* pMessage,
								  unsigned int nFlags) const
{
	assert(pAccount || pFolderModel_);
	assert((!pAccount && !pSubAccount) ||
		(pAccount && !pSubAccount) || (pAccount && pSubAccount));
	assert(pMessage);

	if (!pAccount) {
		assert(pFolderModel_);

		UnstructuredParser account;
		Part::Field f = pMessage->getField(L"X-QMAIL-Account", &account);
		if (f == Part::FIELD_EXIST) {
			pAccount = pDocument_->getAccount(account.getValue());
		}
		else {
			pAccount = pFolderModel_->getCurrentAccount();
			if (!pAccount) {
				Folder* pFolder = pFolderModel_->getCurrentFolder();
				if (pFolder)
					pAccount = pFolder->getAccount();
			}
		}
	}
	if (!pAccount)
		return false;
	if (!pSubAccount) {
		UnstructuredParser subaccount;
		Part::Field f = pMessage->getField(L"X-QMAIL-SubAccount", &subaccount);
		if (f == Part::FIELD_EXIST)
			pSubAccount = pAccount->getSubAccount(subaccount.getValue());
		else
			pSubAccount = pAccount->getCurrentSubAccount();
	}

	Folder* pFolder = pAccount->getFolderByFlag(
		bDraft_ ? Folder::FLAG_DRAFTBOX : Folder::FLAG_OUTBOX);
	if (!pFolder || pFolder->getType() != Folder::TYPE_NORMAL)
		return false;

	bool bResent = PartUtil(*pMessage).isResent();

	AddressParser from(pSubAccount->getSenderName(),
		pSubAccount->getSenderAddress());
	if (!pMessage->setField(bResent ? L"Resent-From" : L"From", from))
		return false;

	Time time(Time::getCurrentTime());
	DateParser date(time);
	if (!pMessage->setField(bResent ? L"Resent-Date" : L"Date", date))
		return false;

	if (pSubAccount->isAddMessageId()) {
		WCHAR wsz[256];
		swprintf(wsz, L"%u%04d%02d%02d%02d%02d%02d",
			::GetCurrentProcessId(), time.wYear, time.wMonth,
			time.wDay, time.wHour, time.wMinute, time.wSecond);

		wstring_ptr wstrMessageId(concat(wsz, pSubAccount->getSenderAddress()));

		MessageIdParser messageId(wstrMessageId.get());
		if (!pMessage->setField(bResent ? L"Resent-Message-Id" : L"Message-Id", messageId))
			return false;
	}

	const WCHAR* pwszMacro = 0;
	UnstructuredParser macro;
	Part::Field f = pMessage->getField(L"X-QMAIL-Macro", &macro);
	if (f == Part::FIELD_EXIST)
		pwszMacro = macro.getValue();
	pMessage->removeField(L"X-QMAIL-Macro");

	bool bWithOSVersion = pProfile_->getInt(L"Global", L"XMailerWithOSVersion", 1) != 0;
	wstring_ptr wstrVersion(Application::getApplication().getVersion(bWithOSVersion));
	UnstructuredParser mailer(wstrVersion.get(), L"utf-8");
	if (!pMessage->replaceField(L"X-Mailer", mailer))
		return false;

	if (!pMessage->sortHeader())
		return false;

	const Security* pSecurity = pDocument_->getSecurity();
	const SMIMEUtility* pSMIMEUtility = pSecurity->getSMIMEUtility();
	if (pSMIMEUtility && nFlags != 0) {
		const Certificate* pSelfCertificate = 0;
		if (pProfile_->getInt(L"Security", L"EncryptForSelf", 0))
			pSelfCertificate = pSubAccount->getCertificate();
		SMIMECallbackImpl callback(pSecurity,
			pDocument_->getAddressBook(), pSelfCertificate);

		if (nFlags & FLAG_SIGN) {
			// TODO
			// Read from profile whether make multipart/signed or not
			bool bMultipart = false;
			Certificate* pCertificate = pSubAccount->getCertificate();
			PrivateKey* pPrivateKey = pSubAccount->getPrivateKey();
			if (pCertificate && pPrivateKey) {
				xstring_ptr strMessage(pSMIMEUtility->sign(pMessage,
					bMultipart, pPrivateKey, pCertificate));
				if (!strMessage.get())
					return false;
				if (!pMessage->create(strMessage.get(), -1, Message::FLAG_NONE))
					return false;
			}
		}
		if (nFlags & FLAG_ENCRYPT) {
			std::auto_ptr<Cipher> pCipher(Cipher::getInstance(L"des3"));
			xstring_ptr strMessage(pSMIMEUtility->encrypt(
				pMessage, pCipher.get(), &callback));
			if (!strMessage.get())
				return false;
			if (!pMessage->create(strMessage.get(), -1, Message::FLAG_NONE))
				return false;
		}
	}

	if (!pAccount->appendMessage(static_cast<NormalFolder*>(pFolder), *pMessage,
		MessageHolder::FLAG_SEEN | (bDraft_ ? MessageHolder::FLAG_DRAFT : 0)))
		return false;
	if (!pFolder->saveMessageHolders())
		return false;

	if (pwszMacro) {
		MacroParser parser(MacroParser::TYPE_MESSAGE);
		std::auto_ptr<Macro> pMacro(parser.parse(pwszMacro));
		if (!pMacro.get())
			return false;

		MacroContext context(0, 0, MessageHolderList(), pAccount, pDocument_,
			hwnd_, pProfile_, false, pSecurityModel_->isDecryptVerify(), 0, 0);
		MacroValuePtr pValue(pMacro->value(&context));
	}

	return true;
}

/****************************************************************************
 *
 * AddressBook::SMIMECallbackImpl
 *
 */

qm::SMIMECallbackImpl::SMIMECallbackImpl(const Security* pSecurity,
										 AddressBook* pAddressBook,
										 const Certificate* pSelfCertificate) :
	pSecurity_(pSecurity),
	pAddressBook_(pAddressBook),
	pSelfCertificate_(pSelfCertificate)
{
}

qm::SMIMECallbackImpl::~SMIMECallbackImpl()
{
}

std::auto_ptr<Certificate> qm::SMIMECallbackImpl::getCertificate(const WCHAR* pwszAddress)
{
	assert(pwszAddress);

	const AddressBookEntry* pEntry = pAddressBook_->getEntry(pwszAddress);
	if (!pEntry)
		return 0;

	const AddressBookEntry::AddressList& l = pEntry->getAddresses();
	for (AddressBookEntry::AddressList::const_iterator itA = l.begin(); itA != l.end(); ++itA) {
		const AddressBookAddress* pAddress = *itA;
		if (_wcsicmp(pAddress->getAddress(), pwszAddress) == 0)
			return pSecurity_->getCertificate(pAddress->getCertificate());
	}
	return 0;
}

const Certificate* qm::SMIMECallbackImpl::getSelfCertificate()
{
	return pSelfCertificate_;
}
<|endoftext|>


<commit_before>// groundwater_pipe.C
//
// Copyright 1996-2001 Per Abrahamsen and Sren Hansen
// Copyright 2000-2001 KVL.
//
// This file is part of Daisy.
//
// Daisy is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// Daisy 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 Lesser Public License for more details.
//
// You should have received a copy of the GNU Lesser Public License
// along with Daisy; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "groundwater.h"
#include "log.h"
#include "soil.h"
#include "soil_heat.h"
#include "soil_water.h"
#include "depth.h"
#include "treelog.h"
#include "mathlib.h"
#include "check.h"
#include <memory>
#include <sstream>

class GroundwaterPipe : public Groundwater
{
  // Parameters
  const double L;		// Distance between pipes. [cm]
  const double x;		// Distance to nearest pipe. [cm]
  const double pipe_position;	// Height pipes are placed above surface. [cm]
  const double K_to_pipes_;	// Horizontal sat. conductivity. [cm h^-1]
  const double K_aquitard_;	// Conductivity of the aquitard. [cm h^-1]
  /*const*/ double Z_aquitard_;	// Vertical length of the aquitard. [cm]
  std::auto_ptr<Depth> pressure_table; // Virtual groundwater height. [cm]
  int i_drain;			// Node, drain

  // Accessors.
  double Z_aquitard () const
  { return Z_aquitard_; }
  double K_aquitard () const
  { return K_aquitard_; }
  void set_Z_aquitard (double value)
  { Z_aquitard_ = value; }

  // Data.
  double height;		// Groundwater table height above surface. [cm]
  double EqDrnFlow;
  double DrainFlow;		// Drain flow [cm/h]
  std::vector<double> S;        // Pipe drainage. [cm^3/cm^3/h]
  double deep_percolation;	// [cm^3/cm^2/h]
  double h_aquifer;          // Pressure potential in the aquifer [cm]

  // UZbottom.
public:
  bottom_t bottom_type () const
  {
#ifdef USE_UPDATE_WATER
    return pressure;
#else // !USE_UPDATE_WATER
    return forced_flux;
#endif // !USE_UPDATE_WATER
  }
  double q_bottom () const
  { return -deep_percolation; }

  bool accept_bottom (double)
  { return true; }

  // Identity
  bool is_pipe () const
  { return true; }
  double pipe_height () const
  { return pipe_position; }

  // Simulation.
public:
  void tick (const Soil&, SoilWater&, double,
	     const SoilHeat&, const Time&, Treelog&);
  void output (Log& log) const;

private:
  void set_h_aquifer (const Soil& soil, const Time& time)
  {
    const size_t size = soil.size ();
    const double aquitart_bottom = soil.zplus (size-1) - Z_aquitard_;
    h_aquifer = pressure_table->operator()(time) - aquitart_bottom;
  }
  double DeepPercolation (const Soil&);
  double K_to_pipes (const unsigned int i,
                     const Soil& soil,
                     const SoilHeat& soil_heat) const;
  double EquilibriumDrainFlow (const Soil&, const SoilHeat&);

  // Accessors.
  double table () const
  { return height; }

  // Create and Destroy.
public:
  void initialize (const Soil& soil, const Time& time, Treelog& msg)
  {
    const int size = soil.size ();
    double largest = 0.0;
    for (unsigned int i = 0; i < size; i++)
      if (soil.dz (i) > largest)
	largest = soil.dz (i);
    if (largest > 10.0)
      {
	Treelog::Open nest (msg, "Groundwater pipe");
	std::ostringstream tmp;
	tmp << "WARNING: drained soil needs soil intervals < 10.0 cm; "
	    << "largest is " << largest << "";
	msg.warning (tmp.str ());
      }

    i_drain = soil.interval_plus (pipe_position);
    daisy_assert (i_drain > 0);
    S.insert (S.end (), size, 0.0);

    if (!pressure_table.get ())
      {
        // GCC 2.95 need the extra variable for the assignment.
        std::auto_ptr<Depth> depth (Depth::create ((soil.zplus (size-1)
                                                    - Z_aquitard_)
                                                   + h_aquifer));
        pressure_table = depth;
      }
    pressure_table->initialize (msg);
    // Pressure below aquitard.
    if (pressure_table->check (msg))
      set_h_aquifer (soil, time);
  }
  bool check (Treelog& msg) const
  { return pressure_table->check (msg); }
  GroundwaterPipe (const AttributeList& al)
    : Groundwater (al),
      L (al.number ("L")),
      x (al.number ("x", L / 2.0)),
      pipe_position (al.number ("pipe_position")),
      K_to_pipes_ (al.number ("K_to_pipes", -1.0)),
      K_aquitard_ (al.number ("K_aquitard")),
      Z_aquitard_ (al.number ("Z_aquitard")),
      height (al.number ("height", pipe_position)),
      h_aquifer (al.number ("h_aquifer", Z_aquitard_))
  {
    if (al.check ("pressure_table"))
      {
        // GCC 2.95 needs the extra variable for the asignment.
        std::auto_ptr<Depth> depth
          (Librarian<Depth>::create (al.alist ("pressure_table")));
        pressure_table = depth;
      }
  }
  ~GroundwaterPipe ()
  { }
};

void
GroundwaterPipe::tick (const Soil& soil, SoilWater& soil_water,
		       const double h_surface,
		       const SoilHeat& soil_heat, const Time& time,
                       Treelog&)
{
  const size_t size = soil.size ();

  // Empty source.
  fill (S.begin (), S.end (), 0.0);

  // Virtual pressure table.
  set_h_aquifer (soil, time);

  // Find groundwater height.
  height = h_surface;
  for (int i = size - 1; i >= 0; i--)
    {
      const double h = soil_water.h (i);
      if (h < 0)
	{
	  const double zplus = soil.zplus (i);
	  const double z = (i == 0) ? 0.0 : soil.zplus (i-1);
	  const double zx = z - zplus;
	  if (h + zx > 0)
	    // Groundwater in this node.
	    height = zplus + h + zx;
	  else
	    // Groundwater between nodes.
	    height = zplus;
	  break;
	}
    }

  // Find sink term.
  EqDrnFlow = EquilibriumDrainFlow (soil, soil_heat);
  DrainFlow= soil.total (S);
  soil_water.drain (S);

  // Find deep percolation.
  deep_percolation = DeepPercolation (soil);
}

double
GroundwaterPipe::DeepPercolation(const Soil& soil)
{
  const int size = soil.size ();
  daisy_assert (size > 0);
  const double hb = height - soil.zplus (size - 1);
  if (hb > 0)
    return K_aquitard_ * (1.0 + (hb - h_aquifer) / Z_aquitard_);
  else
    return 0;
}

double
GroundwaterPipe::K_to_pipes (const unsigned int i,
                             const Soil& soil,
                             const SoilHeat& soil_heat) const
{
  if (K_to_pipes_ < 0)
    return soil.K (i, 0.0, 0.0, soil_heat.T (i))
      * soil.anisotropy (i);
  return K_to_pipes_;
}

double
GroundwaterPipe::EquilibriumDrainFlow (const Soil& soil,
				       const SoilHeat& soil_heat)
{
  const int size = soil.size ();
  const int i_GWT = soil.interval_plus (height) + 1;
  daisy_assert (i_drain > 0);
  if (height >= soil.zplus(i_drain-1))
    {
      // GWT located above drain
      double Ha = 0;
      double Ka = 0;
      for (unsigned int i = i_GWT; i <= i_drain; i++)
	{
	  Ha += soil.dz (i);
	  Ka += soil.dz (i) * K_to_pipes (i, soil, soil_heat);
	}
      Ka /= Ha;

      // GWT located below drain
      double Hb = 0;
      double Kb = 0;
      for (unsigned int i = i_drain+1; i < size; i++)
	{
	  Hb += soil.dz (i);
	  Kb += soil.dz (i) * K_to_pipes (i, soil, soil_heat);
	}
      Kb /= Hb;
      const double Flow = (4*Ka*Ha*Ha + 2*Kb*Hb*Ha) / (L*x - x*x);

      // Distribution of drain flow among numeric soil layers
      const double a = Flow / (Ka*Ha + Kb*Hb);
      for (unsigned int i = i_GWT; i < size; i++)
	{
          S[i] = a * K_to_pipes (i, soil, soil_heat);
	}
      daisy_assert (isfinite (Flow));
      return Flow;
    }
  return 0.0;
}
void
GroundwaterPipe::output (Log& log) const
{
  Groundwater::output (log);
  output_variable (DrainFlow, log);
  output_variable (EqDrnFlow, log);
  output_value (deep_percolation, "DeepPercolation", log);
  output_variable (S, log);
  output_variable (h_aquifer, log);
}

static struct GroundwaterPipeSyntax
{
  static Groundwater& make (const AttributeList& al)
    {
      return *new GroundwaterPipe (al);
    }
  GroundwaterPipeSyntax ()
    {
      Syntax& syntax = *new Syntax ();
      AttributeList& alist = *new AttributeList ();
      alist.add ("description", "Groundwater for pipe (tile) drained soil.\n\
If you specify this groundwater model, and does not specify the 'zplus' Soil\n\
discretization parameter, an extra aquitard soil horizon approximately a third\n\
of the size of 'Z_aquitart' will be added.  This will allow the grounwater\n\
level to sink into the aquitart.  The model cannot handle groundwater levels\n\
below the last node, or above the soil surface.");
      // We define our own "height", so don't load from here.
      // Groundwater::load_syntax (syntax, alist);

      syntax.add ("L", "cm", Check::positive (), Syntax::Const,
		  "Distance between pipes.");
      alist.add ("L", 1800.0);
      syntax.add ("x", "cm", Check::positive (), Syntax::OptionalConst,
		  "Horizontal distance to nearest pipe.\n\
By default, this is 1/2 L.");
      syntax.add ("pipe_position", "cm", Check::negative (), Syntax::Const,
		  "Height pipes are placed in the soil (a negative number).");
      alist.add ("pipe_position", -110.0);
      syntax.add ("K_to_pipes", "cm/h", Check::non_negative (),
                  Syntax::OptionalConst,
		  "Horizontal conductivity in saturated soil.\n\
By default this is calculated from the horizontal conductivity and the\n\
anisotropy of the horizon.");
      syntax.add ("K_aquitard", "cm/h", Check::non_negative (), Syntax::Const,
		  "Conductivity of the aquitard.");
      alist.add ("K_aquitard", 1e-3);
      syntax.add ("Z_aquitard", "cm", Check::positive (), Syntax::Const,
		  "Thickness of the aquitard.\n\
The aquitard begins below the bottommost soil horizon.");
      alist.add ("Z_aquitard", 200.0);
      syntax.add ("h_aquifer", "cm", Check::positive (), Syntax::OptionalState,
		  "Pressure potential in the aquifer below the aquitard.\n\
By default. this is Z_aquitard.\n\
You can alternatively specify the pressure as a virtual groundwater level.\n\
See 'pressure_table'.");
      syntax.add ("pressure_table", Librarian<Depth>::library (),
                  Syntax::OptionalConst, Syntax::Singleton, "\
Height of groundwater the corresponds to the pressure in the aquifer.  \n\
\n\
If you drilled a well down to the aquifer, this is number what the\n\
water level in the well would be as height above ground (a negative\n\
number).  This is different from the actual groundwater table, because\n\
the aquitart block the water, and the pipes lead the water away.\n\
You can alternatively specify the pressure directly, with 'h_aquifer'.");
      syntax.add ("height", "cm", Check::non_positive (),
		  Syntax::OptionalState,
		  "Current groundwater level (a negative number).");
      syntax.add ("DrainFlow", "cm/h", Syntax::LogOnly,
		  "Drain flow to pipes.");
      syntax.add ("EqDrnFlow", "cm/h", Syntax::LogOnly,
		  "Equilibrium drain flow to pipes.");
      syntax.add ("deficit", "cm", Syntax::LogOnly,
		  "Deficit.");
      syntax.add ("DeepPercolation", "cm/h", Syntax::LogOnly,
		  "Deep percolation to aquifer.");
      syntax.add ("S", "cm^3/cm^3/h", Syntax::LogOnly, Syntax::Sequence,
		  "Pipe drainage.");
      Librarian<Groundwater>::add_type ("pipe", alist, syntax, &make);
    }
} GroundwaterPipe_syntax;

<commit_msg>x40<commit_after>// groundwater_pipe.C
//
// Copyright 1996-2001 Per Abrahamsen and Sren Hansen
// Copyright 2000-2001 KVL.
//
// This file is part of Daisy.
//
// Daisy is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// Daisy 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 Lesser Public License for more details.
//
// You should have received a copy of the GNU Lesser Public License
// along with Daisy; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "groundwater.h"
#include "log.h"
#include "soil.h"
#include "soil_heat.h"
#include "soil_water.h"
#include "depth.h"
#include "treelog.h"
#include "mathlib.h"
#include "check.h"
#include <memory>
#include <sstream>

class GroundwaterPipe : public Groundwater
{
  // Parameters
  const double L;		// Distance between pipes. [cm]
  const double x;		// Distance to nearest pipe. [cm]
  const double pipe_position;	// Height pipes are placed above surface. [cm]
  const double K_to_pipes_;	// Horizontal sat. conductivity. [cm h^-1]
  const double K_aquitard_;	// Conductivity of the aquitard. [cm h^-1]
  /*const*/ double Z_aquitard_;	// Vertical length of the aquitard. [cm]
  std::auto_ptr<Depth> pressure_table; // Virtual groundwater height. [cm]
  int i_drain;			// Node, drain

  // Accessors.
  double Z_aquitard () const
  { return Z_aquitard_; }
  double K_aquitard () const
  { return K_aquitard_; }
  void set_Z_aquitard (double value)
  { Z_aquitard_ = value; }

  // Data.
  double height;		// Groundwater table height above surface. [cm]
  double EqDrnFlow;
  double DrainFlow;		// Drain flow [cm/h]
  std::vector<double> S;        // Pipe drainage. [cm^3/cm^3/h]
  double deep_percolation;	// [cm^3/cm^2/h]
  double h_aquifer;          // Pressure potential in the aquifer [cm]

  // UZbottom.
public:
  bottom_t bottom_type () const
  {
#ifdef USE_UPDATE_WATER
    return pressure;
#else // !USE_UPDATE_WATER
    return forced_flux;
#endif // !USE_UPDATE_WATER
  }
  double q_bottom () const
  { return -deep_percolation; }

  bool accept_bottom (double)
  { return true; }

  // Identity
  bool is_pipe () const
  { return true; }
  double pipe_height () const
  { return pipe_position; }

  // Simulation.
public:
  void tick (const Soil&, SoilWater&, double,
	     const SoilHeat&, const Time&, Treelog&);
  void output (Log& log) const;

private:
  void set_h_aquifer (const Soil& soil, const Time& time)
  {
    const size_t size = soil.size ();
    const double aquitart_bottom = soil.zplus (size-1) - Z_aquitard_;
    h_aquifer = pressure_table->operator()(time) - aquitart_bottom;
  }
  double DeepPercolation (const Soil&);
  double K_to_pipes (const unsigned int i,
                     const Soil& soil,
                     const SoilHeat& soil_heat) const;
  double EquilibriumDrainFlow (const Soil&, const SoilHeat&);

  // Accessors.
  double table () const
  { return height; }

  // Create and Destroy.
public:
  void initialize (const Soil& soil, const Time& time, Treelog& msg)
  {
    const int size = soil.size ();
    double largest = 0.0;
    for (unsigned int i = 0; i < size; i++)
      if (soil.dz (i) > largest)
	largest = soil.dz (i);
    if (largest > 10.0)
      {
	Treelog::Open nest (msg, "Groundwater pipe");
	std::ostringstream tmp;
	tmp << "WARNING: drained soil needs soil intervals < 10.0 cm; "
	    << "largest is " << largest << "";
	msg.warning (tmp.str ());
      }

    i_drain = soil.interval_plus (pipe_position);
    daisy_assert (i_drain > 0);
    S.insert (S.end (), size, 0.0);

    if (!pressure_table.get ())
      {
        // GCC 2.95 need the extra variable for the assignment.
        std::auto_ptr<Depth> depth (Depth::create ((soil.zplus (size-1)
                                                    - Z_aquitard_)
                                                   + h_aquifer));
        pressure_table = depth;
      }
    pressure_table->initialize (msg);
    // Pressure below aquitard.
    if (pressure_table->check (msg))
      set_h_aquifer (soil, time);
  }
  bool check (Treelog& msg) const
  { return pressure_table->check (msg); }
  GroundwaterPipe (const AttributeList& al)
    : Groundwater (al),
      L (al.number ("L")),
      x (al.number ("x", L / 2.0)),
      pipe_position (al.number ("pipe_position")),
      K_to_pipes_ (al.number ("K_to_pipes", -1.0)),
      K_aquitard_ (al.number ("K_aquitard")),
      Z_aquitard_ (al.number ("Z_aquitard")),
      height (al.number ("height", pipe_position)),
      h_aquifer (al.number ("h_aquifer", Z_aquitard_))
  {
    if (al.check ("pressure_table"))
      {
        // GCC 2.95 needs the extra variable for the asignment.
        std::auto_ptr<Depth> depth
          (Librarian<Depth>::create (al.alist ("pressure_table")));
        pressure_table = depth;
      }
  }
  ~GroundwaterPipe ()
  { }
};

void
GroundwaterPipe::tick (const Soil& soil, SoilWater& soil_water,
		       const double h_surface,
		       const SoilHeat& soil_heat, const Time& time,
                       Treelog&)
{
  const size_t size = soil.size ();

  // Empty source.
  fill (S.begin (), S.end (), 0.0);

  // Virtual pressure table.
  set_h_aquifer (soil, time);

  // Find groundwater height.
  height = h_surface;
  for (int i = size - 1; i >= 0; i--)
    {
      const double h = soil_water.h (i);
      if (h < 0)
	{
	  const double zplus = soil.zplus (i);
	  const double z = (i == 0) ? 0.0 : soil.zplus (i-1);
	  const double zx = z - zplus;
	  if (h + zx > 0)
	    // Groundwater in this node.
	    height = zplus + h + zx;
	  else
	    // Groundwater between nodes.
	    height = zplus;
	  break;
	}
    }

  // Find sink term.
  EqDrnFlow = EquilibriumDrainFlow (soil, soil_heat);
  DrainFlow= soil.total (S);
  soil_water.drain (S);

  // Find deep percolation.
  deep_percolation = DeepPercolation (soil);
}

double
GroundwaterPipe::DeepPercolation(const Soil& soil)
{
  const int size = soil.size ();
  daisy_assert (size > 0);
  const double hb = height - soil.zplus (size - 1);
  if (hb > 0)
    return K_aquitard_ * (1.0 + (hb - h_aquifer) / Z_aquitard_);
  else
    return 0;
}

double
GroundwaterPipe::K_to_pipes (const unsigned int i,
                             const Soil& soil,
                             const SoilHeat& soil_heat) const
{
  if (K_to_pipes_ < 0)
    return soil.K (i, 0.0, 0.0, soil_heat.T (i))
      * soil.anisotropy (i);
  return K_to_pipes_;
}

double
GroundwaterPipe::EquilibriumDrainFlow (const Soil& soil,
				       const SoilHeat& soil_heat)
{
  const int size = soil.size ();
  const int i_GWT = soil.interval_plus (height) + 1;
  daisy_assert (i_drain > 0);
  if (height >= soil.zplus(i_drain-1))
    {
      // GWT located above drain
      double Ha = 0;
      double Ka = 0;
      for (unsigned int i = i_GWT; i <= i_drain; i++)
	{
	  Ha += soil.dz (i);
	  Ka += soil.dz (i) * K_to_pipes (i, soil, soil_heat);
	}
      Ka /= Ha;

      // GWT located below drain
      double Hb = 0;
      double Kb = 0;
      for (unsigned int i = i_drain+1; i < size; i++)
	{
	  Hb += soil.dz (i);
	  Kb += soil.dz (i) * K_to_pipes (i, soil, soil_heat);
	}
      Kb /= Hb;
      const double Flow = (4*Ka*Ha*Ha + 2*Kb*Hb*Ha) / (L*x - x*x);

      // Distribution of drain flow among numeric soil layers
      const double a = Flow / (Ka*Ha + Kb*Hb);
      for (unsigned int i = i_GWT; i < size; i++)
	{
          S[i] = a * K_to_pipes (i, soil, soil_heat);
	}
      daisy_assert (std::isfinite (Flow));
      return Flow;
    }
  return 0.0;
}
void
GroundwaterPipe::output (Log& log) const
{
  Groundwater::output (log);
  output_variable (DrainFlow, log);
  output_variable (EqDrnFlow, log);
  output_value (deep_percolation, "DeepPercolation", log);
  output_variable (S, log);
  output_variable (h_aquifer, log);
}

static struct GroundwaterPipeSyntax
{
  static Groundwater& make (const AttributeList& al)
    {
      return *new GroundwaterPipe (al);
    }
  GroundwaterPipeSyntax ()
    {
      Syntax& syntax = *new Syntax ();
      AttributeList& alist = *new AttributeList ();
      alist.add ("description", "Groundwater for pipe (tile) drained soil.\n\
If you specify this groundwater model, and does not specify the 'zplus' Soil\n\
discretization parameter, an extra aquitard soil horizon approximately a third\n\
of the size of 'Z_aquitart' will be added.  This will allow the grounwater\n\
level to sink into the aquitart.  The model cannot handle groundwater levels\n\
below the last node, or above the soil surface.");
      // We define our own "height", so don't load from here.
      // Groundwater::load_syntax (syntax, alist);

      syntax.add ("L", "cm", Check::positive (), Syntax::Const,
		  "Distance between pipes.");
      alist.add ("L", 1800.0);
      syntax.add ("x", "cm", Check::positive (), Syntax::OptionalConst,
		  "Horizontal distance to nearest pipe.\n\
By default, this is 1/2 L.");
      syntax.add ("pipe_position", "cm", Check::negative (), Syntax::Const,
		  "Height pipes are placed in the soil (a negative number).");
      alist.add ("pipe_position", -110.0);
      syntax.add ("K_to_pipes", "cm/h", Check::non_negative (),
                  Syntax::OptionalConst,
		  "Horizontal conductivity in saturated soil.\n\
By default this is calculated from the horizontal conductivity and the\n\
anisotropy of the horizon.");
      syntax.add ("K_aquitard", "cm/h", Check::non_negative (), Syntax::Const,
		  "Conductivity of the aquitard.");
      alist.add ("K_aquitard", 1e-3);
      syntax.add ("Z_aquitard", "cm", Check::positive (), Syntax::Const,
		  "Thickness of the aquitard.\n\
The aquitard begins below the bottommost soil horizon.");
      alist.add ("Z_aquitard", 200.0);
      syntax.add ("h_aquifer", "cm", Check::positive (), Syntax::OptionalState,
		  "Pressure potential in the aquifer below the aquitard.\n\
By default. this is Z_aquitard.\n\
You can alternatively specify the pressure as a virtual groundwater level.\n\
See 'pressure_table'.");
      syntax.add ("pressure_table", Librarian<Depth>::library (),
                  Syntax::OptionalConst, Syntax::Singleton, "\
Height of groundwater the corresponds to the pressure in the aquifer.  \n\
\n\
If you drilled a well down to the aquifer, this is number what the\n\
water level in the well would be as height above ground (a negative\n\
number).  This is different from the actual groundwater table, because\n\
the aquitart block the water, and the pipes lead the water away.\n\
You can alternatively specify the pressure directly, with 'h_aquifer'.");
      syntax.add ("height", "cm", Check::non_positive (),
		  Syntax::OptionalState,
		  "Current groundwater level (a negative number).");
      syntax.add ("DrainFlow", "cm/h", Syntax::LogOnly,
		  "Drain flow to pipes.");
      syntax.add ("EqDrnFlow", "cm/h", Syntax::LogOnly,
		  "Equilibrium drain flow to pipes.");
      syntax.add ("deficit", "cm", Syntax::LogOnly,
		  "Deficit.");
      syntax.add ("DeepPercolation", "cm/h", Syntax::LogOnly,
		  "Deep percolation to aquifer.");
      syntax.add ("S", "cm^3/cm^3/h", Syntax::LogOnly, Syntax::Sequence,
		  "Pipe drainage.");
      Librarian<Groundwater>::add_type ("pipe", alist, syntax, &make);
    }
} GroundwaterPipe_syntax;

<|endoftext|>


<commit_before>/**
 * \file demoDmpTrainFromTrajectoryFile.cpp
 * \author Freek Stulp
 * \brief  Demonstrates how to train a Dmp with a trajectory in a txt file.
 *
 * \ingroup Demos
 * \ingroup Dmps
 *
 * This file is part of DmpBbo, a set of libraries and programs for the
 * black-box optimization of dynamical movement primitives.
 * Copyright (C) 2014 Freek Stulp, ENSTA-ParisTech
 *
 * DmpBbo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * DmpBbo 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with DmpBbo.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "dmp/Dmp.hpp"
#include "dmp/Trajectory.hpp"

#include "dynamicalsystems/DynamicalSystem.hpp"
#include "dynamicalsystems/ExponentialSystem.hpp"
#include "dynamicalsystems/SigmoidSystem.hpp"
#include "dynamicalsystems/TimeSystem.hpp"
#include "dynamicalsystems/SpringDamperSystem.hpp"

#include "functionapproximators/FunctionApproximatorLWR.hpp"
#include "functionapproximators/MetaParametersLWR.hpp"
#include "functionapproximators/ModelParametersLWR.hpp"

#include <iostream>
#include <fstream>
#include <boost/filesystem.hpp>

using namespace std;
using namespace Eigen;
using namespace DmpBbo;

void help(char* binary_name)
{
  cout << "Usage: " << binary_name << " <input trajectory (txt)> <output directory> [output dmp (xml)] " << endl;
  cout << "Default for dmp: 'dmp.xml' " << endl;
}

/** Main function
 * \param[in] n_args Number of arguments
 * \param[in] args Arguments themselves
 * \return Success of exection. 0 if successful.
 */
int main(int n_args, char** args)
{

  string input_txt_file;
  string directory;
  string output_xml_file("dmp.xml");
  if (n_args<3)
  {
    help(args[0]);
    return -1;
  }

  if (string(args[1]).compare("--help")==0)
  {
    help(args[0]);
    return 0;
  }

  input_txt_file = string(args[1]);
  directory = string(args[2]);
  if (n_args>3)
    output_xml_file = string(args[3]);

  cout << "Reading trajectory from TXT file: " << input_txt_file << endl;
  Trajectory trajectory = Trajectory::readFromFile(input_txt_file);
  if (trajectory.length()==0)
  {
    cerr << "The TXT file " << input_txt_file << " could not be found. Aborting." << endl << endl;
    help(args[0]);
    return -1;
  }

  //double tau = trajectory.duration();
  //int n_time_steps = trajectory.length();
  VectorXd ts = trajectory.ts(); // Time steps
  int n_dims = trajectory.dim();

  // Initialize some meta parameters for training LWR function approximator
  int n_basis_functions = 3;
  int input_dim = 1;
  double intersection = 0.56;
  MetaParametersLWR* meta_parameters = new MetaParametersLWR(input_dim,n_basis_functions,intersection);
  FunctionApproximatorLWR* fa_lwr = new FunctionApproximatorLWR(meta_parameters);

  // Clone the function approximator for each dimension of the DMP
  vector<FunctionApproximator*> function_approximators(n_dims);
  for (int dd=0; dd<n_dims; dd++)
    function_approximators[dd] = fa_lwr->clone();

  // Initialize the DMP
  Dmp* dmp = new Dmp(n_dims, function_approximators, Dmp::KULVICIUS_2012_JOINING);

  cout << "Training Dmp..." << endl;
  bool overwrite = true;
  dmp->train(trajectory,directory+"/train",overwrite);

#ifndef NDEBUG
  // boost serialization currently only works in debug mode; I have no clue why...
  cout << "Writing trained Dmp to XML file: " << directory << "/" << output_xml_file << endl;
  // Make directory if it doesn't already exist
  if (!boost::filesystem::exists(directory))
  {
    if (!boost::filesystem::create_directories(directory))
    {
      cerr << __FILE__ << ":" << __LINE__ << ":";
      cerr << "Couldn't make directory file '" << directory << "'." << endl;
      return false;
    }
  }

  std::ofstream ofs(directory+"/"+output_xml_file);
  boost::archive::xml_oarchive oa(ofs);
  oa << boost::serialization::make_nvp("dmp",dmp);
  ofs.close();
#endif

  delete meta_parameters;
  delete fa_lwr;
  delete dmp;

  return 0;
}
<commit_msg>boost serialization seems to work again<commit_after>/**
 * \file demoDmpTrainFromTrajectoryFile.cpp
 * \author Freek Stulp
 * \brief  Demonstrates how to train a Dmp with a trajectory in a txt file.
 *
 * \ingroup Demos
 * \ingroup Dmps
 *
 * This file is part of DmpBbo, a set of libraries and programs for the
 * black-box optimization of dynamical movement primitives.
 * Copyright (C) 2014 Freek Stulp, ENSTA-ParisTech
 *
 * DmpBbo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * DmpBbo 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with DmpBbo.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "dmp/Dmp.hpp"
#include "dmp/Trajectory.hpp"

#include "dynamicalsystems/DynamicalSystem.hpp"
#include "dynamicalsystems/ExponentialSystem.hpp"
#include "dynamicalsystems/SigmoidSystem.hpp"
#include "dynamicalsystems/TimeSystem.hpp"
#include "dynamicalsystems/SpringDamperSystem.hpp"

#include "functionapproximators/FunctionApproximatorLWR.hpp"
#include "functionapproximators/MetaParametersLWR.hpp"
#include "functionapproximators/ModelParametersLWR.hpp"

#include <iostream>
#include <fstream>
#include <boost/filesystem.hpp>

using namespace std;
using namespace Eigen;
using namespace DmpBbo;

void help(char* binary_name)
{
  cout << "Usage: " << binary_name << " <input trajectory (txt)> <output directory> [output dmp (xml)] " << endl;
  cout << "Default for dmp: 'dmp.xml' " << endl;
}

/** Main function
 * \param[in] n_args Number of arguments
 * \param[in] args Arguments themselves
 * \return Success of exection. 0 if successful.
 */
int main(int n_args, char** args)
{

  string input_txt_file;
  string directory;
  string output_xml_file("dmp.xml");
  if (n_args<3)
  {
    help(args[0]);
    return -1;
  }

  if (string(args[1]).compare("--help")==0)
  {
    help(args[0]);
    return 0;
  }

  input_txt_file = string(args[1]);
  directory = string(args[2]);
  if (n_args>3)
    output_xml_file = string(args[3]);

  cout << "Reading trajectory from TXT file: " << input_txt_file << endl;
  Trajectory trajectory = Trajectory::readFromFile(input_txt_file);
  if (trajectory.length()==0)
  {
    cerr << "The TXT file " << input_txt_file << " could not be found. Aborting." << endl << endl;
    help(args[0]);
    return -1;
  }

  //double tau = trajectory.duration();
  //int n_time_steps = trajectory.length();
  VectorXd ts = trajectory.ts(); // Time steps
  int n_dims = trajectory.dim();

  // Initialize some meta parameters for training LWR function approximator
  int n_basis_functions = 3;
  int input_dim = 1;
  double intersection = 0.56;
  MetaParametersLWR* meta_parameters = new MetaParametersLWR(input_dim,n_basis_functions,intersection);
  FunctionApproximatorLWR* fa_lwr = new FunctionApproximatorLWR(meta_parameters);

  // Clone the function approximator for each dimension of the DMP
  vector<FunctionApproximator*> function_approximators(n_dims);
  for (int dd=0; dd<n_dims; dd++)
    function_approximators[dd] = fa_lwr->clone();

  // Initialize the DMP
  Dmp* dmp = new Dmp(n_dims, function_approximators, Dmp::KULVICIUS_2012_JOINING);

  cout << "Training Dmp..." << endl;
  bool overwrite = true;
  dmp->train(trajectory,directory+"/train",overwrite);

  cout << "Writing trained Dmp to XML file: " << directory << "/" << output_xml_file << endl;
  // Make directory if it doesn't already exist
  if (!boost::filesystem::exists(directory))
  {
    if (!boost::filesystem::create_directories(directory))
    {
      cerr << __FILE__ << ":" << __LINE__ << ":";
      cerr << "Couldn't make directory file '" << directory << "'." << endl;
      return false;
    }
  }

  std::ofstream ofs(directory+"/"+output_xml_file);
  boost::archive::xml_oarchive oa(ofs);
  oa << boost::serialization::make_nvp("dmp",dmp);
  ofs.close();

  delete meta_parameters;
  delete fa_lwr;
  delete dmp;

  return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2010-2012 Jeremy Lainé
 * Contact: http://code.google.com/p/qdjango/
 *
 * This file is part of the QDjango Library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 */

#include "QDjango.h"
#include "QDjangoModel.h"
#include "QDjangoQuerySet.h"
#include "QDjangoWhere.h"
#include "util.h"

class Author : public QDjangoModel
{
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName)

public:
    Author(QObject *parent = 0);

    QString name() const;
    void setName(const QString &name);

private:
    QString m_name;
};

class Book : public QDjangoModel
{
    Q_OBJECT
    Q_PROPERTY(Author* author READ author WRITE setAuthor)
    Q_PROPERTY(QString title READ title WRITE setTitle)

public:
    Book(QObject *parent = 0);

    Author *author() const;
    void setAuthor(Author *author);

    QString title() const;
    void setTitle(const QString &title);

private:
    QString m_title;
};

/** Test QDjangoModel class.
 */
class tst_QDjangoModel : public QObject
{
    Q_OBJECT

private slots:
    void initTestCase();
    void filterRelated();
    void selectRelated();
    void cleanup();
    void cleanupTestCase();
};

Author::Author(QObject *parent)
    : QDjangoModel(parent)
{
}

QString Author::name() const
{
    return m_name;
}

void Author::setName(const QString &name)
{
    m_name = name;
}

Book::Book(QObject *parent)
    : QDjangoModel(parent)
{
    setForeignKey("author", new Author(this));
}

Author* Book::author() const
{
    return qobject_cast<Author*>(foreignKey("author"));
}

void Book::setAuthor(Author *author)
{
    setForeignKey("author", author);
}

QString Book::title() const
{
    return m_title;
}

void Book::setTitle(const QString &title)
{
    m_title = title;
}

/** Create database tables before running tests.
 */
void tst_QDjangoModel::initTestCase()
{
    QVERIFY(initialiseDatabase());
    QCOMPARE(QDjango::registerModel<Author>().createTable(), true);
    QCOMPARE(QDjango::registerModel<Book>().createTable(), true);
}

/** Perform filtering on foreign keys.
 */
void tst_QDjangoModel::filterRelated()
{
    // load fixtures
    {
        Author author;
        author.setName("first");
        QCOMPARE(author.save(), true);

        Book book;
        book.setAuthor(&author);
        book.setTitle("Some book");
        QCOMPARE(book.save(), true);
    }

    // perform filtering
    QDjangoQuerySet<Book> books;

    QDjangoQuerySet<Book> qs = books.filter(
        QDjangoWhere("author__name", QDjangoWhere::Equals, "first"));
    CHECKWHERE(qs.where(), QLatin1String("T0.\"name\" = ?"), QVariantList() << "first");
    QCOMPARE(qs.count(), 1);
    QCOMPARE(qs.size(), 1);

    Book *book = qs.at(0);
    QVERIFY(book != 0);
    QCOMPARE(book->title(), QLatin1String("Some book"));
    delete book;
}

/** Test eager loading of foreign keys.
 */
void tst_QDjangoModel::selectRelated()
{
    // load fixtures
    {
        Author author;
        author.setName("first");
        QCOMPARE(author.save(), true);

        Book book;
        book.setAuthor(&author);
        book.setTitle("Some book");
        QCOMPARE(book.save(), true);
    }

    // without eager loading
    QDjangoQuerySet<Book> qs;
    Book *book = qs.get(QDjangoWhere("title", QDjangoWhere::Equals, "Some book"));
    QVERIFY(book != 0);
    QCOMPARE(book->title(), QLatin1String("Some book"));
    QCOMPARE(book->author()->name(), QLatin1String("first"));
    delete book;

    // with eager loading
    book = qs.selectRelated().get(QDjangoWhere("title", QDjangoWhere::Equals, "Some book"));
    QVERIFY(book != 0);
    QCOMPARE(book->title(), QLatin1String("Some book"));
    QCOMPARE(book->author()->name(), QLatin1String("first"));
    delete book;
}

/** Clear database tables after each test.
 */
void tst_QDjangoModel::cleanup()
{
    QCOMPARE(QDjangoQuerySet<Book>().remove(), true);
    QCOMPARE(QDjangoQuerySet<Author>().remove(), true);
}

/** Drop database tables after running tests.
 */
void tst_QDjangoModel::cleanupTestCase()
{
    QCOMPARE(QDjango::registerModel<Book>().dropTable(), true);
    QCOMPARE(QDjango::registerModel<Author>().dropTable(), true);
}

QTEST_MAIN(tst_QDjangoModel)
#include "tst_qdjangomodel.moc"
<commit_msg>cleanup fixture loading<commit_after>/*
 * Copyright (C) 2010-2012 Jeremy Lainé
 * Contact: http://code.google.com/p/qdjango/
 *
 * This file is part of the QDjango Library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 */

#include "QDjango.h"
#include "QDjangoModel.h"
#include "QDjangoQuerySet.h"
#include "QDjangoWhere.h"
#include "util.h"

class Author : public QDjangoModel
{
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName)

public:
    Author(QObject *parent = 0);

    QString name() const;
    void setName(const QString &name);

private:
    QString m_name;
};

class Book : public QDjangoModel
{
    Q_OBJECT
    Q_PROPERTY(Author* author READ author WRITE setAuthor)
    Q_PROPERTY(QString title READ title WRITE setTitle)

public:
    Book(QObject *parent = 0);

    Author *author() const;
    void setAuthor(Author *author);

    QString title() const;
    void setTitle(const QString &title);

private:
    QString m_title;
};

/** Test QDjangoModel class.
 */
class tst_QDjangoModel : public QObject
{
    Q_OBJECT

private slots:
    void initTestCase();
    void init();
    void filterRelated();
    void selectRelated();
    void cleanup();
    void cleanupTestCase();
};

Author::Author(QObject *parent)
    : QDjangoModel(parent)
{
}

QString Author::name() const
{
    return m_name;
}

void Author::setName(const QString &name)
{
    m_name = name;
}

Book::Book(QObject *parent)
    : QDjangoModel(parent)
{
    setForeignKey("author", new Author(this));
}

Author* Book::author() const
{
    return qobject_cast<Author*>(foreignKey("author"));
}

void Book::setAuthor(Author *author)
{
    setForeignKey("author", author);
}

QString Book::title() const
{
    return m_title;
}

void Book::setTitle(const QString &title)
{
    m_title = title;
}

/** Create database tables before running tests.
 */
void tst_QDjangoModel::initTestCase()
{
    QVERIFY(initialiseDatabase());
    QCOMPARE(QDjango::registerModel<Author>().createTable(), true);
    QCOMPARE(QDjango::registerModel<Book>().createTable(), true);
}

/** Load fixtures.
 */
void tst_QDjangoModel::init()
{
    Author author;
    author.setName("first");
    QCOMPARE(author.save(), true);

    Book book;
    book.setAuthor(&author);
    book.setTitle("Some book");
    QCOMPARE(book.save(), true);
}

/** Perform filtering on foreign keys.
 */
void tst_QDjangoModel::filterRelated()
{
    QDjangoQuerySet<Book> books;

    QDjangoQuerySet<Book> qs = books.filter(
        QDjangoWhere("author__name", QDjangoWhere::Equals, "first"));
    CHECKWHERE(qs.where(), QLatin1String("T0.\"name\" = ?"), QVariantList() << "first");
    QCOMPARE(qs.count(), 1);
    QCOMPARE(qs.size(), 1);

    Book *book = qs.at(0);
    QVERIFY(book != 0);
    QCOMPARE(book->title(), QLatin1String("Some book"));
    delete book;
}

/** Test eager loading of foreign keys.
 */
void tst_QDjangoModel::selectRelated()
{
    // without eager loading
    QDjangoQuerySet<Book> qs;
    Book *book = qs.get(QDjangoWhere("title", QDjangoWhere::Equals, "Some book"));
    QVERIFY(book != 0);
    QCOMPARE(book->title(), QLatin1String("Some book"));
    QVERIFY(book->author() != 0);
    QCOMPARE(book->author()->name(), QLatin1String("first"));
    delete book;

    // with eager loading
    book = qs.selectRelated().get(QDjangoWhere("title", QDjangoWhere::Equals, "Some book"));
    QVERIFY(book != 0);
    QCOMPARE(book->title(), QLatin1String("Some book"));
    QVERIFY(book->author() != 0);
    QCOMPARE(book->author()->name(), QLatin1String("first"));
    delete book;
}

/** Clear database tables after each test.
 */
void tst_QDjangoModel::cleanup()
{
    QCOMPARE(QDjangoQuerySet<Book>().remove(), true);
    QCOMPARE(QDjangoQuerySet<Author>().remove(), true);
}

/** Drop database tables after running tests.
 */
void tst_QDjangoModel::cleanupTestCase()
{
    QCOMPARE(QDjango::registerModel<Book>().dropTable(), true);
    QCOMPARE(QDjango::registerModel<Author>().dropTable(), true);
}

QTEST_MAIN(tst_QDjangoModel)
#include "tst_qdjangomodel.moc"
<|endoftext|>


<commit_before>//
// (c) Copyright 2017 DESY,ESS
//
// This file is part of h5pp.
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
// Boston, MA  02110-1301 USA
// ===========================================================================
//
// Author: Eugen Wintersberger <eugen.wintersberger@desy.de>
// Created on: Oct 24, 2017
//
#include <gtest/gtest.h>
#include <h5cpp/hdf5.hpp>

struct DatasetFixedStringIO : public testing::Test
{
  hdf5::file::File file;
  hdf5::node::Group root_group;
  hdf5::datatype::String string_type;
  hdf5::dataspace::Scalar scalar_space;
  hdf5::dataspace::Simple simple_space;
  hdf5::property::DatasetTransferList dtpl;

  DatasetFixedStringIO():
    file(hdf5::file::create("DatasetFixedStringIO.h5",hdf5::file::AccessFlags::TRUNCATE)),
    root_group(file.root()),
    string_type(hdf5::datatype::String::fixed(5)),
    scalar_space(),
    simple_space({2,3}),
    dtpl(hdf5::property::DatasetTransferList())
  {
    string_type.encoding(hdf5::datatype::CharacterEncoding::UTF8);
    string_type.padding(hdf5::datatype::StringPad::NULLTERM);
  }
};

using namespace hdf5;

TEST_F(DatasetFixedStringIO,scalar_auto_config)
{
  node::Dataset dset(root_group,Path("data"),string_type,scalar_space);

  std::string write_value = "hello";
  EXPECT_NO_THROW(dset.write(write_value,string_type,scalar_space,scalar_space,dtpl));
  std::string read_value;
  EXPECT_NO_THROW(dset.read(read_value,string_type,scalar_space,scalar_space,dtpl));

  EXPECT_EQ(write_value,read_value);

}

TEST_F(DatasetFixedStringIO,vector_no_auto_config)
{
  node::Dataset dset(root_group,Path("data"),string_type,simple_space);

  std::vector<std::string> write{"AAAAA","BBBBB","CCCCC","DDDDD","EEEEE","FFFFF"};
  EXPECT_NO_THROW(dset.write(write,string_type,simple_space,simple_space,dtpl));
  std::vector<std::string> read;
  EXPECT_NO_THROW(dset.read(read,string_type,simple_space,simple_space,dtpl));
  EXPECT_EQ(write,read);
}

TEST_F(DatasetFixedStringIO,single_value_read)
{
  node::Dataset dset(root_group,Path("data"),string_type,simple_space);
  std::vector<std::string> write{"AAAAA","BBBBB","CCCCC","DDDDD","EEEEE","FFFFF"};
  EXPECT_NO_THROW(dset.write(write,string_type,simple_space,simple_space,dtpl));

  auto read_type = datatype::String::fixed(10);
  read_type.padding(datatype::StringPad::SPACEPAD);
  read_type.encoding(datatype::CharacterEncoding::UTF8);
  std::string buffer;
  dset.read(buffer,read_type,dataspace::Scalar(),dataspace::Hyperslab{{0,0},{1,1}});
  EXPECT_EQ(buffer,std::string("AAAAA     "));
  dset.read(buffer,read_type,dataspace::Scalar(),dataspace::Hyperslab{{1,2},{1,1}});
  EXPECT_EQ(buffer,"FFFFF     ");

}

<commit_msg>Have now a even more complex selection to read fixed len strings<commit_after>//
// (c) Copyright 2017 DESY,ESS
//
// This file is part of h5pp.
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
// Boston, MA  02110-1301 USA
// ===========================================================================
//
// Author: Eugen Wintersberger <eugen.wintersberger@desy.de>
// Created on: Oct 24, 2017
//
#include <gtest/gtest.h>
#include <h5cpp/hdf5.hpp>

struct DatasetFixedStringIO : public testing::Test
{
  hdf5::file::File file;
  hdf5::node::Group root_group;
  hdf5::datatype::String string_type;
  hdf5::dataspace::Scalar scalar_space;
  hdf5::dataspace::Simple simple_space;
  hdf5::property::DatasetTransferList dtpl;

  DatasetFixedStringIO():
    file(hdf5::file::create("DatasetFixedStringIO.h5",hdf5::file::AccessFlags::TRUNCATE)),
    root_group(file.root()),
    string_type(hdf5::datatype::String::fixed(5)),
    scalar_space(),
    simple_space({2,3}),
    dtpl(hdf5::property::DatasetTransferList())
  {
    string_type.encoding(hdf5::datatype::CharacterEncoding::UTF8);
    string_type.padding(hdf5::datatype::StringPad::NULLTERM);
  }
};

using namespace hdf5;

TEST_F(DatasetFixedStringIO,scalar_auto_config)
{
  node::Dataset dset(root_group,Path("data"),string_type,scalar_space);

  std::string write_value = "hello";
  EXPECT_NO_THROW(dset.write(write_value,string_type,scalar_space,scalar_space,dtpl));
  std::string read_value;
  EXPECT_NO_THROW(dset.read(read_value,string_type,scalar_space,scalar_space,dtpl));

  EXPECT_EQ(write_value,read_value);

}

TEST_F(DatasetFixedStringIO,vector_no_auto_config)
{
  node::Dataset dset(root_group,Path("data"),string_type,simple_space);

  std::vector<std::string> write{"AAAAA","BBBBB","CCCCC","DDDDD","EEEEE","FFFFF"};
  EXPECT_NO_THROW(dset.write(write,string_type,simple_space,simple_space,dtpl));
  std::vector<std::string> read;
  EXPECT_NO_THROW(dset.read(read,string_type,simple_space,simple_space,dtpl));
  EXPECT_EQ(write,read);
}

TEST_F(DatasetFixedStringIO,single_value_read)
{
  node::Dataset dset(root_group,Path("data"),string_type,simple_space);
  std::vector<std::string> write{"AAAAA","BBBBB","CCCCC","DDDDD","EEEEE","FFFFF"};
  EXPECT_NO_THROW(dset.write(write,string_type,simple_space,simple_space,dtpl));

  auto read_type = datatype::String::fixed(10);
  read_type.padding(datatype::StringPad::SPACEPAD);
  read_type.encoding(datatype::CharacterEncoding::UTF8);
  std::string buffer;
  dset.read(buffer,read_type,dataspace::Scalar(),dataspace::Hyperslab{{0,0},{1,1}});
  EXPECT_EQ(buffer,std::string("AAAAA     "));
  dset.read(buffer,read_type,dataspace::Scalar(),dataspace::Hyperslab{{1,2},{1,1}});
  EXPECT_EQ(buffer,"FFFFF     ");
}

TEST_F(DatasetFixedStringIO,complex_selection)
{
  node::Dataset dset(root_group,Path("data"),string_type,simple_space);
  std::vector<std::string> write{"AAAAA","BBBBB","CCCCC","DDDDD","EEEEE","FFFFF"};
  EXPECT_NO_THROW(dset.write(write,string_type,simple_space,simple_space,dtpl));

  auto read_type = datatype::String::fixed(6);
  read_type.padding(datatype::StringPad::SPACEPAD);
  read_type.encoding(datatype::CharacterEncoding::UTF8);

  dataspace::Hyperslab selection{{0,0},{2,1},{1,2},{1,2}};
  std::vector<std::string> read(4);
  dset.read(read,read_type,dataspace::Simple{{4}},selection);

  EXPECT_EQ(read,(std::vector<std::string>{"AAAAA ","CCCCC ","DDDDD ","FFFFF "}));

}

<|endoftext|>