<commit_before>
#include "input/Input.hpp"
#include "raycaster/Intersection.hpp"
#include "resources/ResourcesManager.hpp"
#include "graphics/ScreenQuad.hpp"
#include "graphics/Framebuffer.hpp"
#include "graphics/GLUtilities.hpp"
#include "system/Window.hpp"
#include "system/System.hpp"
#include "generation/Random.hpp"
#include "system/Config.hpp"
#include "Common.hpp"

#include "AtmosphereApp.hpp"

AtmosphereApp::AtmosphereApp(RenderingConfig & config) : CameraApp(config) {
	_userCamera.projection(config.screenResolution[0] / config.screenResolution[1], 1.34f, 0.1f, 100.0f);
	// Framebuffer to store the rendered atmosphere result before tonemapping and upscaling to the window size.
	const glm::vec2 renderRes = _config.renderingResolution();
	_atmosphereBuffer.reset(new Framebuffer(uint(renderRes[0]), uint(renderRes[1]), {Layout::RGB32F, Filter::LINEAR_NEAREST, Wrap::CLAMP}, false, "Atmosphere"));
	// Atmosphere screen quad.
	_atmosphere = Resources::manager().getProgram2D("atmosphere_params");
	// Final tonemapping screen quad.
	_tonemap = Resources::manager().getProgram2D("tonemap");
	// Sun direction.
	_lightDirection = glm::normalize(glm::vec3(0.337f, 0.174f, -0.925f));
	// Populate lookup table.
	updateSky();

	GLUtilities::setDepthState(true);
	checkGLError();
}

void AtmosphereApp::draw() {
	// Render.
	const glm::mat4 camToWorld = glm::inverse(_userCamera.view());
	const glm::mat4 clipToCam  = glm::inverse(_userCamera.projection());

	// Draw the atmosphere.
	GLUtilities::setDepthState(false);
	_atmosphereBuffer->bind();
	_atmosphereBuffer->setViewport();
	GLUtilities::clearColor({0.0f, 0.0f, 0.0f, 1.0f});

	_atmosphere->use();
	const glm::mat4 camToWorldNoT = glm::mat4(glm::mat3(camToWorld));
	const glm::mat4 clipToWorld	  = camToWorldNoT * clipToCam;
	_atmosphere->uniform("clipToWorld", clipToWorld);
	_atmosphere->uniform("viewPos", _userCamera.position());
	_atmosphere->uniform("lightDirection", _lightDirection);
	_atmosphere->uniform("altitude", _altitude);
	// Send the atmosphere parameters.
	_atmosphere->uniform("atmoParams.sunColor", _atmoParams.sunColor);
	_atmosphere->uniform("atmoParams.kRayleigh", _atmoParams.kRayleigh);
	_atmosphere->uniform("atmoParams.groundRadius", _atmoParams.groundRadius);
	_atmosphere->uniform("atmoParams.topRadius", _atmoParams.topRadius);
	_atmosphere->uniform("atmoParams.sunIntensity", _atmoParams.sunIntensity);
	_atmosphere->uniform("atmoParams.kMie", _atmoParams.kMie);
	_atmosphere->uniform("atmoParams.heightRayleigh", _atmoParams.heightRayleigh);
	_atmosphere->uniform("atmoParams.heightMie", _atmoParams.heightMie);
	_atmosphere->uniform("atmoParams.gMie", _atmoParams.gMie);
	_atmosphere->uniform("atmoParams.sunAngularRadius", _atmoParams.sunRadius);
	_atmosphere->uniform("atmoParams.sunAngularRadiusCos", _atmoParams.sunRadiusCos);

	ScreenQuad::draw(_scattering);
	_atmosphereBuffer->unbind();

	// Tonemapping and final screen.
	GLUtilities::setViewport(0, 0, int(_config.screenResolution[0]), int(_config.screenResolution[1]));
	Framebuffer::backbuffer()->bind(Framebuffer::Mode::SRGB);
	_tonemap->use();
	ScreenQuad::draw(_atmosphereBuffer->texture());
	Framebuffer::backbuffer()->unbind();
}

void AtmosphereApp::update() {
	CameraApp::update();

	if(ImGui::Begin("Atmosphere")) {
		ImGui::Text("%.1f ms, %.1f fps", frameTime() * 1000.0f, frameRate());

		// Sun parameters.
		ImGui::PushItemWidth(120);
		bool shouldUpdateSky = false;
		if(ImGui::DragFloat("Azimuth", &_lightAzimuth, 0.1f, 0.0f, 360.0f, "%.1f°")) {
			_lightAzimuth	= glm::clamp(_lightAzimuth, 0.0f, 360.0f);
			shouldUpdateSky = true;
		}
		ImGui::SameLine();
		if(ImGui::DragFloat("Elevation", &_lightElevation, 0.1f, -15.0f, 90.0f, "%.1f°")) {
			_lightElevation = glm::clamp(_lightElevation, -15.0f, 90.0f);
			shouldUpdateSky = true;
		}
		ImGui::PopItemWidth();

		if(shouldUpdateSky) {
			const float elevRad = _lightElevation / 180 * glm::pi<float>();
			const float azimRad = _lightAzimuth / 180 * glm::pi<float>();
			_lightDirection		= glm::vec3(std::cos(azimRad) * std::cos(elevRad), std::sin(elevRad), std::sin(azimRad) * std::cos(elevRad));
		}

		ImGui::DragFloat("Altitude", &_altitude, 10.0f, 0.0f, 0.0f, "%.0fm", 2.0f);

		if(ImGui::CollapsingHeader("Atmosphere parameters")) {
			bool updateScattering = false;

			updateScattering = ImGui::InputInt("Resolution", &_tableRes) || updateScattering;
			updateScattering = ImGui::InputInt("Samples", &_tableSamples) || updateScattering;

			if(ImGui::Button("Reset")) {
				_atmoParams		 = Sky::AtmosphereParameters();
				updateScattering = true;
			}
			updateScattering = ImGui::SliderFloat("Mie height", &_atmoParams.heightMie, 100.0f, 20000.0f) || updateScattering;

			updateScattering = ImGui::SliderFloat("Mie K", &_atmoParams.kMie, 1e-6f, 100e-6f, "%.6f") || updateScattering;

			updateScattering = ImGui::SliderFloat("Rayleigh height", &_atmoParams.heightRayleigh, 100.0f, 20000.0f) || updateScattering;
			updateScattering = ImGui::SliderFloat3("Rayleigh K", &_atmoParams.kRayleigh[0], 1e-6f, 100e-6f, "%.6f") || updateScattering;

			updateScattering = ImGui::SliderFloat("Ground radius", &_atmoParams.groundRadius, 1e6f, 10e6f) || updateScattering;
			updateScattering = ImGui::SliderFloat("Atmosphere radius", &_atmoParams.topRadius, 1e6f, 10e6f) || updateScattering;

			if(updateScattering) {
				updateSky();
			}

			ImGui::SliderFloat("Mie G", &_atmoParams.gMie, 0.0f, 1.0f);
			if(ImGui::SliderFloat("Sun diameter", &_atmoParams.sunRadius, 0.0f, 0.1f)) {
				_atmoParams.sunRadiusCos = std::cos(_atmoParams.sunRadius);
			}
			ImGui::SliderFloat("Sun intensity", &_atmoParams.sunIntensity, 0.0f, 20.0f);

		}
	}
	ImGui::End();
}

void AtmosphereApp::resize() {
	_atmosphereBuffer->resize(_config.renderingResolution());
}

void AtmosphereApp::precomputeTable(const Sky::AtmosphereParameters & params, uint samples, Image & table) {

	// Parameters.
	const uint res = table.width;

	System::forParallel(0, res, [&](size_t y) {
		for(size_t x = 0; x < res; ++x) {
			// Move to 0,1.
			// No need to take care of the 0.5 shift as we are working with indices
			const float xf = float(x) / (res - 1.0f);
			const float yf = float(y) / (res - 1.0f);
			// Position and ray direction.
			// x becomes the height
			// y become the cosine
			const glm::vec3 currPos = glm::vec3(0.0f, (params.topRadius - params.groundRadius) * xf + params.groundRadius, 0.0f);
			const float cosA		= 2.0f * yf - 1.0f;
			const float sinA		= std::sqrt(1.0f - cosA * cosA);
			const glm::vec3 sunDir	= -glm::normalize(glm::vec3(sinA, cosA, 0.0f));
			// Check when the ray leaves the atmosphere.
			glm::vec2 interSecondTop;
			const bool didHitSecondTop = Intersection::sphere(currPos, sunDir, params.topRadius, interSecondTop);
			// Divide the distance traveled through the atmosphere in samplesCount parts.
			const float secondStepSize = didHitSecondTop ? interSecondTop.y / float(samples) : 0.0f;

			// Accumulate optical distance for both scatterings.
			float rayleighSecondDist = 0.0;
			float mieSecondDist		 = 0.0;

			// March along the secondary ray.
			for(unsigned int j = 0; j < samples; ++j) {
				// Compute the current position along the ray, ...
				const glm::vec3 currSecondPos = currPos + (float(j) + 0.5f) * secondStepSize * sunDir;
				// ...and its distance to the ground (as we are in planet space).
				const float currSecondHeight = glm::length(currSecondPos) - params.groundRadius;
				// Compute density based on the characteristic height of Rayleigh and Mie.
				const float rayleighSecondStep = exp(-currSecondHeight / params.heightRayleigh) * secondStepSize;
				const float mieSecondStep	   = exp(-currSecondHeight / params.heightMie) * secondStepSize;
				// Accumulate optical distances.
				rayleighSecondDist += rayleighSecondStep;
				mieSecondDist += mieSecondStep;
			}

			// Compute associated attenuation.
			const glm::vec3 secondaryAttenuation = exp(-(params.kMie * mieSecondDist + params.kRayleigh * rayleighSecondDist));
			table.rgb(int(x), int(y))			 = secondaryAttenuation;
		}
	});
}

void AtmosphereApp::updateSky() {
	Log::Info() << Log::Resources << "Updating sky..." << std::flush;
	_scattering.width = _scattering.height = uint(_tableRes);
	_scattering.levels = _scattering.depth = 1;
	_scattering.shape					   = TextureShape::D2;
	_scattering.clean();
	_scattering.images.emplace_back(_scattering.width, _scattering.height, 3);

	// Update the lookup table.
	precomputeTable(_atmoParams, uint(_tableSamples), _scattering.images[0]);

	_scattering.upload({Layout::RGB32F, Filter::LINEAR, Wrap::CLAMP}, false);

	Log::Info() << " done." << std::endl;
}
<commit_msg>Atmosphere: initialize LUT.<commit_after>
#include "input/Input.hpp"
#include "raycaster/Intersection.hpp"
#include "resources/ResourcesManager.hpp"
#include "graphics/ScreenQuad.hpp"
#include "graphics/Framebuffer.hpp"
#include "graphics/GLUtilities.hpp"
#include "system/Window.hpp"
#include "system/System.hpp"
#include "generation/Random.hpp"
#include "system/Config.hpp"
#include "Common.hpp"

#include "AtmosphereApp.hpp"

AtmosphereApp::AtmosphereApp(RenderingConfig & config) : CameraApp(config), _scattering("Scattering LUT") {
	_userCamera.projection(config.screenResolution[0] / config.screenResolution[1], 1.34f, 0.1f, 100.0f);
	// Framebuffer to store the rendered atmosphere result before tonemapping and upscaling to the window size.
	const glm::vec2 renderRes = _config.renderingResolution();
	_atmosphereBuffer.reset(new Framebuffer(uint(renderRes[0]), uint(renderRes[1]), {Layout::RGB32F, Filter::LINEAR_NEAREST, Wrap::CLAMP}, false, "Atmosphere"));
	// Atmosphere screen quad.
	_atmosphere = Resources::manager().getProgram2D("atmosphere_params");
	// Final tonemapping screen quad.
	_tonemap = Resources::manager().getProgram2D("tonemap");
	// Sun direction.
	_lightDirection = glm::normalize(glm::vec3(0.337f, 0.174f, -0.925f));
	// Populate lookup table.
	updateSky();

	GLUtilities::setDepthState(true);
	checkGLError();
}

void AtmosphereApp::draw() {
	// Render.
	const glm::mat4 camToWorld = glm::inverse(_userCamera.view());
	const glm::mat4 clipToCam  = glm::inverse(_userCamera.projection());

	// Draw the atmosphere.
	GLUtilities::setDepthState(false);
	_atmosphereBuffer->bind();
	_atmosphereBuffer->setViewport();
	GLUtilities::clearColor({0.0f, 0.0f, 0.0f, 1.0f});

	_atmosphere->use();
	const glm::mat4 camToWorldNoT = glm::mat4(glm::mat3(camToWorld));
	const glm::mat4 clipToWorld	  = camToWorldNoT * clipToCam;
	_atmosphere->uniform("clipToWorld", clipToWorld);
	_atmosphere->uniform("viewPos", _userCamera.position());
	_atmosphere->uniform("lightDirection", _lightDirection);
	_atmosphere->uniform("altitude", _altitude);
	// Send the atmosphere parameters.
	_atmosphere->uniform("atmoParams.sunColor", _atmoParams.sunColor);
	_atmosphere->uniform("atmoParams.kRayleigh", _atmoParams.kRayleigh);
	_atmosphere->uniform("atmoParams.groundRadius", _atmoParams.groundRadius);
	_atmosphere->uniform("atmoParams.topRadius", _atmoParams.topRadius);
	_atmosphere->uniform("atmoParams.sunIntensity", _atmoParams.sunIntensity);
	_atmosphere->uniform("atmoParams.kMie", _atmoParams.kMie);
	_atmosphere->uniform("atmoParams.heightRayleigh", _atmoParams.heightRayleigh);
	_atmosphere->uniform("atmoParams.heightMie", _atmoParams.heightMie);
	_atmosphere->uniform("atmoParams.gMie", _atmoParams.gMie);
	_atmosphere->uniform("atmoParams.sunAngularRadius", _atmoParams.sunRadius);
	_atmosphere->uniform("atmoParams.sunAngularRadiusCos", _atmoParams.sunRadiusCos);

	ScreenQuad::draw(_scattering);
	_atmosphereBuffer->unbind();

	// Tonemapping and final screen.
	GLUtilities::setViewport(0, 0, int(_config.screenResolution[0]), int(_config.screenResolution[1]));
	Framebuffer::backbuffer()->bind(Framebuffer::Mode::SRGB);
	_tonemap->use();
	ScreenQuad::draw(_atmosphereBuffer->texture());
	Framebuffer::backbuffer()->unbind();
}

void AtmosphereApp::update() {
	CameraApp::update();

	if(ImGui::Begin("Atmosphere")) {
		ImGui::Text("%.1f ms, %.1f fps", frameTime() * 1000.0f, frameRate());

		// Sun parameters.
		ImGui::PushItemWidth(120);
		bool shouldUpdateSky = false;
		if(ImGui::DragFloat("Azimuth", &_lightAzimuth, 0.1f, 0.0f, 360.0f, "%.1f°")) {
			_lightAzimuth	= glm::clamp(_lightAzimuth, 0.0f, 360.0f);
			shouldUpdateSky = true;
		}
		ImGui::SameLine();
		if(ImGui::DragFloat("Elevation", &_lightElevation, 0.1f, -15.0f, 90.0f, "%.1f°")) {
			_lightElevation = glm::clamp(_lightElevation, -15.0f, 90.0f);
			shouldUpdateSky = true;
		}
		ImGui::PopItemWidth();

		if(shouldUpdateSky) {
			const float elevRad = _lightElevation / 180 * glm::pi<float>();
			const float azimRad = _lightAzimuth / 180 * glm::pi<float>();
			_lightDirection		= glm::vec3(std::cos(azimRad) * std::cos(elevRad), std::sin(elevRad), std::sin(azimRad) * std::cos(elevRad));
		}

		ImGui::DragFloat("Altitude", &_altitude, 10.0f, 0.0f, 0.0f, "%.0fm", 2.0f);

		if(ImGui::CollapsingHeader("Atmosphere parameters")) {
			bool updateScattering = false;

			updateScattering = ImGui::InputInt("Resolution", &_tableRes) || updateScattering;
			updateScattering = ImGui::InputInt("Samples", &_tableSamples) || updateScattering;

			if(ImGui::Button("Reset")) {
				_atmoParams		 = Sky::AtmosphereParameters();
				updateScattering = true;
			}
			updateScattering = ImGui::SliderFloat("Mie height", &_atmoParams.heightMie, 100.0f, 20000.0f) || updateScattering;

			updateScattering = ImGui::SliderFloat("Mie K", &_atmoParams.kMie, 1e-6f, 100e-6f, "%.6f") || updateScattering;

			updateScattering = ImGui::SliderFloat("Rayleigh height", &_atmoParams.heightRayleigh, 100.0f, 20000.0f) || updateScattering;
			updateScattering = ImGui::SliderFloat3("Rayleigh K", &_atmoParams.kRayleigh[0], 1e-6f, 100e-6f, "%.6f") || updateScattering;

			updateScattering = ImGui::SliderFloat("Ground radius", &_atmoParams.groundRadius, 1e6f, 10e6f) || updateScattering;
			updateScattering = ImGui::SliderFloat("Atmosphere radius", &_atmoParams.topRadius, 1e6f, 10e6f) || updateScattering;

			if(updateScattering) {
				updateSky();
			}

			ImGui::SliderFloat("Mie G", &_atmoParams.gMie, 0.0f, 1.0f);
			if(ImGui::SliderFloat("Sun diameter", &_atmoParams.sunRadius, 0.0f, 0.1f)) {
				_atmoParams.sunRadiusCos = std::cos(_atmoParams.sunRadius);
			}
			ImGui::SliderFloat("Sun intensity", &_atmoParams.sunIntensity, 0.0f, 20.0f);

		}
	}
	ImGui::End();
}

void AtmosphereApp::resize() {
	_atmosphereBuffer->resize(_config.renderingResolution());
}

void AtmosphereApp::precomputeTable(const Sky::AtmosphereParameters & params, uint samples, Image & table) {

	// Parameters.
	const uint res = table.width;

	System::forParallel(0, res, [&](size_t y) {
		for(size_t x = 0; x < res; ++x) {
			// Move to 0,1.
			// No need to take care of the 0.5 shift as we are working with indices
			const float xf = float(x) / (res - 1.0f);
			const float yf = float(y) / (res - 1.0f);
			// Position and ray direction.
			// x becomes the height
			// y become the cosine
			const glm::vec3 currPos = glm::vec3(0.0f, (params.topRadius - params.groundRadius) * xf + params.groundRadius, 0.0f);
			const float cosA		= 2.0f * yf - 1.0f;
			const float sinA		= std::sqrt(1.0f - cosA * cosA);
			const glm::vec3 sunDir	= -glm::normalize(glm::vec3(sinA, cosA, 0.0f));
			// Check when the ray leaves the atmosphere.
			glm::vec2 interSecondTop;
			const bool didHitSecondTop = Intersection::sphere(currPos, sunDir, params.topRadius, interSecondTop);
			// Divide the distance traveled through the atmosphere in samplesCount parts.
			const float secondStepSize = didHitSecondTop ? interSecondTop.y / float(samples) : 0.0f;

			// Accumulate optical distance for both scatterings.
			float rayleighSecondDist = 0.0;
			float mieSecondDist		 = 0.0;

			// March along the secondary ray.
			for(unsigned int j = 0; j < samples; ++j) {
				// Compute the current position along the ray, ...
				const glm::vec3 currSecondPos = currPos + (float(j) + 0.5f) * secondStepSize * sunDir;
				// ...and its distance to the ground (as we are in planet space).
				const float currSecondHeight = glm::length(currSecondPos) - params.groundRadius;
				// Compute density based on the characteristic height of Rayleigh and Mie.
				const float rayleighSecondStep = exp(-currSecondHeight / params.heightRayleigh) * secondStepSize;
				const float mieSecondStep	   = exp(-currSecondHeight / params.heightMie) * secondStepSize;
				// Accumulate optical distances.
				rayleighSecondDist += rayleighSecondStep;
				mieSecondDist += mieSecondStep;
			}

			// Compute associated attenuation.
			const glm::vec3 secondaryAttenuation = exp(-(params.kMie * mieSecondDist + params.kRayleigh * rayleighSecondDist));
			table.rgb(int(x), int(y))			 = secondaryAttenuation;
		}
	});
}

void AtmosphereApp::updateSky() {
	Log::Info() << Log::Resources << "Updating sky..." << std::flush;
	_scattering.width = _scattering.height = uint(_tableRes);
	_scattering.levels = _scattering.depth = 1;
	_scattering.shape					   = TextureShape::D2;
	_scattering.clean();
	_scattering.images.emplace_back(_scattering.width, _scattering.height, 3);

	// Update the lookup table.
	precomputeTable(_atmoParams, uint(_tableSamples), _scattering.images[0]);

	_scattering.upload({Layout::RGB32F, Filter::LINEAR, Wrap::CLAMP}, false);

	Log::Info() << " done." << std::endl;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: TemplateScanner.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: kz $ $Date: 2004-08-31 13:48:46 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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.
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "TemplateScanner.hxx"

#ifndef _OSL_TIME_H_
#include <osl/time.h>
#endif

#ifndef _VOS_MUTEX_HXX
#include <vos/mutex.hxx>
#endif

#ifndef _SFXAPP_HXX
#include <sfx2/app.hxx>
#endif

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif

using namespace ::rtl;
using namespace ::ucb;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::ucb;

namespace {

const OUString TITLE            = OUString::createFromAscii ("Title");
const OUString TARGET_DIR_URL   = OUString::createFromAscii ("TargetDirURL");
const OUString DESCRIPTION      = OUString::createFromAscii ("TypeDescription");
const OUString TARGET_URL       = OUString::createFromAscii ("TargetURL");

const OUString DOCTEMPLATES     = OUString::createFromAscii ("com.sun.star.frame.DocumentTemplates");

//  These strings are used to find impress templates in the tree of
//  template files.  Should probably be determined dynamically.
const OUString IMPRESS_BIN_TEMPLATE = OUString::createFromAscii ("application/vnd.stardivision.impress");
const OUString IMPRESS_XML_TEMPLATE = OUString::createFromAscii ("application/vnd.sun.xml.impress");
// The following id comes from the bugdoc in #i2764#.
const OUString IMPRESS_XML_TEMPLATE_B = OUString::createFromAscii ("Impress 2.0");
const OUString IMPRESS_XML_TEMPLATE_OASIS = OUString::createFromAscii ("application/x-vnd.oasis.openoffice.presentation");

} // end of anonymous namespace

namespace sd
{

TemplateScanner::TemplateScanner (void)
{
    //  empty;
}

TemplateScanner::~TemplateScanner (void)
{
    // Delete all entries of the template list that have not been
    // transferred to another object.
    std::vector<TemplateDir*>::iterator I;
    for (I=maFolderList.begin(); I!=maFolderList.end(); I++)
        if (*I != NULL)
            delete *I;
}

void TemplateScanner::GetTemplateRoot (void)
{
    Reference<lang::XMultiServiceFactory> xFactory =
        ::comphelper::getProcessServiceFactory ();
    DBG_ASSERT (xFactory.is(),
        "TemplateScanner::GetTemplateRoot: xFactory is NULL");

    Reference<frame::XDocumentTemplates> xTemplates (
        xFactory->createInstance (DOCTEMPLATES), UNO_QUERY);
    DBG_ASSERT (xTemplates.is(),
        "TemplateScanner::GetTemplateRoot: xTemplates is NULL");

    if (xTemplates.is())
        mxTemplateRoot = xTemplates->getContent();

}

void TemplateScanner::ScanEntries (Content& rRoot, TemplateDir* pDir)
{
    Reference<XCommandEnvironment> aCmdEnv;

    //  We are interested only in three properties: the entry's name,
    //  its URL, and its content type.
    Sequence<OUString> aProps (3);
    aProps[0] = TITLE;
    aProps[1] = TARGET_URL;
    aProps[2] = DESCRIPTION;

    //  Create a cursor to iterate over the templates in this folders.
    ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
    Reference<XResultSet> xResultSet (rRoot.createCursor (aProps, eInclude));

    if (xResultSet.is())
    {
        Reference<XContentAccess> xContentAccess (xResultSet, UNO_QUERY);
        Reference<XRow> xRow (xResultSet, UNO_QUERY);

        //  Iterate over the template folder.
        while (xResultSet->next())
        {
            OUString aTitle (xRow->getString (1));
            OUString aTargetURL (xRow->getString (2));
            OUString aContentType (xRow->getString (3));

            OUString aId = xContentAccess->queryContentIdentifierString();
            Content  aContent = Content (aId, aCmdEnv);
            if ( ! aContent.isDocument ())
                continue;

            //  Check wether the entry is an impress template.  If so add a
            //  new entry to the resulting list (which is created first if
            //  necessary).
            if (    (aContentType == IMPRESS_XML_TEMPLATE_OASIS)
                ||  (aContentType == IMPRESS_BIN_TEMPLATE)
                ||  (aContentType == IMPRESS_XML_TEMPLATE)
                ||  (aContentType == IMPRESS_XML_TEMPLATE_B))
                pDir->m_aEntries.push_back (
                    new TemplateEntry (aTitle, aTargetURL));
        }
    }
}

void TemplateScanner::ScanFolders (void)
{
    try
    {
        //  Create content for template folders.
        Reference<XCommandEnvironment> aCmdEnv;
        Content aTemplateDir (mxTemplateRoot, aCmdEnv);

        //  Define the list of properties we are interested in.
        Sequence<OUString> aProps (2);
        aProps[0] = TITLE;
        aProps[1] = TARGET_DIR_URL;

        //  Create an cursor to iterate over the template folders.
        ResultSetInclude eInclude = INCLUDE_FOLDERS_ONLY;
        Reference<XResultSet> xResultSet (aTemplateDir.createCursor (
            aProps, eInclude));

        if (xResultSet.is())
        {
            Reference<XContentAccess> xContentAccess (xResultSet, UNO_QUERY);
            Reference<XRow> xRow (xResultSet, UNO_QUERY);

            while (xResultSet->next())
            {
                OUString aTitle (xRow->getString (1));
                OUString aTargetDir (xRow->getString (2));

                OUString aId = xContentAccess->queryContentIdentifierString();
                Content  aContent = Content (aId, aCmdEnv);
                if (aContent.isFolder())
                {
                    //  Scan the folder and insert it into the list of
                    //  template folders.
                    TemplateDir* pDir = new TemplateDir (aTitle, aTargetDir);
                    if (pDir != NULL)
                    {
                        ScanEntries (aContent, pDir);
                        if (pDir->m_aEntries.empty())
                            delete pDir;
                        else
                        {
                            ::vos::OGuard aGuard(Application::GetSolarMutex());
                            maFolderList.push_back(pDir);
                        }
                    }
                }
            }
        }
    }
    catch(::com::sun::star::uno::Exception&)
    {
        //  Ignore all exceptions.
    }
}

void TemplateScanner::Scan (void)
{
    GetTemplateRoot ();
    ScanFolders ();
}

std::vector<TemplateDir*>& TemplateScanner::GetFolderList (void)
{
    return maFolderList;
}

}
<commit_msg>INTEGRATION: CWS impress20ea (1.2.432); FILE MERGED 2004/10/14 13:02:28 af 1.2.432.2: RESYNC: (1.2-1.3); FILE MERGED 2004/09/15 07:47:14 af 1.2.432.1: #117500# Remove valgrind warning about accesing uninitialized memory.<commit_after>/*************************************************************************
 *
 *  $RCSfile: TemplateScanner.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: pjunck $ $Date: 2004-10-28 13:26:09 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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.
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "TemplateScanner.hxx"

#ifndef _OSL_TIME_H_
#include <osl/time.h>
#endif

#ifndef _VOS_MUTEX_HXX
#include <vos/mutex.hxx>
#endif

#ifndef _SFXAPP_HXX
#include <sfx2/app.hxx>
#endif

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif

using namespace ::rtl;
using namespace ::ucb;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::ucb;

namespace {

const OUString TITLE            = OUString::createFromAscii ("Title");
const OUString TARGET_DIR_URL   = OUString::createFromAscii ("TargetDirURL");
const OUString DESCRIPTION      = OUString::createFromAscii ("TypeDescription");
const OUString TARGET_URL       = OUString::createFromAscii ("TargetURL");

const OUString DOCTEMPLATES     = OUString::createFromAscii ("com.sun.star.frame.DocumentTemplates");

//  These strings are used to find impress templates in the tree of
//  template files.  Should probably be determined dynamically.
const OUString IMPRESS_BIN_TEMPLATE = OUString::createFromAscii ("application/vnd.stardivision.impress");
const OUString IMPRESS_XML_TEMPLATE = OUString::createFromAscii ("application/vnd.sun.xml.impress");
// The following id comes from the bugdoc in #i2764#.
const OUString IMPRESS_XML_TEMPLATE_B = OUString::createFromAscii ("Impress 2.0");
const OUString IMPRESS_XML_TEMPLATE_OASIS = OUString::createFromAscii ("application/x-vnd.oasis.openoffice.presentation");

} // end of anonymous namespace

namespace sd
{

TemplateScanner::TemplateScanner (void)
{
    //  empty;
}

TemplateScanner::~TemplateScanner (void)
{
    // Delete all entries of the template list that have not been
    // transferred to another object.
    std::vector<TemplateDir*>::iterator I;
    for (I=maFolderList.begin(); I!=maFolderList.end(); I++)
        if (*I != NULL)
            delete *I;
}

void TemplateScanner::GetTemplateRoot (void)
{
    Reference<lang::XMultiServiceFactory> xFactory =
        ::comphelper::getProcessServiceFactory ();
    DBG_ASSERT (xFactory.is(),
        "TemplateScanner::GetTemplateRoot: xFactory is NULL");

    Reference<frame::XDocumentTemplates> xTemplates (
        xFactory->createInstance (DOCTEMPLATES), UNO_QUERY);
    DBG_ASSERT (xTemplates.is(),
        "TemplateScanner::GetTemplateRoot: xTemplates is NULL");

    if (xTemplates.is())
        mxTemplateRoot = xTemplates->getContent();

}

void TemplateScanner::ScanEntries (Content& rRoot, TemplateDir* pDir)
{
    Reference<XCommandEnvironment> aCmdEnv;

    //  We are interested only in three properties: the entry's name,
    //  its URL, and its content type.
    Sequence<OUString> aProps (3);
    aProps[0] = TITLE;
    aProps[1] = TARGET_URL;
    aProps[2] = DESCRIPTION;

    //  Create a cursor to iterate over the templates in this folders.
    ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY;
    Reference<XResultSet> xResultSet (rRoot.createCursor (aProps, eInclude));

    if (xResultSet.is())
    {
        Reference<XContentAccess> xContentAccess (xResultSet, UNO_QUERY);
        Reference<XRow> xRow (xResultSet, UNO_QUERY);

        //  Iterate over the template folder.
        while (xResultSet->next())
        {
            OUString aTitle (xRow->getString (1));
            OUString aTargetURL (xRow->getString (2));
            OUString aContentType (xRow->getString (3));

            OUString aId = xContentAccess->queryContentIdentifierString();
            Content  aContent = Content (aId, aCmdEnv);
            if ( ! aContent.isDocument ())
                continue;

            //  Check wether the entry is an impress template.  If so add a
            //  new entry to the resulting list (which is created first if
            //  necessary).
            if (    (aContentType == IMPRESS_XML_TEMPLATE_OASIS)
                ||  (aContentType == IMPRESS_BIN_TEMPLATE)
                ||  (aContentType == IMPRESS_XML_TEMPLATE)
                ||  (aContentType == IMPRESS_XML_TEMPLATE_B))
                pDir->m_aEntries.push_back (
                    new TemplateEntry (aTitle, aTargetURL));
        }
    }
}

void TemplateScanner::ScanFolders (void)
{
    try
    {
        //  Create content for template folders.
        Reference<XCommandEnvironment> aCmdEnv;
        Content aTemplateDir (mxTemplateRoot, aCmdEnv);

        //  Define the list of properties we are interested in.
        Sequence<OUString> aProps (2);
        aProps[0] = TITLE;
        aProps[1] = TARGET_DIR_URL;

        //  Create an cursor to iterate over the template folders.
        ResultSetInclude eInclude = INCLUDE_FOLDERS_ONLY;
        Reference<XResultSet> xResultSet (aTemplateDir.createCursor (
            aProps, eInclude));

        if (xResultSet.is())
        {
            Reference<XContentAccess> xContentAccess (xResultSet, UNO_QUERY);

            while (xResultSet->next())
            {
                Reference<XRow> xRow (xResultSet, UNO_QUERY);
                if ( ! xRow.is())
                    continue;
                OUString aTitle (xRow->getString (1));
                OUString aTargetDir (xRow->getString (2));

                OUString aId = xContentAccess->queryContentIdentifierString();
                Content  aContent = Content (aId, aCmdEnv);
                if (aContent.isFolder())
                {
                    //  Scan the folder and insert it into the list of
                    //  template folders.
                    TemplateDir* pDir = new TemplateDir (aTitle, aTargetDir);
                    if (pDir != NULL)
                    {
                        ScanEntries (aContent, pDir);
                        if (pDir->m_aEntries.empty())
                            delete pDir;
                        else
                        {
                            ::vos::OGuard aGuard(Application::GetSolarMutex());
                            maFolderList.push_back(pDir);
                        }
                    }
                }
            }
        }
    }
    catch(::com::sun::star::uno::Exception&)
    {
        //  Ignore all exceptions.
    }
}

void TemplateScanner::Scan (void)
{
    GetTemplateRoot ();
    ScanFolders ();
}

std::vector<TemplateDir*>& TemplateScanner::GetFolderList (void)
{
    return maFolderList;
}

}
<|endoftext|>


<commit_before>/*
* ArcEmu MMORPG Server
 * Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
* Copyright (C) 2008 <http://www.ArcEmu.org/>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
*/

#include "StdAfx.h"

const char * GetDifficultyString(uint8 difficulty)
{
	switch(difficulty)
	{
	case MODE_NORMAL:
		return "normal";
	case MODE_HEROIC:
		return "heroic";
	case MODE_EPIC:
		return "epic";
	default:
		return "unknown";
	}
}

const char * GetMapTypeString(uint8 type)
{
	switch(type)
	{
	case INSTANCE_NULL:
		return "Continent";
	case INSTANCE_RAID:
		return "Raid";
	case INSTANCE_NONRAID:
		return "Non-Raid";
	case INSTANCE_PVP:
		return "PvP";
	case INSTANCE_MULTIMODE:
		return "MultiMode";
	default:
		return "Unknown";
	}
}

bool ChatHandler::HandleResetAllInstancesCommand(const char* args, WorldSession *m_session)
{
	Player * plr = getSelectedChar(m_session, true);
	if(!plr)
		return true;

	SystemMessage(m_session, "Trying to reset all instances of player %s...", plr->GetName());
	sInstanceMgr.ResetSavedInstances(plr);
	SystemMessage(m_session, "...done");

	sGMLog.writefromsession(m_session, "used reset all instances command on %s,", plr->GetName());
	return true;
}

bool ChatHandler::HandleResetInstanceCommand(const char* args, WorldSession *m_session)
{
	uint32 instanceId = (args ? atoi(args) : 0);
	if(instanceId == 0)
		return false;

	Player * plr = getSelectedChar(m_session, true);
	if(!plr)
		return true;

	Instance *instance = sInstanceMgr.GetInstanceByIds(NUM_MAPS, instanceId);
	if(instance == NULL)
	{
		RedSystemMessage(m_session, "There's no instance with id %u.", instanceId);
		return true;
	}

	if(IS_PERSISTENT_INSTANCE(instance))
	{
		if(m_session->CanUseCommand('z'))
		{
			bool foundSomething = false;
			plr->m_playerInfo->savedInstanceIdsLock.Acquire();
			for(int difficulty=0; difficulty<NUM_INSTANCE_MODES; difficulty++)
			{
				PlayerInstanceMap::iterator itr = plr->m_playerInfo->savedInstanceIds[difficulty].find(instance->m_mapId);
				if(itr == plr->m_playerInfo->savedInstanceIds[difficulty].end() || (*itr).second != instance->m_instanceId)
					continue;
				plr->SetPersistentInstanceId(instance->m_mapId, difficulty, 0);
				SystemMessage(m_session, "Instance with id %u (%s) is persistent and will only be revoked from player.", instanceId, GetDifficultyString(difficulty));
				foundSomething = true;
			}
			plr->m_playerInfo->savedInstanceIdsLock.Release();
			if(!foundSomething)
				RedSystemMessage(m_session, "Player is not assigned to persistent instance with id %u.", instanceId);
			return true;
		}
		else
		{
			RedSystemMessage(m_session, "Instance with id %u is persistent and can only be removed from player by admins.", instanceId);
			return true;
		}
	}

	if(instance->m_mapMgr && instance->m_mapMgr->HasPlayers())
	{
		RedSystemMessage(m_session, "Failed to reset non-persistent instance with id %u, due to player still inside.", instanceId);
		return true;
	}

	if(instance->m_creatorGroup)
	{
		Group *group = plr->GetGroup();
		if(group == NULL || instance->m_creatorGroup != group->GetID())
		{
			RedSystemMessage(m_session, "Player %s is not a member of the group assigned to the non-persistent instance with id %u.", plr->GetName(), instanceId);
			return true;
		}
	}
	else if(instance->m_creatorGuid == 0 || instance->m_creatorGuid != plr->GetLowGUID())
	{
		RedSystemMessage(m_session, "Player %s is not assigned to instance with id %u.", plr->GetName(), instanceId);
		return true;
	}

	//TODO: Reset that instance...^^
	RedSystemMessage(m_session, "Resetting single non-persistent instances is not available yet.");
	sGMLog.writefromsession(m_session, "used reset instance command on %s, instance %u,", plr->GetName(), instanceId);
	return true;
}

bool ChatHandler::HandleShutdownInstanceCommand(const char* args, WorldSession *m_session)
{
	//RedSystemMessage(m_session, "Command not implemented yet.");
	//return true;

	uint32 instanceId = (args ? atoi(args) : 0);
	if(instanceId == 0)
		return false;

	Instance *instance = sInstanceMgr.GetInstanceByIds(NUM_MAPS, instanceId);
	if(instance == NULL)
	{
		RedSystemMessage(m_session, "There's no instance with id %u.", instanceId);
		return true;
	}

	if(instance->m_mapMgr == NULL)
	{
		RedSystemMessage(m_session, "Instance with id %u already shut down.", instanceId);
		return true;
	}

	SystemMessage(m_session, "Attempting to shutdown instance with id %u...", instanceId);

	//Isn't there a better way?
	instance->m_mapMgr->InstanceShutdown();
	instance->m_mapMgr = NULL;
	delete instance->m_mapMgr;

	SystemMessage(m_session, "...done");

	sGMLog.writefromsession(m_session, "used shutdown instance command on instance %u,", instanceId);
	return true;
}

//bool ChatHandler::HandleDeleteInstanceCommand(const char* args, WorldSession *m_session)
//{
//	RedSystemMessage(m_session, "Command not implemented yet.");
//	return true;
//	//sGMLog.writefromsession(m_session, "used delete instance command on instance %u,", 0);
//}

bool ChatHandler::HandleGetInstanceInfoCommand(const char* args, WorldSession *m_session)
{
	Player *plr = m_session->GetPlayer();
	if(plr == NULL)
		return false;

	bool userInput = true;
	uint32 instanceId = (args ? atoi(args) : 0);
	if(instanceId == 0)
	{
		userInput = false;
		instanceId = plr->GetInstanceID();
		if(instanceId == 0)
			return false;
	}

	Instance *instance = sInstanceMgr.GetInstanceByIds(NUM_MAPS, instanceId);
	if(instance == NULL)
	{
		if(userInput)
		{
			RedSystemMessage(m_session, "Instance with id %u not found.", instanceId);
			return true;
		}
		return false;
	}

	std::stringstream ss;
	ss << "Instance ID: " << MSG_COLOR_CYAN << instance->m_instanceId << "|r (" << MSG_COLOR_CYAN;
	if(instance->m_mapInfo == NULL)
		ss << instance->m_mapId;
	else
		ss << instance->m_mapInfo->name;
	ss << "|r)\n";
	ss << "Persistent: " << MSG_COLOR_CYAN << (instance->m_persistent ? "Yes" : "No") << "|r\n";
	if(instance->m_mapInfo != NULL)
	{
		ss << "Type: " << MSG_COLOR_CYAN << GetMapTypeString(instance->m_mapInfo->type) << "|r";
		if(instance->m_mapInfo->type == INSTANCE_MULTIMODE)
		{
			ss << " (" << MSG_COLOR_CYAN << GetDifficultyString(instance->m_difficulty) << "|r)";
		}
		ss << "\n";
	}
	ss << "Created: " << MSG_COLOR_CYAN << ConvertTimeStampToDataTime((uint32)instance->m_creation) << "|r\n";
	ss << "Expires: " << MSG_COLOR_CYAN << ConvertTimeStampToDataTime((uint32)instance->m_expiration) << "|r\n";

	if(instance->m_mapMgr == NULL)
	{
		ss << "Status: " << MSG_COLOR_LIGHTRED << "Shut Down|r\n";
	}
	else if(!instance->m_mapMgr->HasPlayers())
	{
		ss << "Status: " << MSG_COLOR_LIGHTRED << "Idle|r";
		if(instance->m_mapMgr->InactiveMoveTime && instance->m_mapMgr->GetMapInfo()->type != INSTANCE_NULL)
			ss << " (" << MSG_COLOR_CYAN << "Shutdown in " << MSG_COLOR_LIGHTRED << ( (instance->m_mapMgr->InactiveMoveTime - UNIXTIME) / 60 ) << MSG_COLOR_CYAN << " minutes|r)";
		ss << "\n";
	}
	else
	{
		ss << "Status: " << MSG_COLOR_GREEN << "In use|r (" << MSG_COLOR_GREEN << instance->m_mapMgr->GetPlayerCount() << MSG_COLOR_CYAN << " players inside|r)\n";
		//ss << "Playerlist:\n";
		//int cnt = 0;
		////TODO: Implement lock...
		//for(PlayerStorageMap::iterator itr = instance->m_mapMgr->m_PlayerStorage.begin(); itr != instance->m_mapMgr->m_PlayerStorage.end(); ++itr)
		//{
		//	if(cnt > 0)
		//		ss << ", ";
		//	if((*itr).second->GetSession()->GetPermissionCount() > 0)
		//		ss << MSG_COLOR_LIGHTRED << (*itr).second->GetName() << "|r";
		//	else
		//		ss << MSG_COLOR_CYAN << (*itr).second->GetName() << "|r";

		//	cnt++;
		//	if(cnt >= 5)
		//	{
		//		cnt = 0;
		//		ss << "\n";
		//	}
		//}
	}
	SendMultilineMessage(m_session, ss.str().c_str());
	return true;
}

bool ChatHandler::HandleExitInstanceCommand(const char* args, WorldSession* m_session)
{
	BlueSystemMessage(m_session, "Attempting to exit from instance...");
	bool result = m_session->GetPlayer()->ExitInstance();
	if(!result)
	{
		RedSystemMessage(m_session, "Entry points not found.");
		return true;
	} else {
		GreenSystemMessage(m_session, "Removal successful.");
		return true;
	}
}

bool ChatHandler::HandleShowInstancesCommand(const char* args, WorldSession* m_session)
{
	Player * plr = getSelectedChar(m_session, true);
	if(!plr)
		return true;

	uint32 count = 0;
	std::stringstream ss;
	ss << "Show persistent instances of " << MSG_COLOR_CYAN << plr->GetName() << "|r\n";
	plr->m_playerInfo->savedInstanceIdsLock.Acquire();
	for(int difficulty=0; difficulty<NUM_INSTANCE_MODES; difficulty++)
	{
		for(PlayerInstanceMap::iterator itr = plr->m_playerInfo->savedInstanceIds[difficulty].begin(); itr != plr->m_playerInfo->savedInstanceIds[difficulty].end(); ++itr)
		{
			count++;
			ss << " - " << MSG_COLOR_CYAN << (*itr).second << "|r";
			MapInfo *mapInfo = WorldMapInfoStorage.LookupEntry((*itr).first);
			if(mapInfo != NULL)
				ss << " (" << MSG_COLOR_CYAN << mapInfo->name << "|r)";
			Instance *pInstance = sInstanceMgr.GetInstanceByIds((*itr).first, (*itr).second);
			if(pInstance == NULL)
				ss << " - " << MSG_COLOR_RED << "Expired!|r";
			else
			{
				ss << " [" << GetMapTypeString(pInstance->m_mapInfo->type) << "]";
				if(pInstance->m_mapInfo->type == INSTANCE_MULTIMODE)
				{
					ss << " [" << GetDifficultyString(pInstance->m_difficulty) << "]";
				}
				ss << " - ";
				if(pInstance->m_mapMgr == NULL)
					ss << MSG_COLOR_LIGHTRED << "Shut Down|r";
				else
				{
					if(!pInstance->m_mapMgr->HasPlayers())
						ss << MSG_COLOR_LIGHTRED << "Idle|r";
					else
						ss << MSG_COLOR_GREEN << "In use|r";
				}
			}
			ss << "\n";
		}
	}
	plr->m_playerInfo->savedInstanceIdsLock.Release();

	if(count == 0)
		ss << "Player is not assigned to any persistent instances.\n";
	else
		ss << "Player is assigned to " << MSG_COLOR_CYAN << count << "|r persistent instances.\n";

	SendMultilineMessage(m_session, ss.str().c_str());
	sGMLog.writefromsession(m_session, "used show instances command on %s,", plr->GetName());
	return true;
}
<commit_msg>it's 13 of the month and i hate warnings.<commit_after>/*
* ArcEmu MMORPG Server
 * Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
* Copyright (C) 2008 <http://www.ArcEmu.org/>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
*/

#include "StdAfx.h"

const char * GetDifficultyString(uint8 difficulty)
{
	switch(difficulty)
	{
	case MODE_NORMAL:
		return "normal";
	case MODE_HEROIC:
		return "heroic";
	case MODE_EPIC:
		return "epic";
	default:
		return "unknown";
	}
}

const char * GetMapTypeString(uint8 type)
{
	switch(type)
	{
	case INSTANCE_NULL:
		return "Continent";
	case INSTANCE_RAID:
		return "Raid";
	case INSTANCE_NONRAID:
		return "Non-Raid";
	case INSTANCE_PVP:
		return "PvP";
	case INSTANCE_MULTIMODE:
		return "MultiMode";
	default:
		return "Unknown";
	}
}

bool ChatHandler::HandleResetAllInstancesCommand(const char* args, WorldSession *m_session)
{
	Player * plr = getSelectedChar(m_session, true);
	if(!plr)
		return true;

	SystemMessage(m_session, "Trying to reset all instances of player %s...", plr->GetName());
	sInstanceMgr.ResetSavedInstances(plr);
	SystemMessage(m_session, "...done");

	sGMLog.writefromsession(m_session, "used reset all instances command on %s,", plr->GetName());
	return true;
}

bool ChatHandler::HandleResetInstanceCommand(const char* args, WorldSession *m_session)
{
	uint32 instanceId = (args ? atoi(args) : 0);
	if(instanceId == 0)
		return false;

	Player * plr = getSelectedChar(m_session, true);
	if(!plr)
		return true;

	Instance *instance = sInstanceMgr.GetInstanceByIds(NUM_MAPS, instanceId);
	if(instance == NULL)
	{
		RedSystemMessage(m_session, "There's no instance with id %u.", instanceId);
		return true;
	}

	if(IS_PERSISTENT_INSTANCE(instance))
	{
		if(m_session->CanUseCommand('z'))
		{
			bool foundSomething = false;
			plr->m_playerInfo->savedInstanceIdsLock.Acquire();
			for(int difficulty=0; difficulty<NUM_INSTANCE_MODES; difficulty++)
			{
				PlayerInstanceMap::iterator itr = plr->m_playerInfo->savedInstanceIds[difficulty].find(instance->m_mapId);
				if(itr == plr->m_playerInfo->savedInstanceIds[difficulty].end() || (*itr).second != instance->m_instanceId)
					continue;
				plr->SetPersistentInstanceId(instance->m_mapId, difficulty, 0);
				SystemMessage(m_session, "Instance with id %u (%s) is persistent and will only be revoked from player.", instanceId, GetDifficultyString(difficulty));
				foundSomething = true;
			}
			plr->m_playerInfo->savedInstanceIdsLock.Release();
			if(!foundSomething)
				RedSystemMessage(m_session, "Player is not assigned to persistent instance with id %u.", instanceId);
			return true;
		}
		else
		{
			RedSystemMessage(m_session, "Instance with id %u is persistent and can only be removed from player by admins.", instanceId);
			return true;
		}
	}

	if(instance->m_mapMgr && instance->m_mapMgr->HasPlayers())
	{
		RedSystemMessage(m_session, "Failed to reset non-persistent instance with id %u, due to player still inside.", instanceId);
		return true;
	}

	if(instance->m_creatorGroup)
	{
		Group *group = plr->GetGroup();
		if(group == NULL || instance->m_creatorGroup != group->GetID())
		{
			RedSystemMessage(m_session, "Player %s is not a member of the group assigned to the non-persistent instance with id %u.", plr->GetName(), instanceId);
			return true;
		}
	}
	else if(instance->m_creatorGuid == 0 || instance->m_creatorGuid != plr->GetLowGUID())
	{
		RedSystemMessage(m_session, "Player %s is not assigned to instance with id %u.", plr->GetName(), instanceId);
		return true;
	}

	//TODO: Reset that instance...^^
	RedSystemMessage(m_session, "Resetting single non-persistent instances is not available yet.");
	sGMLog.writefromsession(m_session, "used reset instance command on %s, instance %u,", plr->GetName(), instanceId);
	return true;
}

bool ChatHandler::HandleShutdownInstanceCommand(const char* args, WorldSession *m_session)
{
	//RedSystemMessage(m_session, "Command not implemented yet.");
	//return true;

	uint32 instanceId = (args ? atoi(args) : 0);
	if(instanceId == 0)
		return false;

	Instance *instance = sInstanceMgr.GetInstanceByIds(NUM_MAPS, instanceId);
	if(instance == NULL)
	{
		RedSystemMessage(m_session, "There's no instance with id %u.", instanceId);
		return true;
	}

	if(instance->m_mapMgr == NULL)
	{
		RedSystemMessage(m_session, "Instance with id %u already shut down.", instanceId);
		return true;
	}

	SystemMessage(m_session, "Attempting to shutdown instance with id %u...", instanceId);

	//Isn't there a better way?
	instance->m_mapMgr->InstanceShutdown();
	instance->m_mapMgr = NULL;
	delete instance->m_mapMgr;

	SystemMessage(m_session, "...done");

	sGMLog.writefromsession(m_session, "used shutdown instance command on instance %u,", instanceId);
	return true;
}

//bool ChatHandler::HandleDeleteInstanceCommand(const char* args, WorldSession *m_session)
//{
//	RedSystemMessage(m_session, "Command not implemented yet.");
//	return true;
//	//sGMLog.writefromsession(m_session, "used delete instance command on instance %u,", 0);
//}

bool ChatHandler::HandleGetInstanceInfoCommand(const char* args, WorldSession *m_session)
{
	Player *plr = m_session->GetPlayer();
	if(plr == NULL)
		return false;

	bool userInput = true;
	uint32 instanceId = (args ? atoi(args) : 0);
	if(instanceId == 0)
	{
		userInput = false;
		instanceId = plr->GetInstanceID();
		if(instanceId == 0)
			return false;
	}

	Instance *instance = sInstanceMgr.GetInstanceByIds(NUM_MAPS, instanceId);
	if(instance == NULL)
	{
		if(userInput)
		{
			RedSystemMessage(m_session, "Instance with id %u not found.", instanceId);
			return true;
		}
		return false;
	}

	std::stringstream ss;
	ss << "Instance ID: " << MSG_COLOR_CYAN << instance->m_instanceId << "|r (" << MSG_COLOR_CYAN;
	if(instance->m_mapInfo == NULL)
		ss << instance->m_mapId;
	else
		ss << instance->m_mapInfo->name;
	ss << "|r)\n";
	ss << "Persistent: " << MSG_COLOR_CYAN << (instance->m_persistent ? "Yes" : "No") << "|r\n";
	if(instance->m_mapInfo != NULL)
	{
		ss << "Type: " << MSG_COLOR_CYAN << GetMapTypeString(instance->m_mapInfo->type) << "|r";
		if(instance->m_mapInfo->type == INSTANCE_MULTIMODE)
		{
			ss << " (" << MSG_COLOR_CYAN << GetDifficultyString(instance->m_difficulty) << "|r)";
		}
		ss << "\n";
	}
	ss << "Created: " << MSG_COLOR_CYAN << ConvertTimeStampToDataTime((uint32)instance->m_creation) << "|r\n";
	ss << "Expires: " << MSG_COLOR_CYAN << ConvertTimeStampToDataTime((uint32)instance->m_expiration) << "|r\n";

	if(instance->m_mapMgr == NULL)
	{
		ss << "Status: " << MSG_COLOR_LIGHTRED << "Shut Down|r\n";
	}
	else if(!instance->m_mapMgr->HasPlayers())
	{
		ss << "Status: " << MSG_COLOR_LIGHTRED << "Idle|r";
		if(instance->m_mapMgr->InactiveMoveTime && instance->m_mapMgr->GetMapInfo()->type != INSTANCE_NULL)
			ss << " (" << MSG_COLOR_CYAN << "Shutdown in " << MSG_COLOR_LIGHTRED << ( ((long)instance->m_mapMgr->InactiveMoveTime - UNIXTIME) / 60 ) << MSG_COLOR_CYAN << " minutes|r)";
		ss << "\n";
	}
	else
	{
		ss << "Status: " << MSG_COLOR_GREEN << "In use|r (" << MSG_COLOR_GREEN << (uint32)instance->m_mapMgr->GetPlayerCount() << MSG_COLOR_CYAN << " players inside|r)\n";
		//ss << "Playerlist:\n";
		//int cnt = 0;
		////TODO: Implement lock...
		//for(PlayerStorageMap::iterator itr = instance->m_mapMgr->m_PlayerStorage.begin(); itr != instance->m_mapMgr->m_PlayerStorage.end(); ++itr)
		//{
		//	if(cnt > 0)
		//		ss << ", ";
		//	if((*itr).second->GetSession()->GetPermissionCount() > 0)
		//		ss << MSG_COLOR_LIGHTRED << (*itr).second->GetName() << "|r";
		//	else
		//		ss << MSG_COLOR_CYAN << (*itr).second->GetName() << "|r";

		//	cnt++;
		//	if(cnt >= 5)
		//	{
		//		cnt = 0;
		//		ss << "\n";
		//	}
		//}
	}
	SendMultilineMessage(m_session, ss.str().c_str());
	return true;
}

bool ChatHandler::HandleExitInstanceCommand(const char* args, WorldSession* m_session)
{
	BlueSystemMessage(m_session, "Attempting to exit from instance...");
	bool result = m_session->GetPlayer()->ExitInstance();
	if(!result)
	{
		RedSystemMessage(m_session, "Entry points not found.");
		return true;
	} else {
		GreenSystemMessage(m_session, "Removal successful.");
		return true;
	}
}

bool ChatHandler::HandleShowInstancesCommand(const char* args, WorldSession* m_session)
{
	Player * plr = getSelectedChar(m_session, true);
	if(!plr)
		return true;

	uint32 count = 0;
	std::stringstream ss;
	ss << "Show persistent instances of " << MSG_COLOR_CYAN << plr->GetName() << "|r\n";
	plr->m_playerInfo->savedInstanceIdsLock.Acquire();
	for(int difficulty=0; difficulty<NUM_INSTANCE_MODES; difficulty++)
	{
		for(PlayerInstanceMap::iterator itr = plr->m_playerInfo->savedInstanceIds[difficulty].begin(); itr != plr->m_playerInfo->savedInstanceIds[difficulty].end(); ++itr)
		{
			count++;
			ss << " - " << MSG_COLOR_CYAN << (*itr).second << "|r";
			MapInfo *mapInfo = WorldMapInfoStorage.LookupEntry((*itr).first);
			if(mapInfo != NULL)
				ss << " (" << MSG_COLOR_CYAN << mapInfo->name << "|r)";
			Instance *pInstance = sInstanceMgr.GetInstanceByIds((*itr).first, (*itr).second);
			if(pInstance == NULL)
				ss << " - " << MSG_COLOR_RED << "Expired!|r";
			else
			{
				ss << " [" << GetMapTypeString(pInstance->m_mapInfo->type) << "]";
				if(pInstance->m_mapInfo->type == INSTANCE_MULTIMODE)
				{
					ss << " [" << GetDifficultyString(pInstance->m_difficulty) << "]";
				}
				ss << " - ";
				if(pInstance->m_mapMgr == NULL)
					ss << MSG_COLOR_LIGHTRED << "Shut Down|r";
				else
				{
					if(!pInstance->m_mapMgr->HasPlayers())
						ss << MSG_COLOR_LIGHTRED << "Idle|r";
					else
						ss << MSG_COLOR_GREEN << "In use|r";
				}
			}
			ss << "\n";
		}
	}
	plr->m_playerInfo->savedInstanceIdsLock.Release();

	if(count == 0)
		ss << "Player is not assigned to any persistent instances.\n";
	else
		ss << "Player is assigned to " << MSG_COLOR_CYAN << count << "|r persistent instances.\n";

	SendMultilineMessage(m_session, ss.str().c_str());
	sGMLog.writefromsession(m_session, "used show instances command on %s,", plr->GetName());
	return true;
}
<|endoftext|>


<commit_before>//
// Created by Danni on 09.06.15.
//

#include "TweeCompiler.h"
#include "ZAssemblyGenerator.h"
#include <sstream>
#include <iostream>
#include <Passage/Body/Link.h>

using namespace std;

static const string PASSAGE_GLOB = "PASSAGE_PTR",
        JUMP_TABLE_LABEL = "JUMP_TABLE_START",
        JUMP_TABLE_END_LABEL = "JUMP_TABLE_END",
        MAIN_ROUTINE = "main",
        USER_INPUT = "USER_INPUT";

static const unsigned int ZSCII_NUM_OFFSET = 49;

//#define ZAS_DEBUG

string routineNameForPassageName(std::string passageName) {
    stringstream ss;
    ss << "R_" << passageName;
    return ss.str();
}

string routineNameForPassage(Passage& passage) {
    return routineNameForPassageName(passage.getHead().getName());
}

string labelForPassage(Passage& passage) {
    stringstream ss;
    ss << "L_" << passage.getHead().getName();
    return ss.str();
}

void TweeCompiler::compile(TweeFile &tweeFile, std::ostream &out) {
    ZAssemblyGenerator assgen(out);
    vector<Passage> passages = tweeFile.getPassages();

    {
        int i = 0;
        for (auto passage = passages.begin(); passage != passages.end(); ++passage) {
            passageName2id[passage->getHead().getName()] = i;
            i++;
        }
    }

    // main routine
    {
        // globals
        assgen.addGlobal(PASSAGE_GLOB)
                .addGlobal(USER_INPUT);

        // call start routine first
        assgen.addRoutine(MAIN_ROUTINE)
                .markStart()
                .call(routineNameForPassageName("start"), PASSAGE_GLOB)
                .addLabel(JUMP_TABLE_LABEL);

        for(auto passage = passages.begin(); passage != passages.end(); ++passage) {
            int passageId = passageName2id.at(passage->getHead().getName());

            assgen.jumpEquals(ZAssemblyGenerator::makeArgs({std::to_string(passageId), PASSAGE_GLOB}), labelForPassage(*passage));
        }

        for(auto passage = passages.begin(); passage != passages.end(); ++passage) {
            assgen.addLabel(labelForPassage(*passage))
                    .call(routineNameForPassage(*passage), PASSAGE_GLOB)
                    .jump(JUMP_TABLE_LABEL);
        }

        assgen.addLabel(JUMP_TABLE_END_LABEL);

        assgen.quit();
    }

    // passage routines
    {
        for(auto passage = passages.begin(); passage != passages.end(); ++passage) {
            // declare passage routine, print passage contents and read user input
            assgen.addRoutine(routineNameForPassage(*passage));

            assgen.println(passage->getHead().getName())
                    .read_char(USER_INPUT);

            vector<Link*> links;
            auto bodyParts = passage->getBody().getBodyParts();
            // get links from passage
            for(vector<BodyPart*>::iterator bodyPart = bodyParts.begin(); bodyPart != bodyParts.end();
                ++bodyPart)
            {
                if(Link* link = dynamic_cast<Link*>(*bodyPart)) {
                    links.push_back(link);
                }
            }

            // jump to according link selection
            int i = 0;
            for (auto link = links.begin(); link != links.end(); link++) {
                string label = string("L") + to_string(i);
                assgen.jumpEquals(ZAssemblyGenerator::makeArgs({USER_INPUT, to_string(ZSCII_NUM_OFFSET + i)}), label);

                i++;
            }

            // no proper selection was made
            assgen.ret("-1");

            i = 0;
            for (auto link = links.begin(); link != links.end(); link++) {
                string label = string("L") + to_string(i);
                try {
                    int targetPassageId = passageName2id.at((*link)->getTarget());
                    assgen.addLabel(label);
                    #ifdef ZAS_DEBUG
                    assgen.print(string("selected ") + to_string(targetPassageId) );
                    #endif
                    assgen.ret(to_string(targetPassageId));
                } catch (out_of_range &err) {
                    cerr << "could not find passage for link \"" << *link << "\"" << endl;
                    throw;
                }
                i++;
            }
        }
    }
}
<commit_msg>better compiling<commit_after>//
// Created by Danni on 09.06.15.
//

#include "TweeCompiler.h"
#include "ZAssemblyGenerator.h"
#include <sstream>
#include <iostream>
#include <Passage/Body/Link.h>
#include <Passage/Body/Text.h>

using namespace std;

static const string PASSAGE_GLOB = "PASSAGE_PTR",
        JUMP_TABLE_LABEL = "JUMP_TABLE_START",
        JUMP_TABLE_END_LABEL = "JUMP_TABLE_END",
        MAIN_ROUTINE = "main",
        USER_INPUT = "USER_INPUT",
        READ_BEGIN = "READ_BEGIN";

static const unsigned int ZSCII_NUM_OFFSET = 49;

//#define ZAS_DEBUG

string routineNameForPassageName(std::string passageName) {
    stringstream ss;
    ss << "R_" << passageName;
    return ss.str();
}

string routineNameForPassage(Passage& passage) {
    return routineNameForPassageName(passage.getHead().getName());
}

string labelForPassage(Passage& passage) {
    stringstream ss;
    ss << "L_" << passage.getHead().getName();
    return ss.str();
}

void TweeCompiler::compile(TweeFile &tweeFile, std::ostream &out) {
    ZAssemblyGenerator assgen(out);
    vector<Passage> passages = tweeFile.getPassages();

    {
        int i = 0;
        for (auto passage = passages.begin(); passage != passages.end(); ++passage) {
            passageName2id[passage->getHead().getName()] = i;
            i++;
        }
    }

    // main routine
    {
        // globals
        assgen.addGlobal(PASSAGE_GLOB)
                .addGlobal(USER_INPUT);

        // call start routine first
        assgen.addRoutine(MAIN_ROUTINE)
                .markStart()
                .call(routineNameForPassageName("start"), PASSAGE_GLOB)
                .addLabel(JUMP_TABLE_LABEL);

        for(auto passage = passages.begin(); passage != passages.end(); ++passage) {
            int passageId = passageName2id.at(passage->getHead().getName());

            assgen.jumpEquals(ZAssemblyGenerator::makeArgs({std::to_string(passageId), PASSAGE_GLOB}), labelForPassage(*passage));
        }

        for(auto passage = passages.begin(); passage != passages.end(); ++passage) {
            assgen.addLabel(labelForPassage(*passage))
                    .call(routineNameForPassage(*passage), PASSAGE_GLOB)
                    .jump(JUMP_TABLE_LABEL);
        }

        assgen.addLabel(JUMP_TABLE_END_LABEL);

        assgen.quit();
    }

    // passage routines
    {
        for(auto passage = passages.begin(); passage != passages.end(); ++passage) {
            auto bodyParts = passage->getBody().getBodyParts();

            // declare passage routine
            assgen.addRoutine(routineNameForPassage(*passage));

            assgen.println(string("***** ") + passage->getHead().getName() + string(" *****"));

            //  print passage contents
            for(auto bodyPart = bodyParts.begin(); bodyPart != bodyParts.end(); bodyPart++) {
                if(Text* text = dynamic_cast<Text*>(*bodyPart)) {
                    assgen.print(text->getContent());
                }
            }

            assgen.newline();

            vector<Link*> links;
            // get links from passage
            for(auto bodyPart = bodyParts.begin(); bodyPart != bodyParts.end();
                ++bodyPart)
            {
                if(Link* link = dynamic_cast<Link*>(*bodyPart)) {
                    links.push_back(link);
                }
            }

            // present choices to user
            assgen.println("Select one of the following options:");
            int i = 1;
            for (auto link = links.begin(); link != links.end(); link++) {
                assgen.println(string("    ") + to_string(i) + string(") ") + (*link)->getTarget() );
                i++;
            }

            assgen.addLabel(READ_BEGIN);

            // read user input
            assgen.read_char(USER_INPUT);

            // jump to according link selection
            i = 0;
            for (auto link = links.begin(); link != links.end(); link++) {
                string label = string("L") + to_string(i);
                assgen.jumpEquals(ZAssemblyGenerator::makeArgs({USER_INPUT, to_string(ZSCII_NUM_OFFSET + i)}), label);

                i++;
            }

            // no proper selection was made
            assgen.jump(READ_BEGIN);

            i = 0;
            for (auto link = links.begin(); link != links.end(); link++) {
                string label = string("L") + to_string(i);
                try {
                    int targetPassageId = passageName2id.at((*link)->getTarget());
                    assgen.addLabel(label);
                    #ifdef ZAS_DEBUG
                    assgen.print(string("selected ") + to_string(targetPassageId) );
                    #endif
                    assgen.ret(to_string(targetPassageId));
                } catch (out_of_range &err) {
                    cerr << "could not find passage for link \"" << *link << "\"" << endl;
                    throw;
                }
                i++;
            }
        }
    }
}
<|endoftext|>


<commit_before>//
// Created by Danni on 09.06.15.
//

#include "TweeCompiler.h"
#include "ZAssemblyGenerator.h"
#include "exceptions.h"
#include "Utils.h"

#include <plog/Log.h>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <set>

#include <Passage/Body/Link.h>
#include <Passage/Body/Text.h>
#include <Passage/Body/Newline.h>

#include <Passage/Body/Expressions/BinaryOperation.h>
#include <Passage/Body/Expressions/UnaryOperation.h>
#include <Passage/Body/Expressions/Const.h>
#include <Passage/Body/Expressions/Variable.h>

#include <Passage/Body/Macros/Print.h>
#include <Passage/Body/Macros/SetMacro.h>

using namespace std;
using namespace std::experimental;

static const string GLOB_PASSAGE = "PASSAGE_PTR",
        GLOB_PASSAGES_COUNT = "PASSAGES_COUNT",
        LABEL_MAIN_LOOP = "MAIN_LOOP",
        ROUTINE_MAIN = "main",
        GLOBAL_USER_INPUT = "USER_INPUT",
        TABLE_LINKED_PASSAGES = "LINKED_PASSAGES",
        TABLE_USERINPUT_LOOKUP = "USERINPUT_LOOKUP",
        ROUTINE_PASSAGE_BY_ID = "passage_by_id",
        ROUTINE_NAME_FOR_PASSAGE = "print_name_for_passage",
        ROUTINE_DISPLAY_LINKS = "display_links",
        ROUTINE_CLEAR_TABLES = "reset_tables";

static const unsigned int ZSCII_NUM_OFFSET = 49;

//#define ZAS_DEBUG

#ifndef ASSGEN
#define ASSGEN (*_assgen)
#endif

void maskString(std::string &string) {
    std::replace(string.begin(), string.end(), ' ', '_');
}

string routineNameForPassageName(std::string passageName) {
    stringstream ss;
    maskString(passageName);
    ss << "R_" << passageName;
    return ss.str();
}

string routineNameForPassage(Passage &passage) {
    return routineNameForPassageName(passage.getHead().getName());
}

string labelForPassage(Passage &passage) {
    stringstream ss;
    string passageName = passage.getHead().getName();
    maskString(passageName);
    ss << "L_" << passageName;
    return ss.str();
}

string makeUserInputRoutine() {
    return ".FUNCT display_links i, selectcount\n"
            "loop_start:\n"
            "loadb PASSAGES i -> sp\n"
            "jz sp ?passage_not_set\n"
            "storeb USERINPUT_LOOKUP selectcount i\n"
            "add selectcount 1 -> sp\n"
            "add selectcount 49 -> sp\n"
            "print_char sp\n"
            "print \": \"\n"
            "call_vs print_name_for_passage_id i -> sp\n"
            "new_line\n"
            "add selectcount 1 -> selectcount\n"
            "\n"
            "passage_not_set:\n"
            "\n"
            "add i 1 -> i\n"
            "jl i PASSAGES_COUNT ?loop_start\n"
            "\n"
            "read_char 1 -> USER_INPUT\n"
            "sub USER_INPUT 48 -> sp\n"
            "sub sp 1 -> sp\n"
            "loadb USERINPUT_LOOKUP sp -> sp \n"
            "\n"
            "ret sp"
            "\n";
}

string makeClearTablesRoutine() {
    return ".FUNCT reset_tables i\n"
            "loop_start:\n"
            "storeb PASSAGES i 0\n"
            "storeb USERINPUT_LOOKUP i 0\n"
            "add i 1 -> i\n"
            "jl i PASSAGES_COUNT ?loop_start\n"
            "ret 0"
            "\n";
}

void TweeCompiler::compile(TweeFile &tweeFile, std::ostream &out) {
    _assgen = unique_ptr<ZAssemblyGenerator>(new ZAssemblyGenerator(out));

    vector<Passage> passages = tweeFile.getPassages();

    globalVariables = std::set<std::string>();

    labelCount = 0;

    {
        int i = 0;
        for (auto passage = passages.begin(); passage != passages.end(); ++passage) {
            passageName2id[passage->getHead().getName()] = i;
            i++;
        }
    }

    // tables needed for routine linking
    ASSGEN.addByteArray(TABLE_LINKED_PASSAGES, (unsigned)passages.size());
    ASSGEN.addByteArray(TABLE_USERINPUT_LOOKUP, (unsigned)passages.size());

    // globals
    ASSGEN.addGlobal(GLOB_PASSAGE)
            .addGlobal(GLOBAL_USER_INPUT)
            .addGlobal(GLOB_PASSAGES_COUNT);

    out << makeUserInputRoutine() << makeClearTablesRoutine();

    // call passage by id routine
    {
        const string idLocal = "id";
        ASSGEN.addRoutine(ROUTINE_PASSAGE_BY_ID, vector<ZRoutineArgument>({ZRoutineArgument(idLocal)}));
        for(auto it = passages.begin(); it != passages.end(); ++it) {
            string passageName = it->getHead().getName();
            unsigned id = passageName2id.at(passageName);
            ASSGEN.jumpEquals(ASSGEN.makeArgs({idLocal, to_string(id)}), labelForPassage(*it));
        }

        // error case
        ASSGEN.print("invalid id for passage "); // TODO: print offending argument as soon as print_num is available
        ASSGEN.quit();

        for(auto it = passages.begin(); it != passages.end(); ++it) {
            ASSGEN.addLabel(labelForPassage(*it)).call_vs(routineNameForPassage(*it), nullopt, "sp").ret("0");
        }
    }

    // print passage name by id routine
    {
        const string idLocal = "id";
        ASSGEN.addRoutine(ROUTINE_NAME_FOR_PASSAGE, vector<ZRoutineArgument>({ZRoutineArgument(idLocal)}));
        for(auto it = passages.begin(); it != passages.end(); ++it) {
            string passageName = it->getHead().getName();
            unsigned id = passageName2id.at(passageName);
            ASSGEN.jumpEquals(ASSGEN.makeArgs({idLocal, to_string(id)}), labelForPassage(*it));
        }

        // error case
        ASSGEN.print("invalid id for passage "); // TODO: print offending argument as soon as print_num is available
        ASSGEN.quit();

        for(auto it = passages.begin(); it != passages.end(); ++it) {
            ASSGEN.addLabel(labelForPassage(*it)).print(it->getHead().getName()).ret("0");
        }
    }

    // main routine
    {
        // initialize globals
        ASSGEN.store(GLOB_PASSAGES_COUNT, to_string(passages.size()));

        // call start routine first
        ASSGEN.addRoutine(ROUTINE_MAIN)
                .markStart()
                .call_vs(ROUTINE_PASSAGE_BY_ID, to_string(passageName2id.at(string("Start"))), "sp");

        ASSGEN.addLabel(LABEL_MAIN_LOOP)
                .call_vs(ROUTINE_DISPLAY_LINKS, string("sp"), "sp")
                .call_vs(ROUTINE_CLEAR_TABLES, nullopt, "sp")
                .call_vs(ROUTINE_PASSAGE_BY_ID, string("sp"), "sp")
                .jump(LABEL_MAIN_LOOP);

        ASSGEN.quit();
    }

    // passage routines
    {
        for (auto passage = passages.begin(); passage != passages.end(); ++passage) {
            const vector<unique_ptr<BodyPart>> &bodyParts = passage->getBody().getBodyParts();

            // declare passage routine
            ASSGEN.addRoutine(routineNameForPassage(*passage));

            ASSGEN.println(string("***** ") + passage->getHead().getName() + string(" *****"));

            //  print passage contents
            for(auto it = bodyParts.begin(); it != bodyParts.end(); it++) {
                BodyPart* bodyPart = it->get();
                if(Text* text = dynamic_cast<Text*>(bodyPart)) {
                    ASSGEN.print(text->getContent());
                } else if (Variable* variable = dynamic_cast<Variable*>(bodyPart)) {
                    ASSGEN.variable(variable->getName());
                } else if (Link* link = dynamic_cast<Link*>(bodyPart)) {
                    // TODO: catch invalid link
                    ASSGEN.storeb(TABLE_LINKED_PASSAGES, passageName2id.at(link->getTarget()), 1);
                } else if (Newline* text = dynamic_cast<Newline*>(bodyPart)) {
                    ASSGEN.newline();
                } else if (Print *print = dynamic_cast<Print *>(bodyPart)) {
                    evalExpression(print->getExpression().get());
                    ASSGEN.print_num("sp");
                } else if (SetMacro *op = dynamic_cast<SetMacro *>(bodyPart)) {
                    LOG_DEBUG << "generate SetMacro assembly code";

                    if (BinaryOperation *binaryOperation = (BinaryOperation *) (op->getExpression().get())) {
                        if (Variable *variable = (Variable *) (binaryOperation->getLeftSide().get())) {
                            std::string variableName = variable->getName();
                            variableName = variableName.erase(0, 1); //remove the $ symbol

                            // TODO: merge this with evalExpression
                            if (Utils::contains<std::string>(globalVariables, variableName)) {
                                ASSGEN.push(variableName);
                            } else {
                                globalVariables.insert(variableName);
                                ASSGEN.addGlobal(variableName);
                                ASSGEN.push(variableName);
                            }

                            evalExpression(binaryOperation->getRightSide().get());

                            ASSGEN.load("sp", variableName);
                        }
                    }
                }
            }

            ASSGEN.ret("0");
        }
    }
}

void TweeCompiler::evalExpression(Expression *expression) {

    if (Const<int> *constant = dynamic_cast<Const<int> *>(expression)) {

        ASSGEN.push(std::to_string(constant->getValue()));

    } else if (Variable *variable = dynamic_cast<Variable *>(expression)) {

        std::string prunedVarName = variable->getName().substr(1);

        if (Utils::contains<std::string>(globalVariables, prunedVarName)) {
            ASSGEN.push(prunedVarName);
        } else {
            globalVariables.insert(prunedVarName);
            ASSGEN.addGlobal(prunedVarName);
            ASSGEN.push(prunedVarName);
        }

    } else if (BinaryOperation *binOp = dynamic_cast<BinaryOperation *>(expression)) {
        std::pair<std::string, std::string> labels;

        TweeCompiler::evalExpression(binOp->getLeftSide().get());
        TweeCompiler::evalExpression(binOp->getRightSide().get());

        switch (binOp->getOperator()) {
            case BinOps::ADD:
                ASSGEN.add("sp", "sp", "sp");
                break;
            case BinOps::SUB:
                ASSGEN.sub("sp", "sp", "sp");
                break;
            case BinOps::MUL:
                ASSGEN.mul("sp", "sp", "sp");
                break;
            case BinOps::DIV:
                ASSGEN.div("sp", "sp", "sp");
                break;
            case BinOps::MOD:
                ASSGEN.mod("sp", "sp", "sp");
                break;
            case BinOps::AND:
                ASSGEN.land("sp", "sp", "sp");
                break;
            case BinOps::OR:
                ASSGEN.lor("sp", "sp", "sp");
                break;
            case BinOps::TO:
                // TODO: check if this is right
                ASSGEN.load("sp", "sp");
                break;
            case BinOps::LT:
                labels = labelCreator("lower");
                ASSGEN.jumpLower(std::string("sp") + " " + std::string("sp"), labels.first);
                ASSGEN.push("0");
                ASSGEN.jump(labels.second);
                ASSGEN.addLabel(labels.first);
                ASSGEN.push("1");
                ASSGEN.addLabel(labels.second);
                break;
            case BinOps::LTE:
                labels = labelCreator("lowerEquals");
                ASSGEN.jumpLowerEquals(std::string("sp") + " " + std::string("sp"), labels.first);
                ASSGEN.push("0");
                ASSGEN.jump(labels.second);
                ASSGEN.addLabel(labels.first);
                ASSGEN.push("1");
                ASSGEN.addLabel(labels.second);
                break;
            case BinOps::GT:
                labels = labelCreator("greater");
                ASSGEN.jumpGreater(std::string("sp") + " " + std::string("sp"), labels.first);
                ASSGEN.push("0");
                ASSGEN.jump(labels.second);
                ASSGEN.addLabel(labels.first);
                ASSGEN.push("1");
                ASSGEN.addLabel(labels.second);
                break;
            case BinOps::GTE:
                labels = labelCreator("greaterEquals");
                ASSGEN.jumpGreaterEquals(std::string("sp") + " " + std::string("sp"), labels.first);
                ASSGEN.push("0");
                ASSGEN.jump(labels.second);
                ASSGEN.addLabel(labels.first);
                ASSGEN.push("1");
                ASSGEN.addLabel(labels.second);
                break;
            case BinOps::IS:
                ASSGEN.jumpEquals(std::string("sp") + " " + std::string("sp"), labels.first);
                ASSGEN.push("0");
                ASSGEN.jump(labels.second);
                ASSGEN.addLabel(labels.first);
                ASSGEN.push("1");
                ASSGEN.addLabel(labels.second);
                break;
            case BinOps::NEQ:
                ASSGEN.jumpNotEquals(std::string("sp") + " " + std::string("sp"), labels.first);
                ASSGEN.push("0");
                ASSGEN.jump(labels.second);
                ASSGEN.addLabel(labels.first);
                ASSGEN.push("1");
                ASSGEN.addLabel(labels.second);
                break;

        }
    } else if (UnaryOperation *unOp = dynamic_cast<UnaryOperation *>(expression)) {
        TweeCompiler::evalExpression(unOp->getExpression().get());
        switch (unOp->getOperator()) {
            case UnOps::NOT:
                ASSGEN.lnot("sp", "sp");
                break;
            case UnOps::PLUS:
                ASSGEN.push("0");
                ASSGEN.add("sp", "sp", "sp");
                break;
            case UnOps::MINUS:
                ASSGEN.push("0");
                ASSGEN.sub("sp", "sp", "sp");
                break;
            default:
                break;
        }
    }
}

std::pair<std::string, std::string> TweeCompiler::labelCreator(std::string labelName) {

    std::string resultLabel = labelName.append("_");
    std::string afterLabel = "after_";
    resultLabel.append(std::to_string(labelCount));
    afterLabel.append(std::to_string(labelCount));
    ++labelCount;

    return std::make_pair(resultLabel, afterLabel);

}<commit_msg>generate main routine first<commit_after>//
// Created by Danni on 09.06.15.
//

#include "TweeCompiler.h"
#include "ZAssemblyGenerator.h"
#include "exceptions.h"
#include "Utils.h"

#include <plog/Log.h>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <set>

#include <Passage/Body/Link.h>
#include <Passage/Body/Text.h>
#include <Passage/Body/Newline.h>

#include <Passage/Body/Expressions/BinaryOperation.h>
#include <Passage/Body/Expressions/UnaryOperation.h>
#include <Passage/Body/Expressions/Const.h>
#include <Passage/Body/Expressions/Variable.h>

#include <Passage/Body/Macros/Print.h>
#include <Passage/Body/Macros/SetMacro.h>

using namespace std;
using namespace std::experimental;

static const string GLOB_PASSAGE = "PASSAGE_PTR",
        GLOB_PASSAGES_COUNT = "PASSAGES_COUNT",
        LABEL_MAIN_LOOP = "MAIN_LOOP",
        ROUTINE_MAIN = "main",
        GLOBAL_USER_INPUT = "USER_INPUT",
        TABLE_LINKED_PASSAGES = "LINKED_PASSAGES",
        TABLE_USERINPUT_LOOKUP = "USERINPUT_LOOKUP",
        ROUTINE_PASSAGE_BY_ID = "passage_by_id",
        ROUTINE_NAME_FOR_PASSAGE = "print_name_for_passage",
        ROUTINE_DISPLAY_LINKS = "display_links",
        ROUTINE_CLEAR_TABLES = "reset_tables";

static const unsigned int ZSCII_NUM_OFFSET = 49;

//#define ZAS_DEBUG

#ifndef ASSGEN
#define ASSGEN (*_assgen)
#endif

void maskString(std::string &string) {
    std::replace(string.begin(), string.end(), ' ', '_');
}

string routineNameForPassageName(std::string passageName) {
    stringstream ss;
    maskString(passageName);
    ss << "R_" << passageName;
    return ss.str();
}

string routineNameForPassage(Passage &passage) {
    return routineNameForPassageName(passage.getHead().getName());
}

string labelForPassage(Passage &passage) {
    stringstream ss;
    string passageName = passage.getHead().getName();
    maskString(passageName);
    ss << "L_" << passageName;
    return ss.str();
}

string makeUserInputRoutine() {
    return ".FUNCT display_links i, selectcount\n"
            "loop_start:\n"
            "loadb PASSAGES i -> sp\n"
            "jz sp ?passage_not_set\n"
            "storeb USERINPUT_LOOKUP selectcount i\n"
            "add selectcount 1 -> sp\n"
            "add selectcount 49 -> sp\n"
            "print_char sp\n"
            "print \": \"\n"
            "call_vs print_name_for_passage_id i -> sp\n"
            "new_line\n"
            "add selectcount 1 -> selectcount\n"
            "\n"
            "passage_not_set:\n"
            "\n"
            "add i 1 -> i\n"
            "jl i PASSAGES_COUNT ?loop_start\n"
            "\n"
            "read_char 1 -> USER_INPUT\n"
            "sub USER_INPUT 48 -> sp\n"
            "sub sp 1 -> sp\n"
            "loadb USERINPUT_LOOKUP sp -> sp \n"
            "\n"
            "ret sp"
            "\n";
}

string makeClearTablesRoutine() {
    return ".FUNCT reset_tables i\n"
            "loop_start:\n"
            "storeb PASSAGES i 0\n"
            "storeb USERINPUT_LOOKUP i 0\n"
            "add i 1 -> i\n"
            "jl i PASSAGES_COUNT ?loop_start\n"
            "ret 0"
            "\n";
}

void TweeCompiler::compile(TweeFile &tweeFile, std::ostream &out) {
    _assgen = unique_ptr<ZAssemblyGenerator>(new ZAssemblyGenerator(out));

    vector<Passage> passages = tweeFile.getPassages();

    globalVariables = std::set<std::string>();

    labelCount = 0;

    {
        int i = 0;
        for (auto passage = passages.begin(); passage != passages.end(); ++passage) {
            passageName2id[passage->getHead().getName()] = i;
            i++;
        }
    }

    // tables needed for routine linking
    ASSGEN.addByteArray(TABLE_LINKED_PASSAGES, (unsigned)passages.size());
    ASSGEN.addByteArray(TABLE_USERINPUT_LOOKUP, (unsigned)passages.size());

    // globals
    ASSGEN.addGlobal(GLOB_PASSAGE)
            .addGlobal(GLOBAL_USER_INPUT)
            .addGlobal(GLOB_PASSAGES_COUNT);

    // main routine
    {
        // call start routine first
        ASSGEN.addRoutine(ROUTINE_MAIN)
                .markStart()
                .call_vs(ROUTINE_PASSAGE_BY_ID, to_string(passageName2id.at(string("Start"))), "sp");

        // initialize globals
        ASSGEN.store(GLOB_PASSAGES_COUNT, to_string(passages.size()));

        ASSGEN.addLabel(LABEL_MAIN_LOOP)
                .call_vs(ROUTINE_DISPLAY_LINKS, string("sp"), "sp")
                .call_vs(ROUTINE_CLEAR_TABLES, nullopt, "sp")
                .call_vs(ROUTINE_PASSAGE_BY_ID, string("sp"), "sp")
                .jump(LABEL_MAIN_LOOP);

        ASSGEN.quit();
    }

    out << makeUserInputRoutine() << makeClearTablesRoutine();

    // call passage by id routine
    {
        const string idLocal = "id";
        ASSGEN.addRoutine(ROUTINE_PASSAGE_BY_ID, vector<ZRoutineArgument>({ZRoutineArgument(idLocal)}));
        for(auto it = passages.begin(); it != passages.end(); ++it) {
            string passageName = it->getHead().getName();
            unsigned id = passageName2id.at(passageName);
            ASSGEN.jumpEquals(ASSGEN.makeArgs({idLocal, to_string(id)}), labelForPassage(*it));
        }

        // error case
        ASSGEN.print("invalid id for passage "); // TODO: print offending argument as soon as print_num is available
        ASSGEN.quit();

        for(auto it = passages.begin(); it != passages.end(); ++it) {
            ASSGEN.addLabel(labelForPassage(*it)).call_vs(routineNameForPassage(*it), nullopt, "sp").ret("0");
        }
    }

    // print passage name by id routine
    {
        const string idLocal = "id";
        ASSGEN.addRoutine(ROUTINE_NAME_FOR_PASSAGE, vector<ZRoutineArgument>({ZRoutineArgument(idLocal)}));
        for(auto it = passages.begin(); it != passages.end(); ++it) {
            string passageName = it->getHead().getName();
            unsigned id = passageName2id.at(passageName);
            ASSGEN.jumpEquals(ASSGEN.makeArgs({idLocal, to_string(id)}), labelForPassage(*it));
        }

        // error case
        ASSGEN.print("invalid id for passage "); // TODO: print offending argument as soon as print_num is available
        ASSGEN.quit();

        for(auto it = passages.begin(); it != passages.end(); ++it) {
            ASSGEN.addLabel(labelForPassage(*it)).print(it->getHead().getName()).ret("0");
        }
    }

    // passage routines
    {
        for (auto passage = passages.begin(); passage != passages.end(); ++passage) {
            const vector<unique_ptr<BodyPart>> &bodyParts = passage->getBody().getBodyParts();

            // declare passage routine
            ASSGEN.addRoutine(routineNameForPassage(*passage));

            ASSGEN.println(string("***** ") + passage->getHead().getName() + string(" *****"));

            //  print passage contents
            for(auto it = bodyParts.begin(); it != bodyParts.end(); it++) {
                BodyPart* bodyPart = it->get();
                if(Text* text = dynamic_cast<Text*>(bodyPart)) {
                    ASSGEN.print(text->getContent());
                } else if (Variable* variable = dynamic_cast<Variable*>(bodyPart)) {
                    ASSGEN.variable(variable->getName());
                } else if (Link* link = dynamic_cast<Link*>(bodyPart)) {
                    // TODO: catch invalid link
                    ASSGEN.storeb(TABLE_LINKED_PASSAGES, passageName2id.at(link->getTarget()), 1);
                } else if (Newline* text = dynamic_cast<Newline*>(bodyPart)) {
                    ASSGEN.newline();
                } else if (Print *print = dynamic_cast<Print *>(bodyPart)) {
                    evalExpression(print->getExpression().get());
                    ASSGEN.print_num("sp");
                } else if (SetMacro *op = dynamic_cast<SetMacro *>(bodyPart)) {
                    LOG_DEBUG << "generate SetMacro assembly code";

                    if (BinaryOperation *binaryOperation = (BinaryOperation *) (op->getExpression().get())) {
                        if (Variable *variable = (Variable *) (binaryOperation->getLeftSide().get())) {
                            std::string variableName = variable->getName();
                            variableName = variableName.erase(0, 1); //remove the $ symbol

                            // TODO: merge this with evalExpression
                            if (Utils::contains<std::string>(globalVariables, variableName)) {
                                ASSGEN.push(variableName);
                            } else {
                                globalVariables.insert(variableName);
                                ASSGEN.addGlobal(variableName);
                                ASSGEN.push(variableName);
                            }

                            evalExpression(binaryOperation->getRightSide().get());

                            ASSGEN.load("sp", variableName);
                        }
                    }
                }
            }

            ASSGEN.ret("0");
        }
    }
}

void TweeCompiler::evalExpression(Expression *expression) {

    if (Const<int> *constant = dynamic_cast<Const<int> *>(expression)) {

        ASSGEN.push(std::to_string(constant->getValue()));

    } else if (Variable *variable = dynamic_cast<Variable *>(expression)) {

        std::string prunedVarName = variable->getName().substr(1);

        if (Utils::contains<std::string>(globalVariables, prunedVarName)) {
            ASSGEN.push(prunedVarName);
        } else {
            globalVariables.insert(prunedVarName);
            ASSGEN.addGlobal(prunedVarName);
            ASSGEN.push(prunedVarName);
        }

    } else if (BinaryOperation *binOp = dynamic_cast<BinaryOperation *>(expression)) {
        std::pair<std::string, std::string> labels;

        TweeCompiler::evalExpression(binOp->getLeftSide().get());
        TweeCompiler::evalExpression(binOp->getRightSide().get());

        switch (binOp->getOperator()) {
            case BinOps::ADD:
                ASSGEN.add("sp", "sp", "sp");
                break;
            case BinOps::SUB:
                ASSGEN.sub("sp", "sp", "sp");
                break;
            case BinOps::MUL:
                ASSGEN.mul("sp", "sp", "sp");
                break;
            case BinOps::DIV:
                ASSGEN.div("sp", "sp", "sp");
                break;
            case BinOps::MOD:
                ASSGEN.mod("sp", "sp", "sp");
                break;
            case BinOps::AND:
                ASSGEN.land("sp", "sp", "sp");
                break;
            case BinOps::OR:
                ASSGEN.lor("sp", "sp", "sp");
                break;
            case BinOps::TO:
                // TODO: check if this is right
                ASSGEN.load("sp", "sp");
                break;
            case BinOps::LT:
                labels = labelCreator("lower");
                ASSGEN.jumpLower(std::string("sp") + " " + std::string("sp"), labels.first);
                ASSGEN.push("0");
                ASSGEN.jump(labels.second);
                ASSGEN.addLabel(labels.first);
                ASSGEN.push("1");
                ASSGEN.addLabel(labels.second);
                break;
            case BinOps::LTE:
                labels = labelCreator("lowerEquals");
                ASSGEN.jumpLowerEquals(std::string("sp") + " " + std::string("sp"), labels.first);
                ASSGEN.push("0");
                ASSGEN.jump(labels.second);
                ASSGEN.addLabel(labels.first);
                ASSGEN.push("1");
                ASSGEN.addLabel(labels.second);
                break;
            case BinOps::GT:
                labels = labelCreator("greater");
                ASSGEN.jumpGreater(std::string("sp") + " " + std::string("sp"), labels.first);
                ASSGEN.push("0");
                ASSGEN.jump(labels.second);
                ASSGEN.addLabel(labels.first);
                ASSGEN.push("1");
                ASSGEN.addLabel(labels.second);
                break;
            case BinOps::GTE:
                labels = labelCreator("greaterEquals");
                ASSGEN.jumpGreaterEquals(std::string("sp") + " " + std::string("sp"), labels.first);
                ASSGEN.push("0");
                ASSGEN.jump(labels.second);
                ASSGEN.addLabel(labels.first);
                ASSGEN.push("1");
                ASSGEN.addLabel(labels.second);
                break;
            case BinOps::IS:
                ASSGEN.jumpEquals(std::string("sp") + " " + std::string("sp"), labels.first);
                ASSGEN.push("0");
                ASSGEN.jump(labels.second);
                ASSGEN.addLabel(labels.first);
                ASSGEN.push("1");
                ASSGEN.addLabel(labels.second);
                break;
            case BinOps::NEQ:
                ASSGEN.jumpNotEquals(std::string("sp") + " " + std::string("sp"), labels.first);
                ASSGEN.push("0");
                ASSGEN.jump(labels.second);
                ASSGEN.addLabel(labels.first);
                ASSGEN.push("1");
                ASSGEN.addLabel(labels.second);
                break;

        }
    } else if (UnaryOperation *unOp = dynamic_cast<UnaryOperation *>(expression)) {
        TweeCompiler::evalExpression(unOp->getExpression().get());
        switch (unOp->getOperator()) {
            case UnOps::NOT:
                ASSGEN.lnot("sp", "sp");
                break;
            case UnOps::PLUS:
                ASSGEN.push("0");
                ASSGEN.add("sp", "sp", "sp");
                break;
            case UnOps::MINUS:
                ASSGEN.push("0");
                ASSGEN.sub("sp", "sp", "sp");
                break;
            default:
                break;
        }
    }
}

std::pair<std::string, std::string> TweeCompiler::labelCreator(std::string labelName) {

    std::string resultLabel = labelName.append("_");
    std::string afterLabel = "after_";
    resultLabel.append(std::to_string(labelCount));
    afterLabel.append(std::to_string(labelCount));
    ++labelCount;

    return std::make_pair(resultLabel, afterLabel);

}<|endoftext|>