cz.cuni.mff.ms.brodecva.botnicek.ide.project.model.Project.java Source code

Java tutorial

Introduction

Here is the source code for cz.cuni.mff.ms.brodecva.botnicek.ide.project.model.Project.java

Source

/**
 * Copyright Vclav Brodec 2014.
 * 
 * This file is part of Botn?ek.
 * 
 * Botn?ek is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Botn?ek is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Botn?ek.  If not, see <http://www.gnu.org/licenses/>.
 */
package cz.cuni.mff.ms.brodecva.botnicek.ide.project.model;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.io.Writer;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

import cz.cuni.mff.ms.brodecva.botnicek.ide.aiml.elements.root.Aiml;
import cz.cuni.mff.ms.brodecva.botnicek.ide.aiml.elements.root.Toplevel;
import cz.cuni.mff.ms.brodecva.botnicek.ide.aiml.elements.toplevel.Topic;
import cz.cuni.mff.ms.brodecva.botnicek.ide.aiml.types.NormalWord;
import cz.cuni.mff.ms.brodecva.botnicek.ide.aiml.types.NormalWords;
import cz.cuni.mff.ms.brodecva.botnicek.ide.check.code.model.builder.DefaultCodeBuilder;
import cz.cuni.mff.ms.brodecva.botnicek.ide.check.code.model.checker.DefaultCodeChecker;
import cz.cuni.mff.ms.brodecva.botnicek.ide.compile.Compiler;
import cz.cuni.mff.ms.brodecva.botnicek.ide.compile.CompilerFactory;
import cz.cuni.mff.ms.brodecva.botnicek.ide.compile.DefaultCompilerFactory;
import cz.cuni.mff.ms.brodecva.botnicek.ide.compile.library.Randomize;
import cz.cuni.mff.ms.brodecva.botnicek.ide.compile.library.Recursion;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.arcs.model.TransitionArc;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.networks.model.Network;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.nodes.model.Node;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.DefaultSystem;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.NamingAuthority;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.NormalizedNamingAuthority;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.System;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.types.Priority;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.types.SystemName;
import cz.cuni.mff.ms.brodecva.botnicek.ide.print.DefaultPrettyPrinter;
import cz.cuni.mff.ms.brodecva.botnicek.ide.print.PrintException;
import cz.cuni.mff.ms.brodecva.botnicek.ide.print.Printer;
import cz.cuni.mff.ms.brodecva.botnicek.ide.project.events.ConversationSettingsChangedEvent;
import cz.cuni.mff.ms.brodecva.botnicek.ide.project.events.ProjectOpenedEvent;
import cz.cuni.mff.ms.brodecva.botnicek.ide.render.DefaultRendererFactory;
import cz.cuni.mff.ms.brodecva.botnicek.ide.render.DefaultRenderingVisitorFactory;
import cz.cuni.mff.ms.brodecva.botnicek.ide.render.Renderer;
import cz.cuni.mff.ms.brodecva.botnicek.ide.render.RendererFactory;
import cz.cuni.mff.ms.brodecva.botnicek.ide.runtime.events.RunsTerminatedEvent;
import cz.cuni.mff.ms.brodecva.botnicek.ide.runtime.events.RuntimeRunEvent;
import cz.cuni.mff.ms.brodecva.botnicek.ide.runtime.model.DefaultRuntimeFactory;
import cz.cuni.mff.ms.brodecva.botnicek.ide.runtime.model.RunException;
import cz.cuni.mff.ms.brodecva.botnicek.ide.runtime.model.Runtime;
import cz.cuni.mff.ms.brodecva.botnicek.ide.runtime.model.RuntimeFactory;
import cz.cuni.mff.ms.brodecva.botnicek.ide.runtime.model.RuntimeSettings;
import cz.cuni.mff.ms.brodecva.botnicek.ide.utils.concepts.Intended;
import cz.cuni.mff.ms.brodecva.botnicek.ide.utils.events.Dispatcher;
import cz.cuni.mff.ms.brodecva.botnicek.library.api.AIMLConversationConfiguration;
import cz.cuni.mff.ms.brodecva.botnicek.library.api.BotConfiguration;
import cz.cuni.mff.ms.brodecva.botnicek.library.api.ConversationConfiguration;
import cz.cuni.mff.ms.brodecva.botnicek.library.api.LanguageConfiguration;
import cz.cuni.mff.ms.brodecva.botnicek.library.api.SessionException;
import cz.cuni.mff.ms.brodecva.botnicek.library.loader.LoaderException;
import cz.cuni.mff.ms.brodecva.botnicek.library.platform.AIML;
import cz.cuni.mff.ms.brodecva.botnicek.library.preprocessor.SimpleNormalizer;
import cz.cuni.mff.ms.brodecva.botnicek.library.processor.set.DisplayStrategy;

/**
 * <p>
 * Instance projektov tdy slou k provdn zkladnch operac, jako je
 * oteven, uloen, export, konfigurace a proveden testu.
 * </p>
 * <p>
 * Je spole?n s potebnmi sou?stmi serializovateln, a lze tedy ut k
 * uloen a pozdjmu na?ten aktulnho stavu prce.
 * </p>
 * 
 * @author Vclav Brodec
 * @version 1.0
 */
public final class Project {

    private final static class ProjectSerializationProxy implements Serializable {
        private static final long serialVersionUID = 1L;

        private final NamingAuthority statesNamingAuthority;
        private final NamingAuthority predicatesNamingAuthority;
        private final RendererFactory rendererFactory;
        private final CompilerFactory compilerFactory;
        private final RuntimeFactory runtimeFactory;
        private final Printer printer;
        private final System system;
        private final WriterFactory unitWriterFactory;
        private final Settings settings;
        private final RuntimeSettings runtimeSettings;

        public ProjectSerializationProxy(final NamingAuthority statesNamingAuthority,
                final NamingAuthority predicatesNamingAuthority, final RendererFactory rendererFactory,
                final CompilerFactory compilerFactory, final RuntimeFactory runtimeFactory, final Printer printer,
                final System system, final WriterFactory unitWriterFactory, final Settings settings,
                final RuntimeSettings runtimeSettings) {
            this.system = system;
            this.statesNamingAuthority = statesNamingAuthority;
            this.predicatesNamingAuthority = predicatesNamingAuthority;
            this.settings = settings;
            this.runtimeSettings = runtimeSettings;
            this.compilerFactory = compilerFactory;
            this.rendererFactory = rendererFactory;
            this.runtimeFactory = runtimeFactory;
            this.printer = printer;
            this.unitWriterFactory = unitWriterFactory;
        }

        public CompilerFactory getCompilerFactory() {
            return this.compilerFactory;
        }

        public NamingAuthority getPredicatesNamingAuthority() {
            return this.predicatesNamingAuthority;
        }

        public Printer getPrinter() {
            return this.printer;
        }

        public RendererFactory getRendererFactory() {
            return this.rendererFactory;
        }

        public RuntimeFactory getRuntimeFactory() {
            return this.runtimeFactory;
        }

        public RuntimeSettings getRuntimeSettings() {
            return this.runtimeSettings;
        }

        public Settings getSettings() {
            return this.settings;
        }

        public NamingAuthority getStatesNamingAuthority() {
            return this.statesNamingAuthority;
        }

        public System getSystem() {
            return this.system;
        }

        public WriterFactory getUnitWriterFactory() {
            return this.unitWriterFactory;
        }
    }

    /**
     * Rezervovan nzev exportnho souboru knihovny.
     */
    public static final SystemName RESERVED_LIBRARY_NAME = SystemName.of("botnicek");

    private static final Object PROPERTIES_EXTENSION = "properties";

    /**
     * Vytvo projekt z danch zvislost.
     * 
     * @param system
     *            systm st
     * @param statesNamingAuthority
     *            autorita, kter d pidlovn jmen stavm st
     * @param predicatesNamingAuthority
     *            autorita, kter d pidlovn jmen testovacm prediktm
     * @param dispatcher
     *            rozesla? udlost
     * @param settings
     *            obecn nastaven projektu
     * @param runtimeSettings
     *            nastaven bhovho prosted
     * @param rendererFactory
     *            tovrna na formtovn zdrojovho kdu
     * @param printer
     *            formtova? kdu
     * @param compilerFactory
     *            tovrna na peklad systmu st do jazyka AIML
     * @param runtimeFactory
     *            tovrna na bhov prosted bot
     * @param unitWriterFactory
     *            tovrna na zapisova?e jednotek s generovanm kdem
     * @return projekt
     */
    public static Project create(final System system, final NamingAuthority statesNamingAuthority,
            final NamingAuthority predicatesNamingAuthority, final Dispatcher dispatcher, final Settings settings,
            final RuntimeSettings runtimeSettings, final RendererFactory rendererFactory, final Printer printer,
            final CompilerFactory compilerFactory, final RuntimeFactory runtimeFactory,
            final WriterFactory unitWriterFactory) {
        return new Project(system, statesNamingAuthority, predicatesNamingAuthority, dispatcher, settings,
                runtimeSettings, rendererFactory, printer, compilerFactory, runtimeFactory, unitWriterFactory);
    }

    /**
     * Vytvo vchoz projekt.
     * 
     * @param name
     *            nzev projektu
     * @param dispatcher
     *            vysla? udlost
     * @return vchoz projekt
     */
    public static Project createAndOpen(final SystemName name, final Dispatcher dispatcher) {
        Preconditions.checkNotNull(name);
        Preconditions.checkNotNull(dispatcher);

        final NamingAuthority statesNamingAuthority = NormalizedNamingAuthority.create(new SimpleNormalizer());
        final NamingAuthority predicatesNamingAuthority = NormalizedNamingAuthority.create(new SimpleNormalizer());

        final System system = DefaultSystem.create(name, dispatcher, statesNamingAuthority,
                predicatesNamingAuthority, ImmutableSet.of(RESERVED_LIBRARY_NAME));

        final Settings settings = Settings.getDefault();
        final RuntimeSettings runtimeSettings = RuntimeSettings.getDefault();

        final RendererFactory rendererFactory = DefaultRendererFactory
                .create(DefaultRenderingVisitorFactory.create());
        final Printer printer = DefaultPrettyPrinter.create();
        final CompilerFactory compilerFactory = DefaultCompilerFactory.create();
        final RuntimeFactory runtimeFactory = DefaultRuntimeFactory.create();

        statesNamingAuthority.use(NormalWords.join(settings.getPrefix(), settings.getPullState()).getText());
        statesNamingAuthority.use(NormalWords.join(settings.getPrefix(), settings.getPullStopState()).getText());
        statesNamingAuthority.use(NormalWords.join(settings.getPrefix(), settings.getRandomizeState()).getText());
        statesNamingAuthority.use(NormalWords.join(settings.getPrefix(), settings.getReturnState()).getText());
        statesNamingAuthority.use(NormalWords.join(settings.getPrefix(), settings.getSuccessState()).getText());
        statesNamingAuthority.use(NormalWords.join(settings.getPrefix(), settings.getFailState()).getText());

        predicatesNamingAuthority
                .use(NormalWords.join(settings.getPrefix(), settings.getTestingPredicate()).getText());

        final Project newInstance = create(system, statesNamingAuthority, predicatesNamingAuthority, dispatcher,
                settings, runtimeSettings, rendererFactory, printer, compilerFactory, runtimeFactory,
                BufferedFileWriterFactory.create());

        newInstance.fillNew();

        dispatcher.fire(ProjectOpenedEvent.create(newInstance));
        return newInstance;
    }

    /**
     * Na?te projekt ze vstupnho proudu.
     * 
     * @param inputStream
     *            vstupn proud
     * @param dispatcher
     *            rozesla? udlost
     * @return na?ten projekt
     * @throws IOException
     *             pokud dojde k chyb pi otevrn ?i na?tn
     * @throws ClassNotFoundException
     *             pokud je oteven definice projektu nekompatibiln
     */
    public static Project open(final InputStream inputStream, final Dispatcher dispatcher)
            throws IOException, ClassNotFoundException {
        Preconditions.checkNotNull(inputStream);
        Preconditions.checkNotNull(dispatcher);

        try (final InputStream inputBuffer = new BufferedInputStream(inputStream);
                final ObjectInput objectInput = new ObjectInputStream(inputBuffer)) {

            final ProjectSerializationProxy loadedProxy = (ProjectSerializationProxy) objectInput.readObject();
            final Project loaded = new Project(loadedProxy, dispatcher);

            loaded.dispatcher.fire(ProjectOpenedEvent.create(loaded));
            return loaded;
        }
    }

    /**
     * Na?te projekt z umstn.
     * 
     * @param projectPath
     *            cesta k souboru s projektem
     * @param dispatcher
     *            rozesla? udlost
     * @return na?ten projekt
     * @throws IOException
     *             pokud dojde k chyb pi otevrn ?i na?tn
     * @throws ClassNotFoundException
     *             pokud je oteven definice projektu nekompatibiln
     */
    public static Project open(final Path projectPath, final Dispatcher dispatcher)
            throws IOException, ClassNotFoundException {
        Preconditions.checkNotNull(projectPath);
        Preconditions.checkNotNull(dispatcher);

        try (final InputStream fileInput = new FileInputStream(projectPath.toFile())) {
            return open(fileInput, dispatcher);
        } catch (final FileNotFoundException e) {
            throw e;
        }
    }

    private final NamingAuthority statesNamingAuthority;
    private final NamingAuthority predicatesNamingAuthority;
    private final RendererFactory rendererFactory;
    private final CompilerFactory compilerFactory;

    private final RuntimeFactory runtimeFactory;

    private final Printer printer;
    private final System system;

    private final WriterFactory unitWriterFactory;

    private final Dispatcher dispatcher;

    private Settings settings;

    private RuntimeSettings runtimeSettings;

    private Project(final ProjectSerializationProxy loadedProxy, final Dispatcher dispatcher) {
        this(loadedProxy.getSystem(), loadedProxy.getStatesNamingAuthority(),
                loadedProxy.getPredicatesNamingAuthority(), dispatcher, loadedProxy.getSettings(),
                loadedProxy.getRuntimeSettings(), loadedProxy.getRendererFactory(), loadedProxy.getPrinter(),
                loadedProxy.getCompilerFactory(), loadedProxy.getRuntimeFactory(),
                loadedProxy.getUnitWriterFactory());

        this.system.setDispatcher(dispatcher);
    }

    private Project(final System system, final NamingAuthority statesNamingAuthority,
            final NamingAuthority predicatesNamingAuthority, final Dispatcher dispatcher, final Settings settings,
            final RuntimeSettings runtimeSettings, final RendererFactory rendererFactory, final Printer printer,
            final CompilerFactory compilerFactory, final RuntimeFactory runtimeFactory,
            final WriterFactory unitWriterFactory) {
        Preconditions.checkNotNull(system);
        Preconditions.checkNotNull(statesNamingAuthority);
        Preconditions.checkNotNull(predicatesNamingAuthority);
        Preconditions.checkNotNull(dispatcher);
        Preconditions.checkNotNull(settings);
        Preconditions.checkNotNull(runtimeSettings);
        Preconditions.checkNotNull(rendererFactory);
        Preconditions.checkNotNull(compilerFactory);
        Preconditions.checkNotNull(runtimeFactory);
        Preconditions.checkNotNull(printer);

        Preconditions.checkArgument(statesNamingAuthority
                .isUsed(NormalWords.join(settings.getPrefix(), settings.getPullState()).getText()));
        Preconditions.checkArgument(statesNamingAuthority
                .isUsed(NormalWords.join(settings.getPrefix(), settings.getPullStopState()).getText()));
        Preconditions.checkArgument(statesNamingAuthority
                .isUsed(NormalWords.join(settings.getPrefix(), settings.getRandomizeState()).getText()));
        Preconditions.checkArgument(statesNamingAuthority
                .isUsed(NormalWords.join(settings.getPrefix(), settings.getReturnState()).getText()));
        Preconditions.checkArgument(statesNamingAuthority
                .isUsed(NormalWords.join(settings.getPrefix(), settings.getSuccessState()).getText()));
        Preconditions.checkArgument(statesNamingAuthority
                .isUsed(NormalWords.join(settings.getPrefix(), settings.getFailState()).getText()));

        Preconditions.checkArgument(predicatesNamingAuthority
                .isUsed(NormalWords.join(settings.getPrefix(), settings.getTestingPredicate()).getText()));

        this.system = system;
        this.statesNamingAuthority = statesNamingAuthority;
        this.predicatesNamingAuthority = predicatesNamingAuthority;
        this.dispatcher = dispatcher;
        this.settings = settings;
        this.runtimeSettings = runtimeSettings;
        this.compilerFactory = compilerFactory;
        this.rendererFactory = rendererFactory;
        this.runtimeFactory = runtimeFactory;
        this.printer = printer;
        this.unitWriterFactory = unitWriterFactory;
    }

    /**
     * Pevede systm st na strom objektovho modelu jazyka AIML pomoc
     * kompiltoru z dodan tovrny.
     * 
     * @return st a k nim psluejc tmata jazyka AIML
     */
    private Map<Network, List<Topic>> compile() {
        final Compiler compiler = this.compilerFactory.produce(joinPullState(), joinPullStopState(),
                joinRandomizeState(), joinSuccessState(), joinReturnState(), joinTestingPredicate());

        final Map<Network, List<Topic>> result = compiler.compile(this.system);
        return result;
    }

    /**
     * Vyexportuje zdrojov kdy bota vyvjenho v rmci projektu.
     * 
     * @param directory
     *            adres pro export
     * @throws IOException
     *             pokud dojde k chyb pi exportu
     */
    public void export(final Path directory) throws IOException {
        final Map<Network, List<Topic>> result = compile();

        final Renderer render = this.rendererFactory.produce(this.settings.getNamespacesToPrefixes());
        final Set<Entry<Network, List<Topic>>> units = result.entrySet();
        for (final Entry<Network, List<Topic>> unit : units) {
            final Network network = unit.getKey();
            final List<Topic> content = unit.getValue();

            exportUnit(network.getName(), content, render, directory);
        }

        exportUnit(RESERVED_LIBRARY_NAME, getLibraries(), render, directory);
        exportConfigs(directory);
    }

    private void exportUnit(final SystemName name, final List<? extends Topic> content, final Renderer render,
            final Path directory) throws IOException {
        final String text = render(render, content);
        final String formatted = format(text);

        final String unitName = String.format("%s.%s", name.getText(), AIML.FILE_SUFFIX);

        writeUnit(directory, unitName, formatted);
    }

    private void exportConfigs(final Path directory) throws IOException {
        final ImmutableMap.Builder<String, Properties> propertiesUnitsBuilder = ImmutableMap.builder();
        propertiesUnitsBuilder.putAll(this.runtimeSettings.getBotConfiguration().toNamedProperties());
        propertiesUnitsBuilder.putAll(this.runtimeSettings.getLanguageConfiguration().toNamedProperties());
        propertiesUnitsBuilder.putAll(this.runtimeSettings.getConversationConfiguration().toNamedProperties());
        final Map<String, Properties> propertiesUnits = propertiesUnitsBuilder.build();

        final Set<Entry<String, Properties>> propertiesUnitsEntries = propertiesUnits.entrySet();
        for (final Entry<String, Properties> unit : propertiesUnitsEntries) {
            final String name = unit.getKey();
            final Properties content = unit.getValue();

            final String unitName = String.format("%s.%s", name, PROPERTIES_EXTENSION);

            writePropertiesUnit(directory, unitName, content);
        }
    }

    private void fillNew() {
        final System addedSystem = getSystem();

        final SystemName addNetworkName = SystemName.of("HelloWorld");
        addedSystem.addNetwork(addNetworkName);

        final Network addedNetwork = addedSystem.getNetwork(addNetworkName);

        addedSystem.addNode(addedNetwork, 160, 120);
        final Node startNode = addedSystem.getNode(NormalWords.of("1"));
        final NormalWord startNodeName = NormalWords.of("START");
        addedSystem.changeNode(startNode, startNodeName);

        addedSystem.addNode(addedNetwork, 260, 200);
        final Node finishNode = addedSystem.getNode(NormalWords.of("2"));
        final NormalWord finishNodeName = NormalWords.of("END");
        addedSystem.changeNode(finishNode, finishNodeName);

        final NormalWord arcName = NormalWords.of("HELLO");
        addedSystem.addArc(addedNetwork, arcName, startNodeName, finishNodeName);
        addedSystem.changeArc(addedSystem.getArc(arcName), arcName, Priority.of(1), TransitionArc.class,
                DefaultCodeBuilder.create(DefaultCodeChecker.create(this.runtimeSettings.getBotConfiguration(),
                        this.runtimeSettings.getLanguageConfiguration(), this.settings.getNamespacesToPrefixes()),
                        "Hello World!").build());

        setConversationConfiguration(AIMLConversationConfiguration.of(
                ImmutableMap.of("TOPIC", startNodeName.getText() + " " + joinSuccessState().getText()),
                ImmutableMap.<String, DisplayStrategy>of()));
    }

    /**
     * Zformtuje dodan kd do lidsky ?iteln podoby pomoc dodanho
     * formtova?e.
     * 
     * @param code
     *            zdrojov kd
     * @return naformtovan kd
     * @throws IOException
     *             pokud dojde k chyb pi pokusu o pevod do zformtovanho
     *             tvaru
     */
    private String format(final String code) throws IOException {
        final String formatted;
        try {
            formatted = this.printer.print(code);
        } catch (final PrintException e) {
            throw new IOException(e);
        }
        return formatted;
    }

    /**
     * Vrt konfiguraci bota.
     * 
     * @return konfigurace bota
     */
    public BotConfiguration getBotConfiguration() {
        return this.runtimeSettings.getBotConfiguration();
    }

    /**
     * Vrt konfiguraci bota.
     * 
     * @return konfigurace bota
     */
    public ConversationConfiguration getConversationConfiguration() {
        return this.runtimeSettings.getConversationConfiguration();
    }

    /**
     * Vrt konfiguraci jazyka.
     * 
     * @return konfigurace jazyka
     */
    public LanguageConfiguration getLanguageConfiguration() {
        return this.runtimeSettings.getLanguageConfiguration();
    }

    private List<Topic> getLibraries() {
        final ImmutableList.Builder<Topic> builder = ImmutableList.builder();

        builder.addAll(Recursion.getLibrary(joinPullState(), joinPullStopState(), joinSuccessState(),
                joinFailState(), joinReturnState()));
        builder.addAll(Randomize.getLibrary(joinRandomizeState(), Priority.MAX_VALUE,
                this.system.getMaxBranchingFactor(), this.statesNamingAuthority));

        return builder.build();
    }

    /**
     * Vrt nastaven projektu.
     * 
     * @return nastaven projektu
     */
    public Settings getSettings() {
        return this.settings;
    }

    /**
     * Vrt editovan systm st.
     * 
     * @return systm st
     */
    public System getSystem() {
        return this.system;
    }

    private NormalWord joinFailState() {
        return joinWithCurrentPrefix(this.settings.getFailState());
    }

    private NormalWord joinPullState() {
        return joinWithCurrentPrefix(this.settings.getPullState());
    }

    private NormalWord joinPullStopState() {
        return joinWithCurrentPrefix(this.settings.getPullStopState());
    }

    private NormalWord joinRandomizeState() {
        return joinWithCurrentPrefix(this.settings.getRandomizeState());
    }

    private NormalWord joinReturnState() {
        return joinWithCurrentPrefix(this.settings.getReturnState());
    }

    private NormalWord joinSuccessState() {
        return joinWithCurrentPrefix(this.settings.getSuccessState());
    }

    private NormalWord joinTestingPredicate() {
        return joinWithCurrentPrefix(this.settings.getTestingPredicate());
    }

    /**
     * Spoj aktuln prefix provoznch stav s danm nzvem stavu.
     * 
     * @param word
     *            pojmenovn stavu bez prefixu
     * @return nzev stavu s odliovacm prefixem
     */
    private NormalWord joinWithCurrentPrefix(final NormalWord word) {
        return NormalWords.join(this.settings.getPrefix(), word);
    }

    /**
     * Na?te pslun tmata st z objektovho modelu a knihoven do bhovho
     * prosted.
     * 
     * @param runtime
     *            bhov prosted
     * @param metaStructure
     *            st a jejich tmata, kter budou zpracovna genertorem kdu
     * @throws RunException
     *             pokud dojde k chyb pi inicializaci
     */
    private void loadToRuntime(final Runtime runtime, final Map<Network, List<Topic>> metaStructure)
            throws RunException {
        final Renderer renderer = this.rendererFactory.produce(this.settings.getNamespacesToPrefixes());

        try {
            for (final Entry<Network, List<Topic>> unit : metaStructure.entrySet()) {
                final Network network = unit.getKey();
                final List<Topic> content = unit.getValue();

                loadUnit(network.getName(), content, renderer, runtime);
            }
            loadUnit(RESERVED_LIBRARY_NAME, getLibraries(), renderer, runtime);
        } catch (final LoaderException e) {
            throw new RunException(e);
        }
    }

    /**
     * Vygeneruje a na?te kd obsah do bhovho prosted.
     * 
     * @param name
     *            nzev jednotky
     * @param content
     *            zdroj dat ke generovn kdu
     * @param renderer
     *            genertor kdu
     * @param runtime
     *            plnn bhov prosted
     * @throws LoaderException
     *             pokud dojde k chyb pi na?tn kdu
     */
    private void loadUnit(final SystemName name, final List<? extends Toplevel> content, final Renderer renderer,
            final Runtime runtime) throws LoaderException {
        final String text = render(renderer, content);

        runtime.load(name.getText(), text);
    }

    /**
     * Vygeneruje kd ze zdroje s pomoc dodanho genertoru.
     * 
     * @param renderer
     *            genertor kdu
     * @param content
     *            zdroj
     * @return vygenerovan kd
     */
    private String render(final Renderer renderer, final List<? extends Toplevel> content) {
        final Aiml root = Aiml.create(content, this.settings.getNamespacesToPrefixes());
        final String text = renderer.render(root);
        return text;
    }

    /**
     * Ulo projekt do vstupnho proudu.
     * 
     * @param outputStream
     *            vstupn proud
     * @throws IOException
     *             pokud dojde k chyb pi ukldn
     */
    public void save(final OutputStream outputStream) throws IOException {
        Preconditions.checkNotNull(outputStream);

        try (final ObjectOutputStream objectOutput = new ObjectOutputStream(outputStream)) {
            objectOutput.writeObject(new ProjectSerializationProxy(this.statesNamingAuthority,
                    this.predicatesNamingAuthority, this.rendererFactory, this.compilerFactory, this.runtimeFactory,
                    this.printer, this.system, this.unitWriterFactory, this.settings, this.runtimeSettings));
        } catch (final IOException e) {
            throw e;
        }
    }

    /**
     * Ulo projekt jako soubor do zadanho umstn.
     * 
     * @param projectPath
     *            cesta pro uloen
     * @throws IOException
     *             pokud dojde k chyb pi ukldn
     */
    public void save(final Path projectPath) throws IOException {
        Preconditions.checkNotNull(projectPath);

        try (final FileOutputStream fileOutput = new FileOutputStream(projectPath.toFile());
                final OutputStream outputBuffer = new BufferedOutputStream(fileOutput)) {
            save(outputBuffer);
        } catch (final FileNotFoundException e) {
            throw e;
        }
    }

    /**
     * Nastav projekt.
     * 
     * @param settings
     *            nastaven
     */
    public void set(final Settings settings) {
        Preconditions.checkNotNull(settings);

        if (settings.equals(this.settings)) {
            return;
        }

        final NormalWord newNamePrefix = settings.getPrefix();
        final NormalWord newJoinedPullState = NormalWords.join(newNamePrefix, settings.getPullState());
        final NormalWord newJoinedPullStopState = NormalWords.join(newNamePrefix, settings.getPullStopState());
        final NormalWord newJoinedRandomizeState = NormalWords.join(newNamePrefix, settings.getRandomizeState());
        final NormalWord newJoinedPredicateName = NormalWords.join(newNamePrefix, settings.getTestingPredicate());
        final NormalWord newJoinedReturnState = NormalWords.join(newNamePrefix, settings.getReturnState());
        final NormalWord newJoinedSuccessState = NormalWords.join(newNamePrefix, settings.getSuccessState());
        final NormalWord newJoinedFailState = NormalWords.join(newNamePrefix, settings.getFailState());

        this.predicatesNamingAuthority
                .tryReplace(ImmutableMap.of(joinTestingPredicate().getText(), newJoinedPredicateName.getText()));
        try {
            final ImmutableMap.Builder<String, String> replacements = ImmutableMap.builder();
            replacements.put(joinPullState().getText(), newJoinedPullState.getText());
            replacements.put(joinPullStopState().getText(), newJoinedPullStopState.getText());
            replacements.put(joinRandomizeState().getText(), newJoinedRandomizeState.getText());
            replacements.put(joinReturnState().getText(), newJoinedReturnState.getText());
            replacements.put(joinSuccessState().getText(), newJoinedSuccessState.getText());
            replacements.put(joinFailState().getText(), newJoinedFailState.getText());

            this.statesNamingAuthority.tryReplace(replacements.build());
        } catch (final Exception e) {
            this.predicatesNamingAuthority.tryReplace(
                    ImmutableMap.of(newJoinedPredicateName.getText(), joinTestingPredicate().getText()));
            throw e;
        }

        this.settings = settings;
        this.dispatcher.fire(cz.cuni.mff.ms.brodecva.botnicek.ide.project.events.SettingsChangedEvent.create(this,
                this.settings));
        this.dispatcher.fire(cz.cuni.mff.ms.brodecva.botnicek.ide.design.arcs.events.SettingsChangedEvent
                .create(this.system, this.settings));
    }

    /**
     * Nastav bota.
     * 
     * @param botConfiguration
     *            konfigurace bota
     */
    public void setBotConfiguration(final BotConfiguration botConfiguration) {
        Preconditions.checkNotNull(botConfiguration);

        this.runtimeSettings = RuntimeSettings.create(botConfiguration,
                this.runtimeSettings.getLanguageConfiguration(),
                this.runtimeSettings.getConversationConfiguration());
        this.dispatcher.fire(cz.cuni.mff.ms.brodecva.botnicek.ide.project.events.BotSettingsChangedEvent
                .create(this, botConfiguration));
        this.dispatcher.fire(cz.cuni.mff.ms.brodecva.botnicek.ide.design.arcs.events.BotSettingsChangedEvent
                .create(this.system, botConfiguration));
    }

    /**
     * Nastav konverzaci.
     * 
     * @param conversationConfiguration
     *            konfigurace konverzace
     */
    public void setConversationConfiguration(final ConversationConfiguration conversationConfiguration) {
        Preconditions.checkNotNull(conversationConfiguration);

        this.runtimeSettings = RuntimeSettings.create(this.runtimeSettings.getBotConfiguration(),
                this.runtimeSettings.getLanguageConfiguration(), conversationConfiguration);
        this.dispatcher.fire(ConversationSettingsChangedEvent.create(this, conversationConfiguration));
    }

    /**
     * Nastav jazyk.
     * 
     * @param languageConfiguration
     *            konfigurace jazyka
     */
    public void setLanguageConfiguration(final LanguageConfiguration languageConfiguration) {
        Preconditions.checkNotNull(languageConfiguration);

        this.runtimeSettings = RuntimeSettings.create(this.runtimeSettings.getBotConfiguration(),
                languageConfiguration, this.runtimeSettings.getConversationConfiguration());
        this.dispatcher.fire(cz.cuni.mff.ms.brodecva.botnicek.ide.project.events.LanguageSettingsChangedEvent
                .create(this, languageConfiguration));
        this.dispatcher.fire(cz.cuni.mff.ms.brodecva.botnicek.ide.design.arcs.events.LanguageSettingsChangedEvent
                .create(this.system, languageConfiguration));
    }

    /**
     * Vytvo bhov prosted pomoc dodan tovrny a z nastaven dodanch
     * projektu.
     * 
     * @return bhov prosted
     * @throws RunException
     *             pokud dojde k chyb pi inicializaci
     */
    private Runtime startRuntime() throws RunException {
        final Runtime runtime;
        try {
            runtime = this.runtimeFactory.produce(this.runtimeSettings, this.dispatcher);
        } catch (final SessionException e) {
            throw new RunException(e);
        }
        return runtime;
    }

    /**
     * Spust test.
     * 
     * @throws RunException
     *             pokud dojde k chyb pi inicializaci bhovho prosted
     */
    public void test() throws RunException {
        final Map<Network, List<Topic>> result = compile();
        final Runtime runtime = startRuntime();

        loadToRuntime(runtime, result);

        this.dispatcher.fire(RunsTerminatedEvent.create());
        this.dispatcher.fire(RuntimeRunEvent.create(this, runtime.run()));
    }

    /**
     * Zape do adrese soubor danho jmna s dodanm obsahem.
     * 
     * @param directory
     *            adres
     * @param unitName
     *            jmno souboru
     * @param text
     *            obsah
     * @throws IOException
     *             pokud dojde k chyb pi zpisu
     */
    private void writeUnit(final Path directory, final String unitName, final String text) throws IOException {
        try (final Writer outputBuffer = this.unitWriterFactory.produce(directory, unitName)) {
            outputBuffer.write(text);
        }
    }

    /**
     * Zape do adrese soubor {@link Properties}.
     * 
     * @param name nzev jednotky
     * @param content kl?e v {@link Properties}
     * @throws IOException pokud dojde k chyb pi zpisu
     */
    private void writePropertiesUnit(final Path directory, final String name, final Properties content)
            throws IOException {
        try (final OutputStream outputBuffer = new BufferedOutputStream(
                new FileOutputStream(directory.resolve(name).toFile()))) {
            content.store(outputBuffer, Intended.<String>nullReference());
        }
    }
}